diff options
Diffstat (limited to 'drivers')
711 files changed, 22004 insertions, 12924 deletions
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index e9562a7cb2f9..3b20a3401b64 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -212,37 +212,40 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device, return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* Validate wake_device is of type Device */ - - device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device); - if (device_node->type != ACPI_TYPE_DEVICE) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* Ensure that we have a valid GPE number */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); - if (gpe_event_info) { - /* - * If there is no method or handler for this GPE, then the - * wake_device will be notified whenever this GPE fires (aka - * "implicit notify") Note: The GPE is assumed to be - * level-triggered (for windows compatibility). - */ - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == - ACPI_GPE_DISPATCH_NONE) { - gpe_event_info->flags = - (ACPI_GPE_DISPATCH_NOTIFY | - ACPI_GPE_LEVEL_TRIGGERED); - gpe_event_info->dispatch.device_node = device_node; - } + if (!gpe_event_info) { + goto unlock_and_exit; + } + + /* + * If there is no method or handler for this GPE, then the + * wake_device will be notified whenever this GPE fires (aka + * "implicit notify") Note: The GPE is assumed to be + * level-triggered (for windows compatibility). + */ + if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == + ACPI_GPE_DISPATCH_NONE) && (wake_device != ACPI_ROOT_OBJECT)) { - gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; - status = AE_OK; + /* Validate wake_device is of type Device */ + + device_node = ACPI_CAST_PTR(struct acpi_namespace_node, + wake_device); + if (device_node->type != ACPI_TYPE_DEVICE) { + goto unlock_and_exit; + } + gpe_event_info->flags = (ACPI_GPE_DISPATCH_NOTIFY | + ACPI_GPE_LEVEL_TRIGGERED); + gpe_event_info->dispatch.device_node = device_node; } + gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; + status = AE_OK; + + unlock_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index b0931818cf98..c90c76aa7f8b 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -636,17 +636,21 @@ EXPORT_SYMBOL(acpi_os_write_port); acpi_status acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width) { - u32 dummy; void __iomem *virt_addr; - int size = width / 8, unmap = 0; + unsigned int size = width / 8; + bool unmap = false; + u32 dummy; rcu_read_lock(); virt_addr = acpi_map_vaddr_lookup(phys_addr, size); - rcu_read_unlock(); if (!virt_addr) { + rcu_read_unlock(); virt_addr = acpi_os_ioremap(phys_addr, size); - unmap = 1; + if (!virt_addr) + return AE_BAD_ADDRESS; + unmap = true; } + if (!value) value = &dummy; @@ -666,6 +670,8 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width) if (unmap) iounmap(virt_addr); + else + rcu_read_unlock(); return AE_OK; } @@ -674,14 +680,17 @@ acpi_status acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) { void __iomem *virt_addr; - int size = width / 8, unmap = 0; + unsigned int size = width / 8; + bool unmap = false; rcu_read_lock(); virt_addr = acpi_map_vaddr_lookup(phys_addr, size); - rcu_read_unlock(); if (!virt_addr) { + rcu_read_unlock(); virt_addr = acpi_os_ioremap(phys_addr, size); - unmap = 1; + if (!virt_addr) + return AE_BAD_ADDRESS; + unmap = true; } switch (width) { @@ -700,6 +709,8 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) if (unmap) iounmap(virt_addr); + else + rcu_read_unlock(); return AE_OK; } diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 42d3d72dae85..5af3479714f6 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -82,6 +82,11 @@ long acpi_is_video_device(struct acpi_device *device) if (!device) return 0; + /* Is this device able to support video switching ? */ + if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) || + ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy))) + video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING; + /* Is this device able to retrieve a video ROM ? */ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy))) video_caps |= ACPI_VIDEO_ROM_AVAILABLE; diff --git a/drivers/acpi/wakeup.c b/drivers/acpi/wakeup.c index ed6501452507..7bfbe40bc43b 100644 --- a/drivers/acpi/wakeup.c +++ b/drivers/acpi/wakeup.c @@ -86,8 +86,12 @@ int __init acpi_wakeup_device_init(void) struct acpi_device *dev = container_of(node, struct acpi_device, wakeup_list); - if (device_can_wakeup(&dev->dev)) + if (device_can_wakeup(&dev->dev)) { + /* Button GPEs are supposed to be always enabled. */ + acpi_enable_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number); device_set_wakeup_enable(&dev->dev, true); + } } mutex_unlock(&acpi_device_lock); return 0; diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 328826381a2d..b8d96ce37fc9 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -260,6 +260,7 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x1d02), board_ahci }, /* PBG AHCI */ { PCI_VDEVICE(INTEL, 0x1d04), board_ahci }, /* PBG RAID */ { PCI_VDEVICE(INTEL, 0x1d06), board_ahci }, /* PBG RAID */ + { PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, @@ -379,6 +380,8 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */ { PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv }, /* 6121 */ { PCI_DEVICE(0x1b4b, 0x9123), + .class = PCI_CLASS_STORAGE_SATA_AHCI, + .class_mask = 0xffffff, .driver_data = board_ahci_yes_fbs }, /* 88se9128 */ /* Promise */ diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index a31fe96f7de6..d4e52e214859 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4138,6 +4138,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { * device and controller are SATA. */ { "PIONEER DVD-RW DVRTD08", "1.00", ATA_HORKAGE_NOSETXFER }, + { "PIONEER DVD-RW DVR-212D", "1.28", ATA_HORKAGE_NOSETXFER }, /* End Marker */ { } diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 5defc74973d7..600f6353ecf8 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1099,9 +1099,9 @@ static int ata_scsi_dev_config(struct scsi_device *sdev, struct request_queue *q = sdev->request_queue; void *buf; - /* set the min alignment and padding */ - blk_queue_update_dma_alignment(sdev->request_queue, - ATA_DMA_PAD_SZ - 1); + sdev->sector_size = ATA_SECT_SIZE; + + /* set DMA padding */ blk_queue_update_dma_pad(sdev->request_queue, ATA_DMA_PAD_SZ - 1); @@ -1115,13 +1115,25 @@ static int ata_scsi_dev_config(struct scsi_device *sdev, blk_queue_dma_drain(q, atapi_drain_needed, buf, ATAPI_MAX_DRAIN); } else { - /* ATA devices must be sector aligned */ sdev->sector_size = ata_id_logical_sector_size(dev->id); - blk_queue_update_dma_alignment(sdev->request_queue, - sdev->sector_size - 1); sdev->manage_start_stop = 1; } + /* + * ata_pio_sectors() expects buffer for each sector to not cross + * page boundary. Enforce it by requiring buffers to be sector + * aligned, which works iff sector_size is not larger than + * PAGE_SIZE. ATAPI devices also need the alignment as + * IDENTIFY_PACKET is executed as ATA_PROT_PIO. + */ + if (sdev->sector_size > PAGE_SIZE) + ata_dev_printk(dev, KERN_WARNING, + "sector_size=%u > PAGE_SIZE, PIO may malfunction\n", + sdev->sector_size); + + blk_queue_update_dma_alignment(sdev->request_queue, + sdev->sector_size - 1); + if (dev->flags & ATA_DFLAG_AN) set_bit(SDEV_EVT_MEDIA_CHANGE, sdev->supported_events); diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index d7e57db36bc8..538ec38ba995 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -25,7 +25,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_hpt366" -#define DRV_VERSION "0.6.9" +#define DRV_VERSION "0.6.10" struct hpt_clock { u8 xfer_mode; @@ -160,8 +160,8 @@ static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, while (list[i] != NULL) { if (!strcmp(list[i], model_num)) { - printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n", - modestr, list[i]); + pr_warning(DRV_NAME ": %s is not supported for %s.\n", + modestr, list[i]); return 1; } i++; diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index efdd18bc8663..4c5b5183225e 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -24,7 +24,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_hpt37x" -#define DRV_VERSION "0.6.18" +#define DRV_VERSION "0.6.22" struct hpt_clock { u8 xfer_speed; @@ -229,8 +229,8 @@ static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, while (list[i] != NULL) { if (!strcmp(list[i], model_num)) { - printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n", - modestr, list[i]); + pr_warning(DRV_NAME ": %s is not supported for %s.\n", + modestr, list[i]); return 1; } i++; @@ -642,7 +642,6 @@ static struct ata_port_operations hpt372_port_ops = { static struct ata_port_operations hpt374_fn1_port_ops = { .inherits = &hpt372_port_ops, .cable_detect = hpt374_fn1_cable_detect, - .prereset = hpt37x_pre_reset, }; /** @@ -803,7 +802,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) .udma_mask = ATA_UDMA6, .port_ops = &hpt302_port_ops }; - /* HPT374 - UDMA100, function 1 uses different prereset method */ + /* HPT374 - UDMA100, function 1 uses different cable_detect method */ static const struct ata_port_info info_hpt374_fn0 = { .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = ATA_PIO4, @@ -838,7 +837,8 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) if (rc) return rc; - if (dev->device == PCI_DEVICE_ID_TTI_HPT366) { + switch (dev->device) { + case PCI_DEVICE_ID_TTI_HPT366: /* May be a later chip in disguise. Check */ /* Older chips are in the HPT366 driver. Ignore them */ if (rev < 3) @@ -863,54 +863,50 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) chip_table = &hpt372; break; default: - printk(KERN_ERR "pata_hpt37x: Unknown HPT366 subtype, " + pr_err(DRV_NAME ": Unknown HPT366 subtype, " "please report (%d).\n", rev); return -ENODEV; } - } else { - switch (dev->device) { - case PCI_DEVICE_ID_TTI_HPT372: - /* 372N if rev >= 2 */ - if (rev >= 2) - return -ENODEV; - ppi[0] = &info_hpt372; - chip_table = &hpt372a; - break; - case PCI_DEVICE_ID_TTI_HPT302: - /* 302N if rev > 1 */ - if (rev > 1) - return -ENODEV; - ppi[0] = &info_hpt302; - /* Check this */ - chip_table = &hpt302; - break; - case PCI_DEVICE_ID_TTI_HPT371: - if (rev > 1) - return -ENODEV; - ppi[0] = &info_hpt302; - chip_table = &hpt371; - /* - * Single channel device, master is not present - * but the BIOS (or us for non x86) must mark it - * absent - */ - pci_read_config_byte(dev, 0x50, &mcr1); - mcr1 &= ~0x04; - pci_write_config_byte(dev, 0x50, mcr1); - break; - case PCI_DEVICE_ID_TTI_HPT374: - chip_table = &hpt374; - if (!(PCI_FUNC(dev->devfn) & 1)) - *ppi = &info_hpt374_fn0; - else - *ppi = &info_hpt374_fn1; - break; - default: - printk(KERN_ERR - "pata_hpt37x: PCI table is bogus, please report (%d).\n", - dev->device); - return -ENODEV; - } + break; + case PCI_DEVICE_ID_TTI_HPT372: + /* 372N if rev >= 2 */ + if (rev >= 2) + return -ENODEV; + ppi[0] = &info_hpt372; + chip_table = &hpt372a; + break; + case PCI_DEVICE_ID_TTI_HPT302: + /* 302N if rev > 1 */ + if (rev > 1) + return -ENODEV; + ppi[0] = &info_hpt302; + /* Check this */ + chip_table = &hpt302; + break; + case PCI_DEVICE_ID_TTI_HPT371: + if (rev > 1) + return -ENODEV; + ppi[0] = &info_hpt302; + chip_table = &hpt371; + /* + * Single channel device, master is not present but the BIOS + * (or us for non x86) must mark it absent + */ + pci_read_config_byte(dev, 0x50, &mcr1); + mcr1 &= ~0x04; + pci_write_config_byte(dev, 0x50, mcr1); + break; + case PCI_DEVICE_ID_TTI_HPT374: + chip_table = &hpt374; + if (!(PCI_FUNC(dev->devfn) & 1)) + *ppi = &info_hpt374_fn0; + else + *ppi = &info_hpt374_fn1; + break; + default: + pr_err(DRV_NAME ": PCI table is bogus, please report (%d).\n", + dev->device); + return -ENODEV; } /* Ok so this is a chip we support */ @@ -957,8 +953,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) u8 sr; u32 total = 0; - printk(KERN_WARNING - "pata_hpt37x: BIOS has not set timing clocks.\n"); + pr_warning(DRV_NAME ": BIOS has not set timing clocks.\n"); /* This is the process the HPT371 BIOS is reported to use */ for (i = 0; i < 128; i++) { @@ -1014,7 +1009,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) (f_high << 16) | f_low | 0x100); } if (adjust == 8) { - printk(KERN_ERR "pata_hpt37x: DPLL did not stabilize!\n"); + pr_err(DRV_NAME ": DPLL did not stabilize!\n"); return -ENODEV; } if (dpll == 3) @@ -1022,8 +1017,8 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) else private_data = (void *)hpt37x_timings_50; - printk(KERN_INFO "pata_hpt37x: bus clock %dMHz, using %dMHz DPLL.\n", - MHz[clock_slot], MHz[dpll]); + pr_info(DRV_NAME ": bus clock %dMHz, using %dMHz DPLL.\n", + MHz[clock_slot], MHz[dpll]); } else { private_data = (void *)chip_table->clocks[clock_slot]; /* @@ -1036,8 +1031,9 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) ppi[0] = &info_hpt370_33; if (clock_slot < 2 && ppi[0] == &info_hpt370a) ppi[0] = &info_hpt370a_33; - printk(KERN_INFO "pata_hpt37x: %s using %dMHz bus clock.\n", - chip_table->name, MHz[clock_slot]); + + pr_info(DRV_NAME ": %s using %dMHz bus clock.\n", + chip_table->name, MHz[clock_slot]); } /* Now kick off ATA set up */ diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index d2239bbdb798..eca68caf5f46 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -25,7 +25,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_hpt3x2n" -#define DRV_VERSION "0.3.13" +#define DRV_VERSION "0.3.14" enum { HPT_PCI_FAST = (1 << 31), @@ -418,7 +418,7 @@ static int hpt3x2n_pci_clock(struct pci_dev *pdev) u16 sr; u32 total = 0; - printk(KERN_WARNING "pata_hpt3x2n: BIOS clock data not set.\n"); + pr_warning(DRV_NAME ": BIOS clock data not set.\n"); /* This is the process the HPT371 BIOS is reported to use */ for (i = 0; i < 128; i++) { @@ -528,8 +528,7 @@ hpt372n: ppi[0] = &info_hpt372n; break; default: - printk(KERN_ERR - "pata_hpt3x2n: PCI table is bogus please report (%d).\n", + pr_err(DRV_NAME ": PCI table is bogus, please report (%d).\n", dev->device); return -ENODEV; } @@ -579,12 +578,11 @@ hpt372n: pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low); } if (adjust == 8) { - printk(KERN_ERR "pata_hpt3x2n: DPLL did not stabilize!\n"); + pr_err(DRV_NAME ": DPLL did not stabilize!\n"); return -ENODEV; } - printk(KERN_INFO "pata_hpt37x: bus clock %dMHz, using 66MHz DPLL.\n", - pci_mhz); + pr_info(DRV_NAME ": bus clock %dMHz, using 66MHz DPLL.\n", pci_mhz); /* * Set our private data up. We only need a few flags diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index 8cc536e49a0a..d7d8026cde99 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -610,7 +610,7 @@ static struct scsi_host_template mpc52xx_ata_sht = { }; static struct ata_port_operations mpc52xx_ata_port_ops = { - .inherits = &ata_sff_port_ops, + .inherits = &ata_bmdma_port_ops, .sff_dev_select = mpc52xx_ata_dev_select, .set_piomode = mpc52xx_ata_set_piomode, .set_dmamode = mpc52xx_ata_set_dmamode, diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 73fb1c4f4cd4..25ef1a4556e6 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -866,8 +866,9 @@ static int popen(struct atm_vcc *vcc) } skb = alloc_skb(sizeof(*header), GFP_ATOMIC); - if (!skb && net_ratelimit()) { - dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n"); + if (!skb) { + if (net_ratelimit()) + dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n"); return -ENOMEM; } header = (void *)skb_put(skb, sizeof(*header)); diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 656493a5e073..42615b419dfb 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -407,12 +407,15 @@ static int rpm_suspend(struct device *dev, int rpmflags) goto out; } + /* Maybe the parent is now able to suspend. */ if (parent && !parent->power.ignore_children && !dev->power.irq_safe) { - spin_unlock_irq(&dev->power.lock); + spin_unlock(&dev->power.lock); - pm_request_idle(parent); + spin_lock(&parent->power.lock); + rpm_idle(parent, RPM_ASYNC); + spin_unlock(&parent->power.lock); - spin_lock_irq(&dev->power.lock); + spin_lock(&dev->power.lock); } out: diff --git a/drivers/block/Makefile b/drivers/block/Makefile index d7f463d6312d..40528ba56d1b 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -39,4 +39,4 @@ obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o obj-$(CONFIG_BLK_DEV_DRBD) += drbd/ obj-$(CONFIG_BLK_DEV_RBD) += rbd.o -swim_mod-objs := swim.o swim_asm.o +swim_mod-y := swim.o swim_asm.o diff --git a/drivers/block/aoe/Makefile b/drivers/block/aoe/Makefile index e76d997183c6..06ea82cdf27d 100644 --- a/drivers/block/aoe/Makefile +++ b/drivers/block/aoe/Makefile @@ -3,4 +3,4 @@ # obj-$(CONFIG_ATA_OVER_ETH) += aoe.o -aoe-objs := aoeblk.o aoechr.o aoecmd.o aoedev.o aoemain.o aoenet.o +aoe-y := aoeblk.o aoechr.o aoecmd.o aoedev.o aoemain.o aoenet.o diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 516d5bbec2b6..9279272b3732 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -2833,7 +2833,7 @@ static int cciss_revalidate(struct gendisk *disk) sector_t total_size; InquiryData_struct *inq_buff = NULL; - for (logvol = 0; logvol < CISS_MAX_LUN; logvol++) { + for (logvol = 0; logvol <= h->highest_lun; logvol++) { if (!h->drv[logvol]) continue; if (memcmp(h->drv[logvol]->LunID, drv->LunID, diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 44e18c073c44..49e6a545eb63 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1641,6 +1641,9 @@ out: static void loop_free(struct loop_device *lo) { + if (!lo->lo_queue->queue_lock) + lo->lo_queue->queue_lock = &lo->lo_queue->__queue_lock; + blk_cleanup_queue(lo->lo_queue); put_disk(lo->lo_disk); list_del(&lo->lo_list); diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index a32fb41246f8..e6fc716aca45 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -53,7 +53,6 @@ #define DBG_BLKDEV 0x0100 #define DBG_RX 0x0200 #define DBG_TX 0x0400 -static DEFINE_MUTEX(nbd_mutex); static unsigned int debugflags; #endif /* NDEBUG */ @@ -718,11 +717,9 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n", lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg); - mutex_lock(&nbd_mutex); mutex_lock(&lo->tx_lock); error = __nbd_ioctl(bdev, lo, cmd, arg); mutex_unlock(&lo->tx_lock); - mutex_unlock(&nbd_mutex); return error; } diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index a126e614601f..333c21289d97 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -39,6 +39,8 @@ static struct usb_device_id ath3k_table[] = { /* Atheros AR3011 with sflash firmware*/ { USB_DEVICE(0x0CF3, 0x3002) }, + /* Atheros AR9285 Malbec with sflash firmware */ + { USB_DEVICE(0x03F0, 0x311D) }, { } /* Terminating entry */ }; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 1da773f899a2..4cefa91e6c34 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -102,6 +102,9 @@ static struct usb_device_id blacklist_table[] = { /* Atheros 3011 with sflash firmware */ { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE }, + /* Atheros AR9285 Malbec with sflash firmware */ + { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE }, + /* Broadcom BCM2035 */ { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU }, diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 14033a36bcd0..e2c48a7eccff 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -409,7 +409,8 @@ int register_cdrom(struct cdrom_device_info *cdi) } ENSURE(drive_status, CDC_DRIVE_STATUS ); - ENSURE(media_changed, CDC_MEDIA_CHANGED); + if (cdo->check_events == NULL && cdo->media_changed == NULL) + *change_capability = ~(CDC_MEDIA_CHANGED | CDC_SELECT_DISC); ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY); ENSURE(lock_door, CDC_LOCK); ENSURE(select_speed, CDC_SELECT_SPEED); diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 5bc765d4c3ca..8238f89f73c9 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o obj-$(CONFIG_SX) += sx.o generic_serial.o obj-$(CONFIG_RIO) += rio/ generic_serial.o +obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o obj-$(CONFIG_MSPEC) += mspec.o diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index fcd867d923ba..d8b1b576556c 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig @@ -50,7 +50,7 @@ config AGP_ATI config AGP_AMD tristate "AMD Irongate, 761, and 762 chipset support" - depends on AGP && (X86_32 || ALPHA) + depends on AGP && X86_32 help This option gives you AGP support for the GLX component of X on AMD Irongate, 761, and 762 chipsets. diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index b1b4362bc648..45681c0ff3b6 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -41,22 +41,8 @@ static int amd_create_page_map(struct amd_page_map *page_map) if (page_map->real == NULL) return -ENOMEM; -#ifndef CONFIG_X86 - SetPageReserved(virt_to_page(page_map->real)); - global_cache_flush(); - page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), - PAGE_SIZE); - if (page_map->remapped == NULL) { - ClearPageReserved(virt_to_page(page_map->real)); - free_page((unsigned long) page_map->real); - page_map->real = NULL; - return -ENOMEM; - } - global_cache_flush(); -#else set_memory_uc((unsigned long)page_map->real, 1); page_map->remapped = page_map->real; -#endif for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { writel(agp_bridge->scratch_page, page_map->remapped+i); @@ -68,12 +54,7 @@ static int amd_create_page_map(struct amd_page_map *page_map) static void amd_free_page_map(struct amd_page_map *page_map) { -#ifndef CONFIG_X86 - iounmap(page_map->remapped); - ClearPageReserved(virt_to_page(page_map->real)); -#else set_memory_wb((unsigned long)page_map->real, 1); -#endif free_page((unsigned long) page_map->real); } diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 857df10c0428..b0a0dccc98c1 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -774,20 +774,14 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name); /* - * If the device has not been properly setup, the following will catch - * the problem and should stop the system from crashing. - * 20030610 - hamish@zot.org - */ - if (pci_enable_device(pdev)) { - dev_err(&pdev->dev, "can't enable PCI device\n"); - agp_put_bridge(bridge); - return -ENODEV; - } - - /* * The following fixes the case where the BIOS has "forgotten" to * provide an address range for the GART. * 20030610 - hamish@zot.org + * This happens before pci_enable_device() intentionally; + * calling pci_enable_device() before assigning the resource + * will result in the GART being disabled on machines with such + * BIOSs (the GART ends up with a BAR starting at 0, which + * conflicts a lot of other devices). */ r = &pdev->resource[0]; if (!r->start && r->end) { @@ -798,6 +792,17 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, } } + /* + * If the device has not been properly setup, the following will catch + * the problem and should stop the system from crashing. + * 20030610 - hamish@zot.org + */ + if (pci_enable_device(pdev)) { + dev_err(&pdev->dev, "can't enable PCI device\n"); + agp_put_bridge(bridge); + return -ENODEV; + } + /* Fill in the mode register */ if (cap_ptr) { pci_read_config_dword(pdev, diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 826ab0939a12..fab3d3265adb 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -68,6 +68,7 @@ static struct _intel_private { phys_addr_t gma_bus_addr; u32 PGETBL_save; u32 __iomem *gtt; /* I915G */ + bool clear_fake_agp; /* on first access via agp, fill with scratch */ int num_dcache_entries; union { void __iomem *i9xx_flush_page; @@ -869,21 +870,12 @@ static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge) static int intel_fake_agp_configure(void) { - int i; - if (!intel_enable_gtt()) return -EIO; + intel_private.clear_fake_agp = true; agp_bridge->gart_bus_addr = intel_private.gma_bus_addr; - for (i = 0; i < intel_private.base.gtt_total_entries; i++) { - intel_private.driver->write_entry(intel_private.scratch_page_dma, - i, 0); - } - readl(intel_private.gtt+i-1); /* PCI Posting. */ - - global_cache_flush(); - return 0; } @@ -945,6 +937,13 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem, { int ret = -EINVAL; + if (intel_private.clear_fake_agp) { + int start = intel_private.base.stolen_size / PAGE_SIZE; + int end = intel_private.base.gtt_mappable_entries; + intel_gtt_clear_range(start, end - start); + intel_private.clear_fake_agp = false; + } + if (INTEL_GTT_GEN == 1 && type == AGP_DCACHE_MEMORY) return i810_insert_dcache_entries(mem, pg_start, type); diff --git a/drivers/char/bfin_jtag_comm.c b/drivers/char/bfin_jtag_comm.c index e397df3ad98e..16402445f2b2 100644 --- a/drivers/char/bfin_jtag_comm.c +++ b/drivers/char/bfin_jtag_comm.c @@ -183,16 +183,16 @@ bfin_jc_circ_write(const unsigned char *buf, int count) } #ifndef CONFIG_BFIN_JTAG_COMM_CONSOLE -# define acquire_console_sem() -# define release_console_sem() +# define console_lock() +# define console_unlock() #endif static int bfin_jc_write(struct tty_struct *tty, const unsigned char *buf, int count) { int i; - acquire_console_sem(); + console_lock(); i = bfin_jc_circ_write(buf, count); - release_console_sem(); + console_unlock(); wake_up_process(bfin_jc_kthread); return i; } diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index b6ae6e9a9c5f..7855f9f45b8e 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -320,6 +320,7 @@ static int unload_when_empty = 1; static int add_smi(struct smi_info *smi); static int try_smi_init(struct smi_info *smi); static void cleanup_one_si(struct smi_info *to_clean); +static void cleanup_ipmi_si(void); static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list); static int register_xaction_notifier(struct notifier_block *nb) @@ -3450,16 +3451,7 @@ static int __devinit init_ipmi_si(void) mutex_lock(&smi_infos_lock); if (unload_when_empty && list_empty(&smi_infos)) { mutex_unlock(&smi_infos_lock); -#ifdef CONFIG_PCI - if (pci_registered) - pci_unregister_driver(&ipmi_pci_driver); -#endif - -#ifdef CONFIG_PPC_OF - if (of_registered) - of_unregister_platform_driver(&ipmi_of_platform_driver); -#endif - driver_unregister(&ipmi_driver.driver); + cleanup_ipmi_si(); printk(KERN_WARNING PFX "Unable to find any System Interface(s)\n"); return -ENODEV; diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 36e0fa161c2b..faf5a2c65926 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -577,9 +577,11 @@ duration: if (rc) return; - if (be32_to_cpu(tpm_cmd.header.out.return_code) - != 3 * sizeof(u32)) + if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 || + be32_to_cpu(tpm_cmd.header.out.length) + != sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32)) return; + duration_cap = &tpm_cmd.params.getcap_out.cap.duration; chip->vendor.duration[TPM_SHORT] = usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short)); @@ -939,6 +941,18 @@ ssize_t tpm_show_caps_1_2(struct device * dev, } EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); +ssize_t tpm_show_timeouts(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct tpm_chip *chip = dev_get_drvdata(dev); + + return sprintf(buf, "%d %d %d\n", + jiffies_to_usecs(chip->vendor.duration[TPM_SHORT]), + jiffies_to_usecs(chip->vendor.duration[TPM_MEDIUM]), + jiffies_to_usecs(chip->vendor.duration[TPM_LONG])); +} +EXPORT_SYMBOL_GPL(tpm_show_timeouts); + ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 72ddb031b69a..d84ff772c26f 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -56,6 +56,8 @@ extern ssize_t tpm_show_owned(struct device *, struct device_attribute *attr, char *); extern ssize_t tpm_show_temp_deactivated(struct device *, struct device_attribute *attr, char *); +extern ssize_t tpm_show_timeouts(struct device *, + struct device_attribute *attr, char *); struct tpm_chip; diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index dd21df55689d..0d1d38e5f266 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -376,6 +376,7 @@ static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL); static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); +static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); static struct attribute *tis_attrs[] = { &dev_attr_pubek.attr, @@ -385,7 +386,8 @@ static struct attribute *tis_attrs[] = { &dev_attr_owned.attr, &dev_attr_temp_deactivated.attr, &dev_attr_caps.attr, - &dev_attr_cancel.attr, NULL, + &dev_attr_cancel.attr, + &dev_attr_timeouts.attr, NULL, }; static struct attribute_group tis_attr_grp = { diff --git a/drivers/tty/hvc/virtio_console.c b/drivers/char/virtio_console.c index 896a2ced1d27..490393186338 100644 --- a/drivers/tty/hvc/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2006, 2007, 2009 Rusty Russell, IBM Corporation - * Copyright (C) 2009, 2010 Red Hat, Inc. + * Copyright (C) 2009, 2010, 2011 Red Hat, Inc. + * Copyright (C) 2009, 2010, 2011 Amit Shah <amit.shah@redhat.com> * * 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 @@ -31,7 +32,7 @@ #include <linux/virtio_console.h> #include <linux/wait.h> #include <linux/workqueue.h> -#include "hvc_console.h" +#include "../tty/hvc/hvc_console.h" /* * This is a global struct for storing common data for all the devices @@ -1462,6 +1463,17 @@ static void control_work_handler(struct work_struct *work) spin_unlock(&portdev->cvq_lock); } +static void out_intr(struct virtqueue *vq) +{ + struct port *port; + + port = find_port_by_vq(vq->vdev->priv, vq); + if (!port) + return; + + wake_up_interruptible(&port->waitqueue); +} + static void in_intr(struct virtqueue *vq) { struct port *port; @@ -1566,7 +1578,7 @@ static int init_vqs(struct ports_device *portdev) */ j = 0; io_callbacks[j] = in_intr; - io_callbacks[j + 1] = NULL; + io_callbacks[j + 1] = out_intr; io_names[j] = "input"; io_names[j + 1] = "output"; j += 2; @@ -1580,7 +1592,7 @@ static int init_vqs(struct ports_device *portdev) for (i = 1; i < nr_ports; i++) { j += 2; io_callbacks[j] = in_intr; - io_callbacks[j + 1] = NULL; + io_callbacks[j + 1] = out_intr; io_names[j] = "input"; io_names[j + 1] = "output"; } diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c index 01b886e68822..79c47e88d5d1 100644 --- a/drivers/clocksource/tcb_clksrc.c +++ b/drivers/clocksource/tcb_clksrc.c @@ -196,9 +196,9 @@ static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) clkevt.clkevt.min_delta_ns = clockevent_delta2ns(1, &clkevt.clkevt) + 1; clkevt.clkevt.cpumask = cpumask_of(0); - setup_irq(irq, &tc_irqaction); - clockevents_register_device(&clkevt.clkevt); + + setup_irq(irq, &tc_irqaction); } #else /* !CONFIG_GENERIC_CLOCKEVENTS */ diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 297f48b0cba9..07bca4970e50 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -79,6 +79,7 @@ #include <linux/module.h> #include <linux/interrupt.h> #include <linux/slab.h> +#include <linux/delay.h> #include <linux/dmapool.h> #include <linux/dmaengine.h> #include <linux/amba/bus.h> @@ -235,16 +236,19 @@ static void pl08x_start_txd(struct pl08x_dma_chan *plchan, } /* - * Overall DMAC remains enabled always. + * Pause the channel by setting the HALT bit. * - * Disabling individual channels could lose data. + * For M->P transfers, pause the DMAC first and then stop the peripheral - + * the FIFO can only drain if the peripheral is still requesting data. + * (note: this can still timeout if the DMAC FIFO never drains of data.) * - * Disable the peripheral DMA after disabling the DMAC in order to allow - * the DMAC FIFO to drain, and hence allow the channel to show inactive + * For P->M transfers, disable the peripheral first to stop it filling + * the DMAC FIFO, and then pause the DMAC. */ static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch) { u32 val; + int timeout; /* Set the HALT bit and wait for the FIFO to drain */ val = readl(ch->base + PL080_CH_CONFIG); @@ -252,8 +256,13 @@ static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch) writel(val, ch->base + PL080_CH_CONFIG); /* Wait for channel inactive */ - while (pl08x_phy_channel_busy(ch)) - cpu_relax(); + for (timeout = 1000; timeout; timeout--) { + if (!pl08x_phy_channel_busy(ch)) + break; + udelay(1); + } + if (pl08x_phy_channel_busy(ch)) + pr_err("pl08x: channel%u timeout waiting for pause\n", ch->id); } static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch) @@ -267,19 +276,24 @@ static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch) } -/* Stops the channel */ -static void pl08x_stop_phy_chan(struct pl08x_phy_chan *ch) +/* + * pl08x_terminate_phy_chan() stops the channel, clears the FIFO and + * clears any pending interrupt status. This should not be used for + * an on-going transfer, but as a method of shutting down a channel + * (eg, when it's no longer used) or terminating a transfer. + */ +static void pl08x_terminate_phy_chan(struct pl08x_driver_data *pl08x, + struct pl08x_phy_chan *ch) { - u32 val; + u32 val = readl(ch->base + PL080_CH_CONFIG); - pl08x_pause_phy_chan(ch); + val &= ~(PL080_CONFIG_ENABLE | PL080_CONFIG_ERR_IRQ_MASK | + PL080_CONFIG_TC_IRQ_MASK); - /* Disable channel */ - val = readl(ch->base + PL080_CH_CONFIG); - val &= ~PL080_CONFIG_ENABLE; - val &= ~PL080_CONFIG_ERR_IRQ_MASK; - val &= ~PL080_CONFIG_TC_IRQ_MASK; writel(val, ch->base + PL080_CH_CONFIG); + + writel(1 << ch->id, pl08x->base + PL080_ERR_CLEAR); + writel(1 << ch->id, pl08x->base + PL080_TC_CLEAR); } static inline u32 get_bytes_in_cctl(u32 cctl) @@ -404,13 +418,12 @@ static inline void pl08x_put_phy_channel(struct pl08x_driver_data *pl08x, { unsigned long flags; + spin_lock_irqsave(&ch->lock, flags); + /* Stop the channel and clear its interrupts */ - pl08x_stop_phy_chan(ch); - writel((1 << ch->id), pl08x->base + PL080_ERR_CLEAR); - writel((1 << ch->id), pl08x->base + PL080_TC_CLEAR); + pl08x_terminate_phy_chan(pl08x, ch); /* Mark it as free */ - spin_lock_irqsave(&ch->lock, flags); ch->serving = NULL; spin_unlock_irqrestore(&ch->lock, flags); } @@ -1449,7 +1462,7 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, plchan->state = PL08X_CHAN_IDLE; if (plchan->phychan) { - pl08x_stop_phy_chan(plchan->phychan); + pl08x_terminate_phy_chan(pl08x, plchan->phychan); /* * Mark physical channel as free and free any slave diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index e53d438142bb..e18eaabe92b9 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -49,6 +49,7 @@ struct imxdma_channel { struct imxdma_engine { struct device *dev; + struct device_dma_parameters dma_parms; struct dma_device dma_device; struct imxdma_channel channel[MAX_DMA_CHANNELS]; }; @@ -242,6 +243,21 @@ static struct dma_async_tx_descriptor *imxdma_prep_slave_sg( else dmamode = DMA_MODE_WRITE; + switch (imxdmac->word_size) { + case DMA_SLAVE_BUSWIDTH_4_BYTES: + if (sgl->length & 3 || sgl->dma_address & 3) + return NULL; + break; + case DMA_SLAVE_BUSWIDTH_2_BYTES: + if (sgl->length & 1 || sgl->dma_address & 1) + return NULL; + break; + case DMA_SLAVE_BUSWIDTH_1_BYTE: + break; + default: + return NULL; + } + ret = imx_dma_setup_sg(imxdmac->imxdma_channel, sgl, sg_len, dma_length, imxdmac->per_address, dmamode); if (ret) @@ -329,6 +345,9 @@ static int __init imxdma_probe(struct platform_device *pdev) INIT_LIST_HEAD(&imxdma->dma_device.channels); + dma_cap_set(DMA_SLAVE, imxdma->dma_device.cap_mask); + dma_cap_set(DMA_CYCLIC, imxdma->dma_device.cap_mask); + /* Initialize channel parameters */ for (i = 0; i < MAX_DMA_CHANNELS; i++) { struct imxdma_channel *imxdmac = &imxdma->channel[i]; @@ -346,11 +365,7 @@ static int __init imxdma_probe(struct platform_device *pdev) imxdmac->imxdma = imxdma; spin_lock_init(&imxdmac->lock); - dma_cap_set(DMA_SLAVE, imxdma->dma_device.cap_mask); - dma_cap_set(DMA_CYCLIC, imxdma->dma_device.cap_mask); - imxdmac->chan.device = &imxdma->dma_device; - imxdmac->chan.chan_id = i; imxdmac->channel = i; /* Add the channel to the DMAC list */ @@ -370,6 +385,9 @@ static int __init imxdma_probe(struct platform_device *pdev) platform_set_drvdata(pdev, imxdma); + imxdma->dma_device.dev->dma_parms = &imxdma->dma_parms; + dma_set_max_seg_size(imxdma->dma_device.dev, 0xffffff); + ret = dma_async_device_register(&imxdma->dma_device); if (ret) { dev_err(&pdev->dev, "unable to register\n"); diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index d5a5d4d9c19b..b6d1455fa936 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -230,7 +230,7 @@ struct sdma_engine; * struct sdma_channel - housekeeping for a SDMA channel * * @sdma pointer to the SDMA engine for this channel - * @channel the channel number, matches dmaengine chan_id + * @channel the channel number, matches dmaengine chan_id + 1 * @direction transfer type. Needed for setting SDMA script * @peripheral_type Peripheral type. Needed for setting SDMA script * @event_id0 aka dma request line @@ -301,6 +301,7 @@ struct sdma_firmware_header { struct sdma_engine { struct device *dev; + struct device_dma_parameters dma_parms; struct sdma_channel channel[MAX_DMA_CHANNELS]; struct sdma_channel_control *channel_control; void __iomem *regs; @@ -449,7 +450,7 @@ static void sdma_handle_channel_loop(struct sdma_channel *sdmac) if (bd->mode.status & BD_RROR) sdmac->status = DMA_ERROR; else - sdmac->status = DMA_SUCCESS; + sdmac->status = DMA_IN_PROGRESS; bd->mode.status |= BD_DONE; sdmac->buf_tail++; @@ -770,15 +771,15 @@ static void sdma_enable_channel(struct sdma_engine *sdma, int channel) __raw_writel(1 << channel, sdma->regs + SDMA_H_START); } -static dma_cookie_t sdma_assign_cookie(struct sdma_channel *sdma) +static dma_cookie_t sdma_assign_cookie(struct sdma_channel *sdmac) { - dma_cookie_t cookie = sdma->chan.cookie; + dma_cookie_t cookie = sdmac->chan.cookie; if (++cookie < 0) cookie = 1; - sdma->chan.cookie = cookie; - sdma->desc.cookie = cookie; + sdmac->chan.cookie = cookie; + sdmac->desc.cookie = cookie; return cookie; } @@ -798,7 +799,7 @@ static dma_cookie_t sdma_tx_submit(struct dma_async_tx_descriptor *tx) cookie = sdma_assign_cookie(sdmac); - sdma_enable_channel(sdma, tx->chan->chan_id); + sdma_enable_channel(sdma, sdmac->channel); spin_unlock_irq(&sdmac->lock); @@ -811,10 +812,6 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan) struct imx_dma_data *data = chan->private; int prio, ret; - /* No need to execute this for internal channel 0 */ - if (chan->chan_id == 0) - return 0; - if (!data) return -EINVAL; @@ -879,7 +876,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg( struct sdma_channel *sdmac = to_sdma_chan(chan); struct sdma_engine *sdma = sdmac->sdma; int ret, i, count; - int channel = chan->chan_id; + int channel = sdmac->channel; struct scatterlist *sg; if (sdmac->status == DMA_IN_PROGRESS) @@ -924,22 +921,33 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg( ret = -EINVAL; goto err_out; } - if (sdmac->word_size == DMA_SLAVE_BUSWIDTH_4_BYTES) + + switch (sdmac->word_size) { + case DMA_SLAVE_BUSWIDTH_4_BYTES: bd->mode.command = 0; - else - bd->mode.command = sdmac->word_size; + if (count & 3 || sg->dma_address & 3) + return NULL; + break; + case DMA_SLAVE_BUSWIDTH_2_BYTES: + bd->mode.command = 2; + if (count & 1 || sg->dma_address & 1) + return NULL; + break; + case DMA_SLAVE_BUSWIDTH_1_BYTE: + bd->mode.command = 1; + break; + default: + return NULL; + } param = BD_DONE | BD_EXTD | BD_CONT; - if (sdmac->flags & IMX_DMA_SG_LOOP) { + if (i + 1 == sg_len) { param |= BD_INTR; - if (i + 1 == sg_len) - param |= BD_WRAP; + param |= BD_LAST; + param &= ~BD_CONT; } - if (i + 1 == sg_len) - param |= BD_INTR; - dev_dbg(sdma->dev, "entry %d: count: %d dma: 0x%08x %s%s\n", i, count, sg->dma_address, param & BD_WRAP ? "wrap" : "", @@ -953,6 +961,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg( return &sdmac->desc; err_out: + sdmac->status = DMA_ERROR; return NULL; } @@ -963,7 +972,7 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic( struct sdma_channel *sdmac = to_sdma_chan(chan); struct sdma_engine *sdma = sdmac->sdma; int num_periods = buf_len / period_len; - int channel = chan->chan_id; + int channel = sdmac->channel; int ret, i = 0, buf = 0; dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel); @@ -1066,14 +1075,12 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan, { struct sdma_channel *sdmac = to_sdma_chan(chan); dma_cookie_t last_used; - enum dma_status ret; last_used = chan->cookie; - ret = dma_async_is_complete(cookie, sdmac->last_completed, last_used); dma_set_tx_state(txstate, sdmac->last_completed, last_used, 0); - return ret; + return sdmac->status; } static void sdma_issue_pending(struct dma_chan *chan) @@ -1135,7 +1142,7 @@ static int __init sdma_get_firmware(struct sdma_engine *sdma, /* download the RAM image for SDMA */ sdma_load_script(sdma, ram_code, header->ram_code_size, - sdma->script_addrs->ram_code_start_addr); + addr->ram_code_start_addr); clk_disable(sdma->clk); sdma_add_scripts(sdma, addr); @@ -1237,7 +1244,6 @@ static int __init sdma_probe(struct platform_device *pdev) struct resource *iores; struct sdma_platform_data *pdata = pdev->dev.platform_data; int i; - dma_cap_mask_t mask; struct sdma_engine *sdma; sdma = kzalloc(sizeof(*sdma), GFP_KERNEL); @@ -1280,6 +1286,9 @@ static int __init sdma_probe(struct platform_device *pdev) sdma->version = pdata->sdma_version; + dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask); + dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask); + INIT_LIST_HEAD(&sdma->dma_device.channels); /* Initialize channel parameters */ for (i = 0; i < MAX_DMA_CHANNELS; i++) { @@ -1288,15 +1297,17 @@ static int __init sdma_probe(struct platform_device *pdev) sdmac->sdma = sdma; spin_lock_init(&sdmac->lock); - dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask); - dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask); - sdmac->chan.device = &sdma->dma_device; - sdmac->chan.chan_id = i; sdmac->channel = i; - /* Add the channel to the DMAC list */ - list_add_tail(&sdmac->chan.device_node, &sdma->dma_device.channels); + /* + * Add the channel to the DMAC list. Do not add channel 0 though + * because we need it internally in the SDMA driver. This also means + * that channel 0 in dmaengine counting matches sdma channel 1. + */ + if (i) + list_add_tail(&sdmac->chan.device_node, + &sdma->dma_device.channels); } ret = sdma_init(sdma); @@ -1317,6 +1328,8 @@ static int __init sdma_probe(struct platform_device *pdev) sdma->dma_device.device_prep_dma_cyclic = sdma_prep_dma_cyclic; sdma->dma_device.device_control = sdma_control; sdma->dma_device.device_issue_pending = sdma_issue_pending; + sdma->dma_device.dev->dma_parms = &sdma->dma_parms; + dma_set_max_seg_size(sdma->dma_device.dev, 65535); ret = dma_async_device_register(&sdma->dma_device); if (ret) { @@ -1324,13 +1337,6 @@ static int __init sdma_probe(struct platform_device *pdev) goto err_init; } - /* request channel 0. This is an internal control channel - * to the SDMA engine and not available to clients. - */ - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - dma_request_channel(mask, NULL, NULL); - dev_info(sdma->dev, "initialized\n"); return 0; @@ -1348,7 +1354,7 @@ err_clk: err_request_region: err_irq: kfree(sdma); - return 0; + return ret; } static int __exit sdma_remove(struct platform_device *pdev) diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c index cb26ee9773d6..c1a125e7d1df 100644 --- a/drivers/dma/ipu/ipu_idmac.c +++ b/drivers/dma/ipu/ipu_idmac.c @@ -1145,29 +1145,6 @@ static int ipu_disable_channel(struct idmac *idmac, struct idmac_channel *ichan, reg = idmac_read_icreg(ipu, IDMAC_CHA_EN); idmac_write_icreg(ipu, reg & ~chan_mask, IDMAC_CHA_EN); - /* - * Problem (observed with channel DMAIC_7): after enabling the channel - * and initialising buffers, there comes an interrupt with current still - * pointing at buffer 0, whereas it should use buffer 0 first and only - * generate an interrupt when it is done, then current should already - * point to buffer 1. This spurious interrupt also comes on channel - * DMASDC_0. With DMAIC_7 normally, is we just leave the ISR after the - * first interrupt, there comes the second with current correctly - * pointing to buffer 1 this time. But sometimes this second interrupt - * doesn't come and the channel hangs. Clearing BUFx_RDY when disabling - * the channel seems to prevent the channel from hanging, but it doesn't - * prevent the spurious interrupt. This might also be unsafe. Think - * about the IDMAC controller trying to switch to a buffer, when we - * clear the ready bit, and re-enable it a moment later. - */ - reg = idmac_read_ipureg(ipu, IPU_CHA_BUF0_RDY); - idmac_write_ipureg(ipu, 0, IPU_CHA_BUF0_RDY); - idmac_write_ipureg(ipu, reg & ~(1UL << channel), IPU_CHA_BUF0_RDY); - - reg = idmac_read_ipureg(ipu, IPU_CHA_BUF1_RDY); - idmac_write_ipureg(ipu, 0, IPU_CHA_BUF1_RDY); - idmac_write_ipureg(ipu, reg & ~(1UL << channel), IPU_CHA_BUF1_RDY); - spin_unlock_irqrestore(&ipu->lock, flags); return 0; @@ -1246,33 +1223,6 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id) /* Other interrupts do not interfere with this channel */ spin_lock(&ichan->lock); - if (unlikely(chan_id != IDMAC_SDC_0 && chan_id != IDMAC_SDC_1 && - ((curbuf >> chan_id) & 1) == ichan->active_buffer && - !list_is_last(ichan->queue.next, &ichan->queue))) { - int i = 100; - - /* This doesn't help. See comment in ipu_disable_channel() */ - while (--i) { - curbuf = idmac_read_ipureg(&ipu_data, IPU_CHA_CUR_BUF); - if (((curbuf >> chan_id) & 1) != ichan->active_buffer) - break; - cpu_relax(); - } - - if (!i) { - spin_unlock(&ichan->lock); - dev_dbg(dev, - "IRQ on active buffer on channel %x, active " - "%d, ready %x, %x, current %x!\n", chan_id, - ichan->active_buffer, ready0, ready1, curbuf); - return IRQ_NONE; - } else - dev_dbg(dev, - "Buffer deactivated on channel %x, active " - "%d, ready %x, %x, current %x, rest %d!\n", chan_id, - ichan->active_buffer, ready0, ready1, curbuf, i); - } - if (unlikely((ichan->active_buffer && (ready1 >> chan_id) & 1) || (!ichan->active_buffer && (ready0 >> chan_id) & 1) )) { diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 4a5ecc58025d..23e03554f0d3 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -826,8 +826,6 @@ static void amd64_dump_dramcfg_low(u32 dclr, int chan) /* Display and decode various NB registers for debug purposes. */ static void amd64_dump_misc_regs(struct amd64_pvt *pvt) { - int ganged; - debugf1("F3xE8 (NB Cap): 0x%08x\n", pvt->nbcap); debugf1(" NB two channel DRAM capable: %s\n", @@ -851,28 +849,19 @@ static void amd64_dump_misc_regs(struct amd64_pvt *pvt) debugf1(" DramHoleValid: %s\n", (pvt->dhar & DHAR_VALID) ? "yes" : "no"); + amd64_debug_display_dimm_sizes(0, pvt); + /* everything below this point is Fam10h and above */ - if (boot_cpu_data.x86 == 0xf) { - amd64_debug_display_dimm_sizes(0, pvt); + if (boot_cpu_data.x86 == 0xf) return; - } + + amd64_debug_display_dimm_sizes(1, pvt); amd64_info("using %s syndromes.\n", ((pvt->syn_type == 8) ? "x8" : "x4")); /* Only if NOT ganged does dclr1 have valid info */ if (!dct_ganging_enabled(pvt)) amd64_dump_dramcfg_low(pvt->dclr1, 1); - - /* - * Determine if ganged and then dump memory sizes for first controller, - * and if NOT ganged dump info for 2nd controller. - */ - ganged = dct_ganging_enabled(pvt); - - amd64_debug_display_dimm_sizes(0, pvt); - - if (!ganged) - amd64_debug_display_dimm_sizes(1, pvt); } /* Read in both of DBAM registers */ @@ -1644,11 +1633,10 @@ static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt) WARN_ON(ctrl != 0); } - debugf1("F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n", - ctrl, ctrl ? pvt->dbam1 : pvt->dbam0); + dbam = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dbam1 : pvt->dbam0; + dcsb = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dcsb1 : pvt->dcsb0; - dbam = ctrl ? pvt->dbam1 : pvt->dbam0; - dcsb = ctrl ? pvt->dcsb1 : pvt->dcsb0; + debugf1("F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n", ctrl, dbam); edac_printk(KERN_DEBUG, EDAC_MC, "DCT%d chip selects:\n", ctrl); diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index e28e41668177..bcb1126e3d00 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -378,10 +378,17 @@ static void __init print_filtered(const char *info) static void __init dmi_dump_ids(void) { + const char *board; /* Board Name is optional */ + printk(KERN_DEBUG "DMI: "); - print_filtered(dmi_get_system_info(DMI_BOARD_NAME)); - printk(KERN_CONT "/"); + print_filtered(dmi_get_system_info(DMI_SYS_VENDOR)); + printk(KERN_CONT " "); print_filtered(dmi_get_system_info(DMI_PRODUCT_NAME)); + board = dmi_get_system_info(DMI_BOARD_NAME); + if (board) { + printk(KERN_CONT "/"); + print_filtered(board); + } printk(KERN_CONT ", BIOS "); print_filtered(dmi_get_system_info(DMI_BIOS_VERSION)); printk(KERN_CONT " "); diff --git a/drivers/gpio/langwell_gpio.c b/drivers/gpio/langwell_gpio.c index d81cc748e77f..54d70a47afc1 100644 --- a/drivers/gpio/langwell_gpio.c +++ b/drivers/gpio/langwell_gpio.c @@ -187,7 +187,7 @@ MODULE_DEVICE_TABLE(pci, lnw_gpio_ids); static void lnw_irq_handler(unsigned irq, struct irq_desc *desc) { - struct lnw_gpio *lnw = (struct lnw_gpio *)get_irq_data(irq); + struct lnw_gpio *lnw = get_irq_data(irq); u32 base, gpio; void __iomem *gedr; u32 gedr_v; @@ -206,7 +206,12 @@ static void lnw_irq_handler(unsigned irq, struct irq_desc *desc) /* clear the edge detect status bit */ writel(gedr_v, gedr); } - desc->chip->eoi(irq); + + if (desc->chip->irq_eoi) + desc->chip->irq_eoi(irq_get_irq_data(irq)); + else + dev_warn(lnw->chip.dev, "missing EOI handler for irq %d\n", irq); + } static int __devinit lnw_gpio_probe(struct pci_dev *pdev, diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index a261972f603d..b473429eee75 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -60,6 +60,7 @@ struct pca953x_chip { unsigned gpio_start; uint16_t reg_output; uint16_t reg_direction; + struct mutex i2c_lock; #ifdef CONFIG_GPIO_PCA953X_IRQ struct mutex irq_lock; @@ -119,13 +120,17 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) chip = container_of(gc, struct pca953x_chip, gpio_chip); + mutex_lock(&chip->i2c_lock); reg_val = chip->reg_direction | (1u << off); ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val); if (ret) - return ret; + goto exit; chip->reg_direction = reg_val; - return 0; + ret = 0; +exit: + mutex_unlock(&chip->i2c_lock); + return ret; } static int pca953x_gpio_direction_output(struct gpio_chip *gc, @@ -137,6 +142,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, chip = container_of(gc, struct pca953x_chip, gpio_chip); + mutex_lock(&chip->i2c_lock); /* set output level */ if (val) reg_val = chip->reg_output | (1u << off); @@ -145,7 +151,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val); if (ret) - return ret; + goto exit; chip->reg_output = reg_val; @@ -153,10 +159,13 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, reg_val = chip->reg_direction & ~(1u << off); ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val); if (ret) - return ret; + goto exit; chip->reg_direction = reg_val; - return 0; + ret = 0; +exit: + mutex_unlock(&chip->i2c_lock); + return ret; } static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) @@ -167,7 +176,9 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) chip = container_of(gc, struct pca953x_chip, gpio_chip); + mutex_lock(&chip->i2c_lock); ret = pca953x_read_reg(chip, PCA953X_INPUT, ®_val); + mutex_unlock(&chip->i2c_lock); if (ret < 0) { /* NOTE: diagnostic already emitted; that's all we should * do unless gpio_*_value_cansleep() calls become different @@ -187,6 +198,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) chip = container_of(gc, struct pca953x_chip, gpio_chip); + mutex_lock(&chip->i2c_lock); if (val) reg_val = chip->reg_output | (1u << off); else @@ -194,9 +206,11 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val); if (ret) - return; + goto exit; chip->reg_output = reg_val; +exit: + mutex_unlock(&chip->i2c_lock); } static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) @@ -517,6 +531,8 @@ static int __devinit pca953x_probe(struct i2c_client *client, chip->names = pdata->names; + mutex_init(&chip->i2c_lock); + /* initialize cached registers from their original values. * we can't share this chip with another i2c master. */ diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index bea966f8ac84..0902d4460039 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -100,7 +100,10 @@ config DRM_I830 config DRM_I915 tristate "i915 driver" depends on AGP_INTEL + # we need shmfs for the swappable backing store, and in particular + # the shmem_readpage() which depends upon tmpfs select SHMEM + select TMPFS select DRM_KMS_HELPER select FB_CFB_FILLRECT select FB_CFB_COPYAREA diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 2baa6708e44c..654faa803dcb 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2674,3 +2674,23 @@ out: mutex_unlock(&dev->mode_config.mutex); return ret; } + +void drm_mode_config_reset(struct drm_device *dev) +{ + struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector *connector; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + if (crtc->funcs->reset) + crtc->funcs->reset(crtc); + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) + if (encoder->funcs->reset) + encoder->funcs->reset(encoder); + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) + if (connector->funcs->reset) + connector->funcs->reset(connector); +} +EXPORT_SYMBOL(drm_mode_config_reset); diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 952b3d4fb2a6..92369655dca3 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -343,13 +343,12 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_encoder *encoder; bool ret = true; - adjusted_mode = drm_mode_duplicate(dev, mode); - crtc->enabled = drm_helper_crtc_in_use(crtc); - if (!crtc->enabled) return true; + adjusted_mode = drm_mode_duplicate(dev, mode); + saved_hwmode = crtc->hwmode; saved_mode = crtc->mode; saved_x = crtc->x; @@ -437,10 +436,9 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, */ drm_calc_timestamping_constants(crtc); - /* XXX free adjustedmode */ - drm_mode_destroy(dev, adjusted_mode); /* FIXME: add subpixel order */ done: + drm_mode_destroy(dev, adjusted_mode); if (!ret) { crtc->hwmode = saved_hwmode; crtc->mode = saved_mode; @@ -497,14 +495,17 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) crtc_funcs = set->crtc->helper_private; + if (!set->mode) + set->fb = NULL; + if (set->fb) { DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n", set->crtc->base.id, set->fb->base.id, (int)set->num_connectors, set->x, set->y); } else { - DRM_DEBUG_KMS("[CRTC:%d] [NOFB] #connectors=%d (x y) (%i %i)\n", - set->crtc->base.id, (int)set->num_connectors, - set->x, set->y); + DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id); + set->mode = NULL; + set->num_connectors = 0; } dev = set->crtc->dev; @@ -649,8 +650,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) mode_changed = true; if (mode_changed) { - set->crtc->enabled = (set->mode != NULL); - if (set->mode != NULL) { + set->crtc->enabled = drm_helper_crtc_in_use(set->crtc); + if (set->crtc->enabled) { DRM_DEBUG_KMS("attempting to set mode from" " userspace\n"); drm_mode_debug_printmodeline(set->mode); @@ -665,6 +666,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ret = -EINVAL; goto fail; } + DRM_DEBUG_KMS("Setting connector DPMS state to on\n"); + for (i = 0; i < set->num_connectors; i++) { + DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id, + drm_get_connector_name(set->connectors[i])); + set->connectors[i]->dpms = DRM_MODE_DPMS_ON; + } } drm_helper_disable_unused_functions(dev); } else if (fb_changed) { @@ -681,12 +688,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) goto fail; } } - DRM_DEBUG_KMS("Setting connector DPMS state to on\n"); - for (i = 0; i < set->num_connectors; i++) { - DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id, - drm_get_connector_name(set->connectors[i])); - set->connectors[i]->dpms = DRM_MODE_DPMS_ON; - } kfree(save_connectors); kfree(save_encoders); diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c index 3cdbaf379bb5..be9a9c07d152 100644 --- a/drivers/gpu/drm/drm_info.c +++ b/drivers/gpu/drm/drm_info.c @@ -283,17 +283,18 @@ int drm_vma_info(struct seq_file *m, void *data) #endif mutex_lock(&dev->struct_mutex); - seq_printf(m, "vma use count: %d, high_memory = %p, 0x%08llx\n", + seq_printf(m, "vma use count: %d, high_memory = %pK, 0x%pK\n", atomic_read(&dev->vma_count), - high_memory, (u64)virt_to_phys(high_memory)); + high_memory, (void *)virt_to_phys(high_memory)); list_for_each_entry(pt, &dev->vmalist, head) { vma = pt->vma; if (!vma) continue; seq_printf(m, - "\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000", - pt->pid, vma->vm_start, vma->vm_end, + "\n%5d 0x%pK-0x%pK %c%c%c%c%c%c 0x%08lx000", + pt->pid, + (void *)vma->vm_start, (void *)vma->vm_end, vma->vm_flags & VM_READ ? 'r' : '-', vma->vm_flags & VM_WRITE ? 'w' : '-', vma->vm_flags & VM_EXEC ? 'x' : '-', diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 0054e957203f..3dadfa2a8528 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1250,7 +1250,7 @@ void drm_handle_vblank_events(struct drm_device *dev, int crtc) * Drivers should call this routine in their vblank interrupt handlers to * update the vblank counter and send any signals that may be pending. */ -void drm_handle_vblank(struct drm_device *dev, int crtc) +bool drm_handle_vblank(struct drm_device *dev, int crtc) { u32 vblcount; s64 diff_ns; @@ -1258,7 +1258,7 @@ void drm_handle_vblank(struct drm_device *dev, int crtc) unsigned long irqflags; if (!dev->num_crtcs) - return; + return false; /* Need timestamp lock to prevent concurrent execution with * vblank enable/disable, as this would cause inconsistent @@ -1269,7 +1269,7 @@ void drm_handle_vblank(struct drm_device *dev, int crtc) /* Vblank irq handling disabled. Nothing to do. */ if (!dev->vblank_enabled[crtc]) { spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); - return; + return false; } /* Fetch corresponding timestamp for this vblank interval from @@ -1311,5 +1311,6 @@ void drm_handle_vblank(struct drm_device *dev, int crtc) drm_handle_vblank_events(dev, crtc); spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); + return true; } EXPORT_SYMBOL(drm_handle_vblank); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 844f3c972b04..17bd766f2081 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -152,7 +152,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; - struct intel_ring_buffer *ring = LP_RING(dev_priv); + int ret; master_priv->sarea = drm_getsarea(dev); if (master_priv->sarea) { @@ -163,33 +163,22 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) } if (init->ring_size != 0) { - if (ring->obj != NULL) { + if (LP_RING(dev_priv)->obj != NULL) { i915_dma_cleanup(dev); DRM_ERROR("Client tried to initialize ringbuffer in " "GEM mode\n"); return -EINVAL; } - ring->size = init->ring_size; - - ring->map.offset = init->ring_start; - ring->map.size = init->ring_size; - ring->map.type = 0; - ring->map.flags = 0; - ring->map.mtrr = 0; - - drm_core_ioremap_wc(&ring->map, dev); - - if (ring->map.handle == NULL) { + ret = intel_render_ring_init_dri(dev, + init->ring_start, + init->ring_size); + if (ret) { i915_dma_cleanup(dev); - DRM_ERROR("can not ioremap virtual address for" - " ring buffer\n"); - return -ENOMEM; + return ret; } } - ring->virtual_start = ring->map.handle; - dev_priv->cpp = init->cpp; dev_priv->back_offset = init->back_offset; dev_priv->front_offset = init->front_offset; @@ -1226,9 +1215,15 @@ static int i915_load_modeset_init(struct drm_device *dev) if (ret) DRM_INFO("failed to find VBIOS tables\n"); - /* if we have > 1 VGA cards, then disable the radeon VGA resources */ + /* If we have > 1 VGA cards, then we need to arbitrate access + * to the common VGA resources. + * + * If we are a secondary display controller (!PCI_DISPLAY_CLASS_VGA), + * then we do not take part in VGA arbitration and the + * vga_client_register() fails with -ENODEV. + */ ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_set_decode); - if (ret) + if (ret && ret != -ENODEV) goto cleanup_ringbuffer; intel_register_dsm_handler(); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 72fea2bcfc4f..0ad533f06af9 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -46,6 +46,9 @@ module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); unsigned int i915_powersave = 1; module_param_named(powersave, i915_powersave, int, 0600); +unsigned int i915_enable_rc6 = 0; +module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600); + unsigned int i915_lvds_downclock = 0; module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400); @@ -60,7 +63,7 @@ extern int intel_agp_enabled; #define INTEL_VGA_DEVICE(id, info) { \ .class = PCI_CLASS_DISPLAY_VGA << 8, \ - .class_mask = 0xffff00, \ + .class_mask = 0xff0000, \ .vendor = 0x8086, \ .device = id, \ .subvendor = PCI_ANY_ID, \ @@ -354,12 +357,13 @@ static int i915_drm_thaw(struct drm_device *dev) error = i915_gem_init_ringbuffer(dev); mutex_unlock(&dev->struct_mutex); + drm_mode_config_reset(dev); drm_irq_install(dev); /* Resume the modeset for every activated CRTC */ drm_helper_resume_force_mode(dev); - if (dev_priv->renderctx && dev_priv->pwrctx) + if (IS_IRONLAKE_M(dev)) ironlake_enable_rc6(dev); } @@ -542,6 +546,7 @@ int i915_reset(struct drm_device *dev, u8 flags) mutex_unlock(&dev->struct_mutex); drm_irq_uninstall(dev); + drm_mode_config_reset(dev); drm_irq_install(dev); mutex_lock(&dev->struct_mutex); } @@ -566,6 +571,14 @@ int i915_reset(struct drm_device *dev, u8 flags) static int __devinit i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { + /* Only bind to function 0 of the device. Early generations + * used function 1 as a placeholder for multi-head. This causes + * us confusion instead, especially on the systems where both + * functions have the same PCI-ID! + */ + if (PCI_FUNC(pdev->devfn)) + return -ENODEV; + return drm_get_pci_dev(pdev, ent, &driver); } @@ -752,6 +765,9 @@ static int __init i915_init(void) driver.driver_features &= ~DRIVER_MODESET; #endif + if (!(driver.driver_features & DRIVER_MODESET)) + driver.get_vblank_timestamp = NULL; + return drm_init(&driver); } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5969f46ac2d6..65dfe81d0035 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -543,8 +543,11 @@ typedef struct drm_i915_private { /** List of all objects in gtt_space. Used to restore gtt * mappings on resume */ struct list_head gtt_list; - /** End of mappable part of GTT */ + + /** Usable portion of the GTT for GEM */ + unsigned long gtt_start; unsigned long gtt_mappable_end; + unsigned long gtt_end; struct io_mapping *gtt_mapping; int gtt_mtrr; @@ -955,6 +958,7 @@ extern unsigned int i915_fbpercrtc; extern unsigned int i915_powersave; extern unsigned int i915_lvds_downclock; extern unsigned int i915_panel_use_ssc; +extern unsigned int i915_enable_rc6; extern int i915_suspend(struct drm_device *dev, pm_message_t state); extern int i915_resume(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 3dfc848ff755..cf4f74c7c6fb 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -140,12 +140,16 @@ void i915_gem_do_init(struct drm_device *dev, { drm_i915_private_t *dev_priv = dev->dev_private; - drm_mm_init(&dev_priv->mm.gtt_space, start, - end - start); + drm_mm_init(&dev_priv->mm.gtt_space, start, end - start); + dev_priv->mm.gtt_start = start; + dev_priv->mm.gtt_mappable_end = mappable_end; + dev_priv->mm.gtt_end = end; dev_priv->mm.gtt_total = end - start; dev_priv->mm.mappable_gtt_total = min(end, mappable_end) - start; - dev_priv->mm.gtt_mappable_end = mappable_end; + + /* Take over this portion of the GTT */ + intel_gtt_clear_range(start / PAGE_SIZE, (end-start) / PAGE_SIZE); } int @@ -1857,7 +1861,7 @@ i915_gem_retire_requests_ring(struct drm_device *dev, seqno = ring->get_seqno(ring); - for (i = 0; i < I915_NUM_RINGS; i++) + for (i = 0; i < ARRAY_SIZE(ring->sync_seqno); i++) if (seqno >= ring->sync_seqno[i]) ring->sync_seqno[i] = 0; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index dcfdf4151b6d..d2f445e825f2 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1175,7 +1175,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto err; seqno = i915_gem_next_request_seqno(dev, ring); - for (i = 0; i < I915_NUM_RINGS-1; i++) { + for (i = 0; i < ARRAY_SIZE(ring->sync_seqno); i++) { if (seqno < ring->sync_seqno[i]) { /* The GPU can not handle its semaphore value wrapping, * so every billion or so execbuffers, we need to stall diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 70433ae50ac8..b0abdc64aa9f 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -34,6 +34,10 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; + /* First fill our portion of the GTT with scratch pages */ + intel_gtt_clear_range(dev_priv->mm.gtt_start / PAGE_SIZE, + (dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE); + list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) { i915_gem_clflush_object(obj); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b8e509ae065e..97f946dcc1aa 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -274,24 +274,35 @@ int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, return ret; } -int i915_get_vblank_timestamp(struct drm_device *dev, int crtc, +int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, int *max_error, struct timeval *vblank_time, unsigned flags) { - struct drm_crtc *drmcrtc; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; - if (crtc < 0 || crtc >= dev->num_crtcs) { - DRM_ERROR("Invalid crtc %d\n", crtc); + if (pipe < 0 || pipe >= dev_priv->num_pipe) { + DRM_ERROR("Invalid crtc %d\n", pipe); return -EINVAL; } /* Get drm_crtc to timestamp: */ - drmcrtc = intel_get_crtc_for_pipe(dev, crtc); + crtc = intel_get_crtc_for_pipe(dev, pipe); + if (crtc == NULL) { + DRM_ERROR("Invalid crtc %d\n", pipe); + return -EINVAL; + } + + if (!crtc->enabled) { + DRM_DEBUG_KMS("crtc %d is disabled\n", pipe); + return -EBUSY; + } /* Helper routine in DRM core does all the work: */ - return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error, - vblank_time, flags, drmcrtc); + return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error, + vblank_time, flags, + crtc); } /* @@ -348,8 +359,12 @@ static void notify_ring(struct drm_device *dev, struct intel_ring_buffer *ring) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 seqno = ring->get_seqno(ring); + u32 seqno; + if (ring->obj == NULL) + return; + + seqno = ring->get_seqno(ring); trace_i915_gem_request_complete(dev, seqno); ring->irq_seqno = seqno; @@ -831,6 +846,8 @@ static void i915_capture_error_state(struct drm_device *dev) i++; error->pinned_bo_count = i - error->active_bo_count; + error->active_bo = NULL; + error->pinned_bo = NULL; if (i) { error->active_bo = kmalloc(sizeof(*error->active_bo)*i, GFP_ATOMIC); @@ -1179,18 +1196,18 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) intel_finish_page_flip_plane(dev, 1); } - if (pipea_stats & vblank_status) { + if (pipea_stats & vblank_status && + drm_handle_vblank(dev, 0)) { vblank++; - drm_handle_vblank(dev, 0); if (!dev_priv->flip_pending_is_done) { i915_pageflip_stall_check(dev, 0); intel_finish_page_flip(dev, 0); } } - if (pipeb_stats & vblank_status) { + if (pipeb_stats & vblank_status && + drm_handle_vblank(dev, 1)) { vblank++; - drm_handle_vblank(dev, 1); if (!dev_priv->flip_pending_is_done) { i915_pageflip_stall_check(dev, 1); intel_finish_page_flip(dev, 1); @@ -1278,12 +1295,12 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) if (master_priv->sarea_priv) master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; - ret = -ENODEV; if (ring->irq_get(ring)) { DRM_WAIT_ON(ret, ring->irq_queue, 3 * DRM_HZ, READ_BREADCRUMB(dev_priv) >= irq_nr); ring->irq_put(ring); - } + } else if (wait_for(READ_BREADCRUMB(dev_priv) >= irq_nr, 3000)) + ret = -EBUSY; if (ret == -EBUSY) { DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 40a407f41f61..15d94c63918c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -174,7 +174,9 @@ * address/value pairs. Don't overdue it, though, x <= 2^4 must hold! */ #define MI_LOAD_REGISTER_IMM(x) MI_INSTR(0x22, 2*x-1) -#define MI_FLUSH_DW MI_INSTR(0x26, 2) /* for GEN6 */ +#define MI_FLUSH_DW MI_INSTR(0x26, 1) /* for GEN6 */ +#define MI_INVALIDATE_TLB (1<<18) +#define MI_INVALIDATE_BSD (1<<7) #define MI_BATCH_BUFFER MI_INSTR(0x30, 1) #define MI_BATCH_NON_SECURE (1) #define MI_BATCH_NON_SECURE_I965 (1<<8) @@ -513,6 +515,10 @@ #define GEN6_BLITTER_SYNC_STATUS (1 << 24) #define GEN6_BLITTER_USER_INTERRUPT (1 << 22) +#define GEN6_BLITTER_ECOSKPD 0x221d0 +#define GEN6_BLITTER_LOCK_SHIFT 16 +#define GEN6_BLITTER_FBC_NOTIFY (1<<3) + #define GEN6_BSD_SLEEP_PSMI_CONTROL 0x12050 #define GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK (1 << 16) #define GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_DISABLE (1 << 0) @@ -2626,6 +2632,8 @@ #define DISPLAY_PORT_PLL_BIOS_2 0x46014 #define PCH_DSPCLK_GATE_D 0x42020 +# define DPFCUNIT_CLOCK_GATE_DISABLE (1 << 9) +# define DPFCRUNIT_CLOCK_GATE_DISABLE (1 << 8) # define DPFDUNIT_CLOCK_GATE_DISABLE (1 << 7) # define DPARBUNIT_CLOCK_GATE_DISABLE (1 << 5) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 17035b87ee46..8a77ff4a7237 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -535,6 +535,15 @@ static int intel_crt_set_property(struct drm_connector *connector, return 0; } +static void intel_crt_reset(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct intel_crt *crt = intel_attached_crt(connector); + + if (HAS_PCH_SPLIT(dev)) + crt->force_hotplug_required = 1; +} + /* * Routines for controlling stuff on the analog port */ @@ -548,6 +557,7 @@ static const struct drm_encoder_helper_funcs intel_crt_helper_funcs = { }; static const struct drm_connector_funcs intel_crt_connector_funcs = { + .reset = intel_crt_reset, .dpms = drm_helper_connector_dpms, .detect = intel_crt_detect, .fill_modes = drm_helper_probe_single_connector_modes, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 98967f3b7724..3b006536b3d2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1213,6 +1213,26 @@ static bool g4x_fbc_enabled(struct drm_device *dev) return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN; } +static void sandybridge_blit_fbc_update(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 blt_ecoskpd; + + /* Make sure blitter notifies FBC of writes */ + __gen6_force_wake_get(dev_priv); + blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD); + blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY << + GEN6_BLITTER_LOCK_SHIFT; + I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); + blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY; + I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); + blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY << + GEN6_BLITTER_LOCK_SHIFT); + I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); + POSTING_READ(GEN6_BLITTER_ECOSKPD); + __gen6_force_wake_put(dev_priv); +} + static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) { struct drm_device *dev = crtc->dev; @@ -1266,6 +1286,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) I915_WRITE(SNB_DPFC_CTL_SA, SNB_CPU_FENCE_ENABLE | dev_priv->cfb_fence); I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y); + sandybridge_blit_fbc_update(dev); } DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); @@ -5530,6 +5551,16 @@ cleanup_work: return ret; } +static void intel_crtc_reset(struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + /* Reset flags back to the 'unknown' status so that they + * will be correctly set on the initial modeset. + */ + intel_crtc->dpms_mode = -1; +} + static struct drm_crtc_helper_funcs intel_helper_funcs = { .dpms = intel_crtc_dpms, .mode_fixup = intel_crtc_mode_fixup, @@ -5541,6 +5572,7 @@ static struct drm_crtc_helper_funcs intel_helper_funcs = { }; static const struct drm_crtc_funcs intel_crtc_funcs = { + .reset = intel_crtc_reset, .cursor_set = intel_crtc_cursor_set, .cursor_move = intel_crtc_cursor_move, .gamma_set = intel_crtc_gamma_set, @@ -5631,8 +5663,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base; dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base; - intel_crtc->cursor_addr = 0; - intel_crtc->dpms_mode = -1; + intel_crtc_reset(&intel_crtc->base); intel_crtc->active = true; /* force the pipe off on setup_init_config */ if (HAS_PCH_SPLIT(dev)) { @@ -6286,7 +6317,9 @@ void intel_enable_clock_gating(struct drm_device *dev) if (IS_GEN5(dev)) { /* Required for FBC */ - dspclk_gate |= DPFDUNIT_CLOCK_GATE_DISABLE; + dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE | + DPFCRUNIT_CLOCK_GATE_DISABLE | + DPFDUNIT_CLOCK_GATE_DISABLE; /* Required for CxSR */ dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE; @@ -6429,52 +6462,60 @@ void intel_enable_clock_gating(struct drm_device *dev) } } -void intel_disable_clock_gating(struct drm_device *dev) +static void ironlake_teardown_rc6(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; if (dev_priv->renderctx) { - struct drm_i915_gem_object *obj = dev_priv->renderctx; - - I915_WRITE(CCID, 0); - POSTING_READ(CCID); - - i915_gem_object_unpin(obj); - drm_gem_object_unreference(&obj->base); + i915_gem_object_unpin(dev_priv->renderctx); + drm_gem_object_unreference(&dev_priv->renderctx->base); dev_priv->renderctx = NULL; } if (dev_priv->pwrctx) { - struct drm_i915_gem_object *obj = dev_priv->pwrctx; + i915_gem_object_unpin(dev_priv->pwrctx); + drm_gem_object_unreference(&dev_priv->pwrctx->base); + dev_priv->pwrctx = NULL; + } +} + +static void ironlake_disable_rc6(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (I915_READ(PWRCTXA)) { + /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */ + I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT); + wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON), + 50); I915_WRITE(PWRCTXA, 0); POSTING_READ(PWRCTXA); - i915_gem_object_unpin(obj); - drm_gem_object_unreference(&obj->base); - dev_priv->pwrctx = NULL; + I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); + POSTING_READ(RSTDBYCTL); } + + ironlake_disable_rc6(dev); } -static void ironlake_disable_rc6(struct drm_device *dev) +static int ironlake_setup_rc6(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */ - I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT); - wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON), - 10); - POSTING_READ(CCID); - I915_WRITE(PWRCTXA, 0); - POSTING_READ(PWRCTXA); - I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); - POSTING_READ(RSTDBYCTL); - i915_gem_object_unpin(dev_priv->renderctx); - drm_gem_object_unreference(&dev_priv->renderctx->base); - dev_priv->renderctx = NULL; - i915_gem_object_unpin(dev_priv->pwrctx); - drm_gem_object_unreference(&dev_priv->pwrctx->base); - dev_priv->pwrctx = NULL; + if (dev_priv->renderctx == NULL) + dev_priv->renderctx = intel_alloc_context_page(dev); + if (!dev_priv->renderctx) + return -ENOMEM; + + if (dev_priv->pwrctx == NULL) + dev_priv->pwrctx = intel_alloc_context_page(dev); + if (!dev_priv->pwrctx) { + ironlake_teardown_rc6(dev); + return -ENOMEM; + } + + return 0; } void ironlake_enable_rc6(struct drm_device *dev) @@ -6482,15 +6523,26 @@ void ironlake_enable_rc6(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int ret; + /* rc6 disabled by default due to repeated reports of hanging during + * boot and resume. + */ + if (!i915_enable_rc6) + return; + + ret = ironlake_setup_rc6(dev); + if (ret) + return; + /* * GPU can automatically power down the render unit if given a page * to save state. */ ret = BEGIN_LP_RING(6); if (ret) { - ironlake_disable_rc6(dev); + ironlake_teardown_rc6(dev); return; } + OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN); OUT_RING(MI_SET_CONTEXT); OUT_RING(dev_priv->renderctx->gtt_offset | @@ -6507,6 +6559,7 @@ void ironlake_enable_rc6(struct drm_device *dev) I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); } + /* Set up chip specific display functions */ static void intel_init_display(struct drm_device *dev) { @@ -6749,21 +6802,9 @@ void intel_modeset_init(struct drm_device *dev) if (IS_GEN6(dev)) gen6_enable_rps(dev_priv); - if (IS_IRONLAKE_M(dev)) { - dev_priv->renderctx = intel_alloc_context_page(dev); - if (!dev_priv->renderctx) - goto skip_rc6; - dev_priv->pwrctx = intel_alloc_context_page(dev); - if (!dev_priv->pwrctx) { - i915_gem_object_unpin(dev_priv->renderctx); - drm_gem_object_unreference(&dev_priv->renderctx->base); - dev_priv->renderctx = NULL; - goto skip_rc6; - } + if (IS_IRONLAKE_M(dev)) ironlake_enable_rc6(dev); - } -skip_rc6: INIT_WORK(&dev_priv->idle_work, intel_idle_update); setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, (unsigned long)dev); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1f4242b682c8..51cb4e36997f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1639,6 +1639,24 @@ static int intel_dp_get_modes(struct drm_connector *connector) return 0; } +static bool +intel_dp_detect_audio(struct drm_connector *connector) +{ + struct intel_dp *intel_dp = intel_attached_dp(connector); + struct edid *edid; + bool has_audio = false; + + edid = drm_get_edid(connector, &intel_dp->adapter); + if (edid) { + has_audio = drm_detect_monitor_audio(edid); + + connector->display_info.raw_edid = NULL; + kfree(edid); + } + + return has_audio; +} + static int intel_dp_set_property(struct drm_connector *connector, struct drm_property *property, @@ -1652,17 +1670,23 @@ intel_dp_set_property(struct drm_connector *connector, return ret; if (property == intel_dp->force_audio_property) { - if (val == intel_dp->force_audio) + int i = val; + bool has_audio; + + if (i == intel_dp->force_audio) return 0; - intel_dp->force_audio = val; + intel_dp->force_audio = i; - if (val > 0 && intel_dp->has_audio) - return 0; - if (val < 0 && !intel_dp->has_audio) + if (i == 0) + has_audio = intel_dp_detect_audio(connector); + else + has_audio = i > 0; + + if (has_audio == intel_dp->has_audio) return 0; - intel_dp->has_audio = val > 0; + intel_dp->has_audio = has_audio; goto done; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 74db2557d644..2c431049963c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -298,7 +298,6 @@ extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, int regno); extern void intel_enable_clock_gating(struct drm_device *dev); -extern void intel_disable_clock_gating(struct drm_device *dev); extern void ironlake_enable_drps(struct drm_device *dev); extern void ironlake_disable_drps(struct drm_device *dev); extern void gen6_enable_rps(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 0d0273e7b029..c635c9e357b9 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -251,6 +251,27 @@ static int intel_hdmi_get_modes(struct drm_connector *connector) &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter); } +static bool +intel_hdmi_detect_audio(struct drm_connector *connector) +{ + struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); + struct drm_i915_private *dev_priv = connector->dev->dev_private; + struct edid *edid; + bool has_audio = false; + + edid = drm_get_edid(connector, + &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter); + if (edid) { + if (edid->input & DRM_EDID_INPUT_DIGITAL) + has_audio = drm_detect_monitor_audio(edid); + + connector->display_info.raw_edid = NULL; + kfree(edid); + } + + return has_audio; +} + static int intel_hdmi_set_property(struct drm_connector *connector, struct drm_property *property, @@ -264,17 +285,23 @@ intel_hdmi_set_property(struct drm_connector *connector, return ret; if (property == intel_hdmi->force_audio_property) { - if (val == intel_hdmi->force_audio) + int i = val; + bool has_audio; + + if (i == intel_hdmi->force_audio) return 0; - intel_hdmi->force_audio = val; + intel_hdmi->force_audio = i; - if (val > 0 && intel_hdmi->has_audio) - return 0; - if (val < 0 && !intel_hdmi->has_audio) + if (i == 0) + has_audio = intel_hdmi_detect_audio(connector); + else + has_audio = i > 0; + + if (has_audio == intel_hdmi->has_audio) return 0; - intel_hdmi->has_audio = val > 0; + intel_hdmi->has_audio = has_audio; goto done; } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index ace8d5d30dd2..bcdba7bd5cfa 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -261,12 +261,6 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, return true; } - /* Make sure pre-965s set dither correctly */ - if (INTEL_INFO(dev)->gen < 4) { - if (dev_priv->lvds_dither) - pfit_control |= PANEL_8TO6_DITHER_ENABLE; - } - /* Native modes don't need fitting */ if (adjusted_mode->hdisplay == mode->hdisplay && adjusted_mode->vdisplay == mode->vdisplay) @@ -374,10 +368,16 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, } out: + /* If not enabling scaling, be consistent and always use 0. */ if ((pfit_control & PFIT_ENABLE) == 0) { pfit_control = 0; pfit_pgm_ratios = 0; } + + /* Make sure pre-965 set dither correctly */ + if (INTEL_INFO(dev)->gen < 4 && dev_priv->lvds_dither) + pfit_control |= PANEL_8TO6_DITHER_ENABLE; + if (pfit_control != intel_lvds->pfit_control || pfit_pgm_ratios != intel_lvds->pfit_pgm_ratios) { intel_lvds->pfit_control = pfit_control; diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index f295a7aaadf9..64fd64443ca6 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -26,6 +26,7 @@ */ #include <linux/acpi.h> +#include <linux/acpi_io.h> #include <acpi/video.h> #include "drmP.h" @@ -476,7 +477,7 @@ int intel_opregion_setup(struct drm_device *dev) return -ENOTSUPP; } - base = ioremap(asls, OPREGION_SIZE); + base = acpi_os_ioremap(asls, OPREGION_SIZE); if (!base) return -ENOMEM; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index f6b9baa6a63d..445f27efe677 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -34,6 +34,14 @@ #include "i915_trace.h" #include "intel_drv.h" +static inline int ring_space(struct intel_ring_buffer *ring) +{ + int space = (ring->head & HEAD_ADDR) - (ring->tail + 8); + if (space < 0) + space += ring->size; + return space; +} + static u32 i915_gem_get_seqno(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -204,11 +212,9 @@ static int init_ring_common(struct intel_ring_buffer *ring) if (!drm_core_check_feature(ring->dev, DRIVER_MODESET)) i915_kernel_lost_context(ring->dev); else { - ring->head = I915_READ_HEAD(ring) & HEAD_ADDR; + ring->head = I915_READ_HEAD(ring); ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR; - ring->space = ring->head - (ring->tail + 8); - if (ring->space < 0) - ring->space += ring->size; + ring->space = ring_space(ring); } return 0; @@ -921,32 +927,34 @@ static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring) } ring->tail = 0; - ring->space = ring->head - 8; + ring->space = ring_space(ring); return 0; } int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) { - int reread = 0; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; unsigned long end; u32 head; + /* If the reported head position has wrapped or hasn't advanced, + * fallback to the slow and accurate path. + */ + head = intel_read_status_page(ring, 4); + if (head > ring->head) { + ring->head = head; + ring->space = ring_space(ring); + if (ring->space >= n) + return 0; + } + trace_i915_ring_wait_begin (dev); end = jiffies + 3 * HZ; do { - /* If the reported head position has wrapped or hasn't advanced, - * fallback to the slow and accurate path. - */ - head = intel_read_status_page(ring, 4); - if (reread) - head = I915_READ_HEAD(ring); - ring->head = head & HEAD_ADDR; - ring->space = ring->head - (ring->tail + 8); - if (ring->space < 0) - ring->space += ring->size; + ring->head = I915_READ_HEAD(ring); + ring->space = ring_space(ring); if (ring->space >= n) { trace_i915_ring_wait_end(dev); return 0; @@ -961,7 +969,6 @@ int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) msleep(1); if (atomic_read(&dev_priv->mm.wedged)) return -EAGAIN; - reread = 1; } while (!time_after(jiffies, end)); trace_i915_ring_wait_end (dev); return -EBUSY; @@ -1052,22 +1059,25 @@ static void gen6_bsd_ring_write_tail(struct intel_ring_buffer *ring, } static int gen6_ring_flush(struct intel_ring_buffer *ring, - u32 invalidate_domains, - u32 flush_domains) + u32 invalidate, u32 flush) { + uint32_t cmd; int ret; - if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0) + if (((invalidate | flush) & I915_GEM_GPU_DOMAINS) == 0) return 0; ret = intel_ring_begin(ring, 4); if (ret) return ret; - intel_ring_emit(ring, MI_FLUSH_DW); - intel_ring_emit(ring, 0); + cmd = MI_FLUSH_DW; + if (invalidate & I915_GEM_GPU_DOMAINS) + cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD; + intel_ring_emit(ring, cmd); intel_ring_emit(ring, 0); intel_ring_emit(ring, 0); + intel_ring_emit(ring, MI_NOOP); intel_ring_advance(ring); return 0; } @@ -1223,22 +1233,25 @@ static int blt_ring_begin(struct intel_ring_buffer *ring, } static int blt_ring_flush(struct intel_ring_buffer *ring, - u32 invalidate_domains, - u32 flush_domains) + u32 invalidate, u32 flush) { + uint32_t cmd; int ret; - if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0) + if (((invalidate | flush) & I915_GEM_DOMAIN_RENDER) == 0) return 0; ret = blt_ring_begin(ring, 4); if (ret) return ret; - intel_ring_emit(ring, MI_FLUSH_DW); - intel_ring_emit(ring, 0); + cmd = MI_FLUSH_DW; + if (invalidate & I915_GEM_DOMAIN_RENDER) + cmd |= MI_INVALIDATE_TLB; + intel_ring_emit(ring, cmd); intel_ring_emit(ring, 0); intel_ring_emit(ring, 0); + intel_ring_emit(ring, MI_NOOP); intel_ring_advance(ring); return 0; } @@ -1292,6 +1305,48 @@ int intel_init_render_ring_buffer(struct drm_device *dev) return intel_init_ring_buffer(dev, ring); } +int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = &dev_priv->ring[RCS]; + + *ring = render_ring; + if (INTEL_INFO(dev)->gen >= 6) { + ring->add_request = gen6_add_request; + ring->irq_get = gen6_render_ring_get_irq; + ring->irq_put = gen6_render_ring_put_irq; + } else if (IS_GEN5(dev)) { + ring->add_request = pc_render_add_request; + ring->get_seqno = pc_render_get_seqno; + } + + ring->dev = dev; + INIT_LIST_HEAD(&ring->active_list); + INIT_LIST_HEAD(&ring->request_list); + INIT_LIST_HEAD(&ring->gpu_write_list); + + ring->size = size; + ring->effective_size = ring->size; + if (IS_I830(ring->dev)) + ring->effective_size -= 128; + + ring->map.offset = start; + ring->map.size = size; + ring->map.type = 0; + ring->map.flags = 0; + ring->map.mtrr = 0; + + drm_core_ioremap_wc(&ring->map, dev); + if (ring->map.handle == NULL) { + DRM_ERROR("can not ioremap virtual address for" + " ring buffer\n"); + return -ENOMEM; + } + + ring->virtual_start = (void __force __iomem *)ring->map.handle; + return 0; +} + int intel_init_bsd_ring_buffer(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 5b0abfa881fc..6d6fde85a636 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -166,4 +166,7 @@ int intel_init_blt_ring_buffer(struct drm_device *dev); u32 intel_ring_get_active_head(struct intel_ring_buffer *ring); void intel_ring_setup_status_page(struct intel_ring_buffer *ring); +/* DRI warts */ +int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size); + #endif /* _INTEL_RINGBUFFER_H_ */ diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 45cd37652a37..7c50cdce84f0 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -46,6 +46,7 @@ SDVO_TV_MASK) #define IS_TV(c) (c->output_flag & SDVO_TV_MASK) +#define IS_TMDS(c) (c->output_flag & SDVO_TMDS_MASK) #define IS_LVDS(c) (c->output_flag & SDVO_LVDS_MASK) #define IS_TV_OR_LVDS(c) (c->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK)) @@ -473,20 +474,6 @@ static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd, return false; } - i = 3; - while (status == SDVO_CMD_STATUS_PENDING && i--) { - if (!intel_sdvo_read_byte(intel_sdvo, - SDVO_I2C_CMD_STATUS, - &status)) - return false; - } - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("command returns response %s [%d]\n", - status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP ? cmd_status_names[status] : "???", - status); - return false; - } - return true; } @@ -497,6 +484,8 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, u8 status; int i; + DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo)); + /* * The documentation states that all commands will be * processed within 15µs, and that we need only poll @@ -505,14 +494,19 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, * * Check 5 times in case the hardware failed to read the docs. */ - do { + if (!intel_sdvo_read_byte(intel_sdvo, + SDVO_I2C_CMD_STATUS, + &status)) + goto log_fail; + + while (status == SDVO_CMD_STATUS_PENDING && retry--) { + udelay(15); if (!intel_sdvo_read_byte(intel_sdvo, SDVO_I2C_CMD_STATUS, &status)) - return false; - } while (status == SDVO_CMD_STATUS_PENDING && --retry); + goto log_fail; + } - DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo)); if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) DRM_LOG_KMS("(%s)", cmd_status_names[status]); else @@ -533,7 +527,7 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, return true; log_fail: - DRM_LOG_KMS("\n"); + DRM_LOG_KMS("... failed\n"); return false; } @@ -550,6 +544,7 @@ static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) static bool intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo, u8 ddc_bus) { + /* This must be the immediately preceding write before the i2c xfer */ return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &ddc_bus, 1); @@ -557,7 +552,10 @@ static bool intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo, static bool intel_sdvo_set_value(struct intel_sdvo *intel_sdvo, u8 cmd, const void *data, int len) { - return intel_sdvo_write_cmd(intel_sdvo, cmd, data, len); + if (!intel_sdvo_write_cmd(intel_sdvo, cmd, data, len)) + return false; + + return intel_sdvo_read_response(intel_sdvo, NULL, 0); } static bool @@ -859,18 +857,21 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) intel_dip_infoframe_csum(&avi_if); - if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX, + if (!intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_HBUF_INDEX, set_buf_index, 2)) return false; for (i = 0; i < sizeof(avi_if); i += 8) { - if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA, + if (!intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_HBUF_DATA, data, 8)) return false; data++; } - return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE, + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_HBUF_TXRATE, &tx_rate, 1); } @@ -1359,7 +1360,8 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid); intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid); } - } + } else + status = connector_status_disconnected; connector->display_info.raw_edid = NULL; kfree(edid); } @@ -1407,10 +1409,25 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) if ((intel_sdvo_connector->output_flag & response) == 0) ret = connector_status_disconnected; - else if (response & SDVO_TMDS_MASK) + else if (IS_TMDS(intel_sdvo_connector)) ret = intel_sdvo_hdmi_sink_detect(connector); - else - ret = connector_status_connected; + else { + struct edid *edid; + + /* if we have an edid check it matches the connection */ + edid = intel_sdvo_get_edid(connector); + if (edid == NULL) + edid = intel_sdvo_get_analog_edid(connector); + if (edid != NULL) { + if (edid->input & DRM_EDID_INPUT_DIGITAL) + ret = connector_status_disconnected; + else + ret = connector_status_connected; + connector->display_info.raw_edid = NULL; + kfree(edid); + } else + ret = connector_status_connected; + } /* May update encoder flag for like clock for SDVO TV, etc.*/ if (ret == connector_status_connected) { @@ -1446,10 +1463,15 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) edid = intel_sdvo_get_analog_edid(connector); if (edid != NULL) { - if (edid->input & DRM_EDID_INPUT_DIGITAL) { + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); + bool monitor_is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL); + bool connector_is_digital = !!IS_TMDS(intel_sdvo_connector); + + if (connector_is_digital == monitor_is_digital) { drm_mode_connector_update_edid_property(connector, edid); drm_add_edid_modes(connector, edid); } + connector->display_info.raw_edid = NULL; kfree(edid); } @@ -1668,6 +1690,22 @@ static void intel_sdvo_destroy(struct drm_connector *connector) kfree(connector); } +static bool intel_sdvo_detect_hdmi_audio(struct drm_connector *connector) +{ + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); + struct edid *edid; + bool has_audio = false; + + if (!intel_sdvo->is_hdmi) + return false; + + edid = intel_sdvo_get_edid(connector); + if (edid != NULL && edid->input & DRM_EDID_INPUT_DIGITAL) + has_audio = drm_detect_monitor_audio(edid); + + return has_audio; +} + static int intel_sdvo_set_property(struct drm_connector *connector, struct drm_property *property, @@ -1684,17 +1722,23 @@ intel_sdvo_set_property(struct drm_connector *connector, return ret; if (property == intel_sdvo_connector->force_audio_property) { - if (val == intel_sdvo_connector->force_audio) + int i = val; + bool has_audio; + + if (i == intel_sdvo_connector->force_audio) return 0; - intel_sdvo_connector->force_audio = val; + intel_sdvo_connector->force_audio = i; - if (val > 0 && intel_sdvo->has_hdmi_audio) - return 0; - if (val < 0 && !intel_sdvo->has_hdmi_audio) + if (i == 0) + has_audio = intel_sdvo_detect_hdmi_audio(connector); + else + has_audio = i > 0; + + if (has_audio == intel_sdvo->has_hdmi_audio) return 0; - intel_sdvo->has_hdmi_audio = val > 0; + intel_sdvo->has_hdmi_audio = has_audio; goto done; } diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 93206e4eaa6f..fe4a53a50b83 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1234,7 +1234,8 @@ static const struct drm_display_mode reported_modes[] = { * \return false if TV is disconnected. */ static int -intel_tv_detect_type (struct intel_tv *intel_tv) +intel_tv_detect_type (struct intel_tv *intel_tv, + struct drm_connector *connector) { struct drm_encoder *encoder = &intel_tv->base.base; struct drm_device *dev = encoder->dev; @@ -1245,11 +1246,13 @@ intel_tv_detect_type (struct intel_tv *intel_tv) int type; /* Disable TV interrupts around load detect or we'll recurse */ - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - i915_disable_pipestat(dev_priv, 0, - PIPE_HOTPLUG_INTERRUPT_ENABLE | - PIPE_HOTPLUG_TV_INTERRUPT_ENABLE); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + if (connector->polled & DRM_CONNECTOR_POLL_HPD) { + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + i915_disable_pipestat(dev_priv, 0, + PIPE_HOTPLUG_INTERRUPT_ENABLE | + PIPE_HOTPLUG_TV_INTERRUPT_ENABLE); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + } save_tv_dac = tv_dac = I915_READ(TV_DAC); save_tv_ctl = tv_ctl = I915_READ(TV_CTL); @@ -1302,11 +1305,13 @@ intel_tv_detect_type (struct intel_tv *intel_tv) I915_WRITE(TV_CTL, save_tv_ctl); /* Restore interrupt config */ - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - i915_enable_pipestat(dev_priv, 0, - PIPE_HOTPLUG_INTERRUPT_ENABLE | - PIPE_HOTPLUG_TV_INTERRUPT_ENABLE); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + if (connector->polled & DRM_CONNECTOR_POLL_HPD) { + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + i915_enable_pipestat(dev_priv, 0, + PIPE_HOTPLUG_INTERRUPT_ENABLE | + PIPE_HOTPLUG_TV_INTERRUPT_ENABLE); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + } return type; } @@ -1356,7 +1361,7 @@ intel_tv_detect(struct drm_connector *connector, bool force) drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V); if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) { - type = intel_tv_detect_type(intel_tv); + type = intel_tv_detect_type(intel_tv, connector); } else if (force) { struct drm_crtc *crtc; int dpms_mode; @@ -1364,7 +1369,7 @@ intel_tv_detect(struct drm_connector *connector, bool force) crtc = intel_get_load_detect_pipe(&intel_tv->base, connector, &mode, &dpms_mode); if (crtc) { - type = intel_tv_detect_type(intel_tv); + type = intel_tv_detect_type(intel_tv, connector); intel_release_load_detect_pipe(&intel_tv->base, connector, dpms_mode); } else @@ -1658,6 +1663,18 @@ intel_tv_init(struct drm_device *dev) intel_encoder = &intel_tv->base; connector = &intel_connector->base; + /* The documentation, for the older chipsets at least, recommend + * using a polling method rather than hotplug detection for TVs. + * This is because in order to perform the hotplug detection, the PLLs + * for the TV must be kept alive increasing power drain and starving + * bandwidth from other encoders. Notably for instance, it causes + * pipe underruns on Crestline when this encoder is supposedly idle. + * + * More recent chipsets favour HDMI rather than integrated S-Video. + */ + connector->polled = + DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + drm_connector_init(dev, connector, &intel_tv_connector_funcs, DRM_MODE_CONNECTOR_SVIDEO); diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 2aef5cd3acf5..6bdab891c64e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -6228,7 +6228,7 @@ parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb, entry->tvconf.has_component_output = false; break; case OUTPUT_LVDS: - if ((conn & 0x00003f00) != 0x10) + if ((conn & 0x00003f00) >> 8 != 0x10) entry->lvdsconf.use_straps_for_mode = true; entry->lvdsconf.use_power_scripts = true; break; @@ -6310,6 +6310,9 @@ void merge_like_dcb_entries(struct drm_device *dev, struct dcb_table *dcb) static bool apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf) { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct dcb_table *dcb = &dev_priv->vbios.dcb; + /* Dell Precision M6300 * DCB entry 2: 02025312 00000010 * DCB entry 3: 02026312 00000020 @@ -6327,6 +6330,18 @@ apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf) return false; } + /* GeForce3 Ti 200 + * + * DCB reports an LVDS output that should be TMDS: + * DCB entry 1: f2005014 ffffffff + */ + if (nv_match_device(dev, 0x0201, 0x1462, 0x8851)) { + if (*conn == 0xf2005014 && *conf == 0xffffffff) { + fabricate_dcb_output(dcb, OUTPUT_TMDS, 1, 1, 1); + return false; + } + } + return true; } diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index a7fae26f4654..d38a4d9f9b0b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -128,6 +128,7 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, } } + nvbo->bo.mem.num_pages = size >> PAGE_SHIFT; nouveau_bo_placement_set(nvbo, flags, 0); nvbo->channel = chan; @@ -166,17 +167,17 @@ static void set_placement_range(struct nouveau_bo *nvbo, uint32_t type) { struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev); + int vram_pages = dev_priv->vram_size >> PAGE_SHIFT; if (dev_priv->card_type == NV_10 && - nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM)) { + nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM) && + nvbo->bo.mem.num_pages < vram_pages / 2) { /* * Make sure that the color and depth buffers are handled * by independent memory controller units. Up to a 9x * speed up when alpha-blending and depth-test are enabled * at the same time. */ - int vram_pages = dev_priv->vram_size >> PAGE_SHIFT; - if (nvbo->tile_flags & NOUVEAU_GEM_TILE_ZETA) { nvbo->placement.fpfn = vram_pages / 2; nvbo->placement.lpfn = ~0; @@ -785,7 +786,7 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr, if (ret) goto out; - ret = ttm_bo_move_ttm(bo, evict, no_wait_reserve, no_wait_gpu, new_mem); + ret = ttm_bo_move_ttm(bo, true, no_wait_reserve, no_wait_gpu, new_mem); out: ttm_bo_mem_put(bo, &tmp_mem); return ret; @@ -811,11 +812,11 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr, if (ret) return ret; - ret = ttm_bo_move_ttm(bo, evict, no_wait_reserve, no_wait_gpu, &tmp_mem); + ret = ttm_bo_move_ttm(bo, true, no_wait_reserve, no_wait_gpu, &tmp_mem); if (ret) goto out; - ret = nouveau_bo_move_m2mf(bo, evict, intr, no_wait_reserve, no_wait_gpu, new_mem); + ret = nouveau_bo_move_m2mf(bo, true, intr, no_wait_reserve, no_wait_gpu, new_mem); if (ret) goto out; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index a21e00076839..390d82c3c4b0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -507,6 +507,7 @@ nouveau_connector_native_mode(struct drm_connector *connector) int high_w = 0, high_h = 0, high_v = 0; list_for_each_entry(mode, &nv_connector->base.probed_modes, head) { + mode->vrefresh = drm_mode_vrefresh(mode); if (helper->mode_valid(connector, mode) != MODE_OK || (mode->flags & DRM_MODE_FLAG_INTERLACE)) continue; diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index 13bb672a16f4..f658a04eecf9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -234,9 +234,9 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) pci_set_power_state(pdev, PCI_D3hot); } - acquire_console_sem(); + console_lock(); nouveau_fbcon_set_suspend(dev, 1); - release_console_sem(); + console_unlock(); nouveau_fbcon_restore_accel(dev); return 0; @@ -359,9 +359,9 @@ nouveau_pci_resume(struct pci_dev *pdev) nv_crtc->lut.depth = 0; } - acquire_console_sem(); + console_lock(); nouveau_fbcon_set_suspend(dev, 0); - release_console_sem(); + console_unlock(); nouveau_fbcon_zfill_all(dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 01bffc4412d2..9821fcacc3d2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -848,9 +848,6 @@ extern void nv10_mem_put_tile_region(struct drm_device *dev, struct nouveau_fence *fence); extern const struct ttm_mem_type_manager_func nouveau_vram_manager; -/* nvc0_vram.c */ -extern const struct ttm_mem_type_manager_func nvc0_vram_manager; - /* nouveau_notifier.c */ extern int nouveau_notifier_init_channel(struct nouveau_channel *); extern void nouveau_notifier_takedown_channel(struct nouveau_channel *); diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index fb846a3fef15..4399e2f34db4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -443,7 +443,7 @@ nouveau_hwmon_fini(struct drm_device *dev) struct nouveau_pm_engine *pm = &dev_priv->engine.pm; if (pm->hwmon) { - sysfs_remove_group(&pm->hwmon->kobj, &hwmon_attrgroup); + sysfs_remove_group(&dev->pdev->dev.kobj, &hwmon_attrgroup); hwmon_device_unregister(pm->hwmon); } #endif @@ -543,7 +543,7 @@ nouveau_pm_resume(struct drm_device *dev) struct nouveau_pm_engine *pm = &dev_priv->engine.pm; struct nouveau_pm_level *perflvl; - if (pm->cur == &pm->boot) + if (!pm->cur || pm->cur == &pm->boot) return; perflvl = pm->cur; diff --git a/drivers/gpu/drm/nouveau/nouveau_temp.c b/drivers/gpu/drm/nouveau/nouveau_temp.c index 7ecc4adc1e45..8d9968e1cba8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_temp.c +++ b/drivers/gpu/drm/nouveau/nouveau_temp.c @@ -265,8 +265,8 @@ nouveau_temp_probe_i2c(struct drm_device *dev) struct i2c_board_info info[] = { { I2C_BOARD_INFO("w83l785ts", 0x2d) }, { I2C_BOARD_INFO("w83781d", 0x2d) }, - { I2C_BOARD_INFO("f75375", 0x2e) }, { I2C_BOARD_INFO("adt7473", 0x2e) }, + { I2C_BOARD_INFO("f75375", 0x2e) }, { I2C_BOARD_INFO("lm99", 0x4c) }, { } }; diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index ef23550407b5..c82db37d9f41 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c @@ -342,8 +342,8 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder, if (nv_encoder->dcb->type == OUTPUT_LVDS) { bool duallink, dummy; - nouveau_bios_parse_lvds_table(dev, nv_connector->native_mode-> - clock, &duallink, &dummy); + nouveau_bios_parse_lvds_table(dev, output_mode->clock, + &duallink, &dummy); if (duallink) regp->fp_control |= (8 << 28); } else @@ -518,8 +518,6 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode) return; if (nv_encoder->dcb->lvdsconf.use_power_scripts) { - struct nouveau_connector *nv_connector = nouveau_encoder_connector_get(nv_encoder); - /* when removing an output, crtc may not be set, but PANEL_OFF * must still be run */ @@ -527,12 +525,8 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode) nv04_dfp_get_bound_head(dev, nv_encoder->dcb); if (mode == DRM_MODE_DPMS_ON) { - if (!nv_connector->native_mode) { - NV_ERROR(dev, "Not turning on LVDS without native mode\n"); - return; - } call_lvds_script(dev, nv_encoder->dcb, head, - LVDS_PANEL_ON, nv_connector->native_mode->clock); + LVDS_PANEL_ON, nv_encoder->mode.clock); } else /* pxclk of 0 is fine for PANEL_OFF, and for a * disconnected LVDS encoder there is no native_mode diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c index 8870d72388c8..18d30c2c1aa6 100644 --- a/drivers/gpu/drm/nouveau/nv40_graph.c +++ b/drivers/gpu/drm/nouveau/nv40_graph.c @@ -211,18 +211,32 @@ nv40_graph_set_tile_region(struct drm_device *dev, int i) struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; switch (dev_priv->chipset) { + case 0x40: + case 0x41: /* guess */ + case 0x42: + case 0x43: + case 0x45: /* guess */ + case 0x4e: + nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch); + nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit); + nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr); + nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch); + nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit); + nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr); + break; case 0x44: case 0x4a: - case 0x4e: nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch); nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit); nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr); break; - case 0x46: case 0x47: case 0x49: case 0x4b: + case 0x4c: + case 0x67: + default: nv_wr32(dev, NV47_PGRAPH_TSIZE(i), tile->pitch); nv_wr32(dev, NV47_PGRAPH_TLIMIT(i), tile->limit); nv_wr32(dev, NV47_PGRAPH_TILE(i), tile->addr); @@ -230,15 +244,6 @@ nv40_graph_set_tile_region(struct drm_device *dev, int i) nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit); nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr); break; - - default: - nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch); - nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit); - nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr); - nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch); - nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit); - nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr); - break; } } @@ -396,17 +401,20 @@ nv40_graph_init(struct drm_device *dev) break; default: switch (dev_priv->chipset) { - case 0x46: - case 0x47: - case 0x49: - case 0x4b: - nv_wr32(dev, 0x400DF0, nv_rd32(dev, NV04_PFB_CFG0)); - nv_wr32(dev, 0x400DF4, nv_rd32(dev, NV04_PFB_CFG1)); - break; - default: + case 0x41: + case 0x42: + case 0x43: + case 0x45: + case 0x4e: + case 0x44: + case 0x4a: nv_wr32(dev, 0x4009F0, nv_rd32(dev, NV04_PFB_CFG0)); nv_wr32(dev, 0x4009F4, nv_rd32(dev, NV04_PFB_CFG1)); break; + default: + nv_wr32(dev, 0x400DF0, nv_rd32(dev, NV04_PFB_CFG0)); + nv_wr32(dev, 0x400DF4, nv_rd32(dev, NV04_PFB_CFG1)); + break; } nv_wr32(dev, 0x4069F0, nv_rd32(dev, NV04_PFB_CFG0)); nv_wr32(dev, 0x4069F4, nv_rd32(dev, NV04_PFB_CFG1)); diff --git a/drivers/gpu/drm/nouveau/nv50_evo.c b/drivers/gpu/drm/nouveau/nv50_evo.c index 14e24e906ee8..0ea090f4244a 100644 --- a/drivers/gpu/drm/nouveau/nv50_evo.c +++ b/drivers/gpu/drm/nouveau/nv50_evo.c @@ -283,8 +283,7 @@ nv50_evo_create(struct drm_device *dev) nv50_evo_channel_del(&dev_priv->evo); return ret; } - } else - if (dev_priv->chipset != 0x50) { + } else { ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoFB16, 0x70, 0x19, 0, 0xffffffff, 0x00010000); if (ret) { diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index 2d7ea75a09d4..37e21d2be95b 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -256,6 +256,7 @@ nv50_graph_destroy_context(struct nouveau_channel *chan) struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20; unsigned long flags; @@ -265,6 +266,7 @@ nv50_graph_destroy_context(struct nouveau_channel *chan) return; spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + pfifo->reassign(dev, false); pgraph->fifo_access(dev, false); if (pgraph->channel(dev) == chan) @@ -275,6 +277,7 @@ nv50_graph_destroy_context(struct nouveau_channel *chan) dev_priv->engine.instmem.flush(dev); pgraph->fifo_access(dev, true); + pfifo->reassign(dev, true); spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); nouveau_gpuobj_ref(NULL, &chan->ramin_grctx); diff --git a/drivers/gpu/drm/nouveau/nv50_vm.c b/drivers/gpu/drm/nouveau/nv50_vm.c index 38e523e10995..459ff08241e5 100644 --- a/drivers/gpu/drm/nouveau/nv50_vm.c +++ b/drivers/gpu/drm/nouveau/nv50_vm.c @@ -45,11 +45,6 @@ nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde, } if (phys & 1) { - if (dev_priv->vram_sys_base) { - phys += dev_priv->vram_sys_base; - phys |= 0x30; - } - if (coverage <= 32 * 1024 * 1024) phys |= 0x60; else if (coverage <= 64 * 1024 * 1024) diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c index e6ea7d83187f..eb18a7e89f5b 100644 --- a/drivers/gpu/drm/nouveau/nvc0_graph.c +++ b/drivers/gpu/drm/nouveau/nvc0_graph.c @@ -31,6 +31,7 @@ #include "nvc0_graph.h" static void nvc0_graph_isr(struct drm_device *); +static void nvc0_runk140_isr(struct drm_device *); static int nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan); void @@ -281,6 +282,7 @@ nvc0_graph_destroy(struct drm_device *dev) return; nouveau_irq_unregister(dev, 12); + nouveau_irq_unregister(dev, 25); nouveau_gpuobj_ref(NULL, &priv->unk4188b8); nouveau_gpuobj_ref(NULL, &priv->unk4188b4); @@ -390,6 +392,7 @@ nvc0_graph_create(struct drm_device *dev) } nouveau_irq_register(dev, 12, nvc0_graph_isr); + nouveau_irq_register(dev, 25, nvc0_runk140_isr); NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */ NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */ NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */ @@ -512,8 +515,8 @@ nvc0_graph_init_gpc_1(struct drm_device *dev) nv_wr32(dev, TP_UNIT(gpc, tp, 0x224), 0xc0000000); nv_wr32(dev, TP_UNIT(gpc, tp, 0x48c), 0xc0000000); nv_wr32(dev, TP_UNIT(gpc, tp, 0x084), 0xc0000000); - nv_wr32(dev, TP_UNIT(gpc, tp, 0xe44), 0x001ffffe); - nv_wr32(dev, TP_UNIT(gpc, tp, 0xe4c), 0x0000000f); + nv_wr32(dev, TP_UNIT(gpc, tp, 0x644), 0x001ffffe); + nv_wr32(dev, TP_UNIT(gpc, tp, 0x64c), 0x0000000f); } nv_wr32(dev, GPC_UNIT(gpc, 0x2c90), 0xffffffff); nv_wr32(dev, GPC_UNIT(gpc, 0x2c94), 0xffffffff); @@ -777,3 +780,19 @@ nvc0_graph_isr(struct drm_device *dev) nv_wr32(dev, 0x400500, 0x00010001); } + +static void +nvc0_runk140_isr(struct drm_device *dev) +{ + u32 units = nv_rd32(dev, 0x00017c) & 0x1f; + + while (units) { + u32 unit = ffs(units) - 1; + u32 reg = 0x140000 + unit * 0x2000; + u32 st0 = nv_mask(dev, reg + 0x1020, 0, 0); + u32 st1 = nv_mask(dev, reg + 0x1420, 0, 0); + + NV_INFO(dev, "PRUNK140: %d 0x%08x 0x%08x\n", unit, st0, st1); + units &= ~(1 << unit); + } +} diff --git a/drivers/gpu/drm/nouveau/nvc0_grctx.c b/drivers/gpu/drm/nouveau/nvc0_grctx.c index b9e68b2d30aa..f880ff776db8 100644 --- a/drivers/gpu/drm/nouveau/nvc0_grctx.c +++ b/drivers/gpu/drm/nouveau/nvc0_grctx.c @@ -1830,7 +1830,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan) for (tp = 0, id = 0; tp < 4; tp++) { for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - if (tp <= priv->tp_nr[gpc]) { + if (tp < priv->tp_nr[gpc]) { nv_wr32(dev, TP_UNIT(gpc, tp, 0x698), id); nv_wr32(dev, TP_UNIT(gpc, tp, 0x4e8), id); nv_wr32(dev, GPC_UNIT(gpc, 0x0c10 + tp * 4), id); diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index b0ab185b86f6..a4e5e53e0a62 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -48,29 +48,29 @@ static void atombios_overscan_setup(struct drm_crtc *crtc, switch (radeon_crtc->rmx_type) { case RMX_CENTER: - args.usOverscanTop = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2; - args.usOverscanBottom = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2; - args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2; - args.usOverscanRight = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2; + args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2); + args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2); + args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2); + args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2); break; case RMX_ASPECT: a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay; a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay; if (a1 > a2) { - args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2; - args.usOverscanRight = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2; + args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2); + args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2); } else if (a2 > a1) { - args.usOverscanLeft = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2; - args.usOverscanRight = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2; + args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2); + args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2); } break; case RMX_FULL: default: - args.usOverscanRight = radeon_crtc->h_border; - args.usOverscanLeft = radeon_crtc->h_border; - args.usOverscanBottom = radeon_crtc->v_border; - args.usOverscanTop = radeon_crtc->v_border; + args.usOverscanRight = cpu_to_le16(radeon_crtc->h_border); + args.usOverscanLeft = cpu_to_le16(radeon_crtc->h_border); + args.usOverscanBottom = cpu_to_le16(radeon_crtc->v_border); + args.usOverscanTop = cpu_to_le16(radeon_crtc->v_border); break; } atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); @@ -419,23 +419,23 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc, memset(&args, 0, sizeof(args)); if (ASIC_IS_DCE5(rdev)) { - args.v3.usSpreadSpectrumAmountFrac = 0; + args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0); args.v3.ucSpreadSpectrumType = ss->type; switch (pll_id) { case ATOM_PPLL1: args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL; - args.v3.usSpreadSpectrumAmount = ss->amount; - args.v3.usSpreadSpectrumStep = ss->step; + args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); + args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step); break; case ATOM_PPLL2: args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL; - args.v3.usSpreadSpectrumAmount = ss->amount; - args.v3.usSpreadSpectrumStep = ss->step; + args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); + args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step); break; case ATOM_DCPLL: args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL; - args.v3.usSpreadSpectrumAmount = 0; - args.v3.usSpreadSpectrumStep = 0; + args.v3.usSpreadSpectrumAmount = cpu_to_le16(0); + args.v3.usSpreadSpectrumStep = cpu_to_le16(0); break; case ATOM_PPLL_INVALID: return; @@ -447,18 +447,18 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc, switch (pll_id) { case ATOM_PPLL1: args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL; - args.v2.usSpreadSpectrumAmount = ss->amount; - args.v2.usSpreadSpectrumStep = ss->step; + args.v2.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); + args.v2.usSpreadSpectrumStep = cpu_to_le16(ss->step); break; case ATOM_PPLL2: args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P2PLL; - args.v2.usSpreadSpectrumAmount = ss->amount; - args.v2.usSpreadSpectrumStep = ss->step; + args.v2.usSpreadSpectrumAmount = cpu_to_le16(ss->amount); + args.v2.usSpreadSpectrumStep = cpu_to_le16(ss->step); break; case ATOM_DCPLL: args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_DCPLL; - args.v2.usSpreadSpectrumAmount = 0; - args.v2.usSpreadSpectrumStep = 0; + args.v2.usSpreadSpectrumAmount = cpu_to_le16(0); + args.v2.usSpreadSpectrumStep = cpu_to_le16(0); break; case ATOM_PPLL_INVALID: return; @@ -538,7 +538,6 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; else pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; - } list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { @@ -555,23 +554,28 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, dp_clock = dig_connector->dp_clock; } } -#if 0 /* doesn't work properly on some laptops */ + /* use recommended ref_div for ss */ if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { if (ss_enabled) { if (ss->refdiv) { + pll->flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; pll->flags |= RADEON_PLL_USE_REF_DIV; pll->reference_div = ss->refdiv; + if (ASIC_IS_AVIVO(rdev)) + pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; } } } -#endif + if (ASIC_IS_AVIVO(rdev)) { /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) adjusted_clock = mode->clock * 2; if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + pll->flags |= RADEON_PLL_IS_LCD; } else { if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) pll->flags |= RADEON_PLL_NO_ODD_POST_DIV; @@ -606,14 +610,9 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); args.v1.ucTransmitterID = radeon_encoder->encoder_id; args.v1.ucEncodeMode = encoder_mode; - if (encoder_mode == ATOM_ENCODER_MODE_DP) { - if (ss_enabled) - args.v1.ucConfig |= - ADJUST_DISPLAY_CONFIG_SS_ENABLE; - } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) { + if (ss_enabled) args.v1.ucConfig |= ADJUST_DISPLAY_CONFIG_SS_ENABLE; - } atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); @@ -624,12 +623,12 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id; args.v3.sInput.ucEncodeMode = encoder_mode; args.v3.sInput.ucDispPllConfig = 0; + if (ss_enabled) + args.v3.sInput.ucDispPllConfig |= + DISPPLL_CONFIG_SS_ENABLE; if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; if (encoder_mode == ATOM_ENCODER_MODE_DP) { - if (ss_enabled) - args.v3.sInput.ucDispPllConfig |= - DISPPLL_CONFIG_SS_ENABLE; args.v3.sInput.ucDispPllConfig |= DISPPLL_CONFIG_COHERENT_MODE; /* 16200 or 27000 */ @@ -649,18 +648,11 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, } } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { if (encoder_mode == ATOM_ENCODER_MODE_DP) { - if (ss_enabled) - args.v3.sInput.ucDispPllConfig |= - DISPPLL_CONFIG_SS_ENABLE; args.v3.sInput.ucDispPllConfig |= DISPPLL_CONFIG_COHERENT_MODE; /* 16200 or 27000 */ args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); - } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) { - if (ss_enabled) - args.v3.sInput.ucDispPllConfig |= - DISPPLL_CONFIG_SS_ENABLE; - } else { + } else if (encoder_mode != ATOM_ENCODER_MODE_LVDS) { if (mode->clock > 165000) args.v3.sInput.ucDispPllConfig |= DISPPLL_CONFIG_DUAL_LINK; @@ -670,10 +662,12 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, index, (uint32_t *)&args); adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10; if (args.v3.sOutput.ucRefDiv) { + pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; pll->flags |= RADEON_PLL_USE_REF_DIV; pll->reference_div = args.v3.sOutput.ucRefDiv; } if (args.v3.sOutput.ucPostDiv) { + pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; pll->flags |= RADEON_PLL_USE_POST_DIV; pll->post_div = args.v3.sOutput.ucPostDiv; } @@ -727,14 +721,14 @@ static void atombios_crtc_set_dcpll(struct drm_crtc *crtc, * SetPixelClock provides the dividers */ args.v5.ucCRTC = ATOM_CRTC_INVALID; - args.v5.usPixelClock = dispclk; + args.v5.usPixelClock = cpu_to_le16(dispclk); args.v5.ucPpll = ATOM_DCPLL; break; case 6: /* if the default dcpll clock is specified, * SetPixelClock provides the dividers */ - args.v6.ulDispEngClkFreq = dispclk; + args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk); args.v6.ucPpll = ATOM_DCPLL; break; default: @@ -963,8 +957,12 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode /* adjust pixel clock as needed */ adjusted_clock = atombios_adjust_pll(crtc, mode, pll, ss_enabled, &ss); - radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, - &ref_div, &post_div); + if (ASIC_IS_AVIVO(rdev)) + radeon_compute_pll_avivo(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, + &ref_div, &post_div); + else + radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, + &ref_div, &post_div); atombios_crtc_program_ss(crtc, ATOM_DISABLE, radeon_crtc->pll_id, &ss); @@ -993,9 +991,9 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode } } -static int evergreen_crtc_do_set_base(struct drm_crtc *crtc, - struct drm_framebuffer *fb, - int x, int y, int atomic) +static int dce4_crtc_do_set_base(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int x, int y, int atomic) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; @@ -1006,6 +1004,7 @@ static int evergreen_crtc_do_set_base(struct drm_crtc *crtc, struct radeon_bo *rbo; uint64_t fb_location; uint32_t fb_format, fb_pitch_pixels, tiling_flags; + u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE); int r; /* no fb bound */ @@ -1057,11 +1056,17 @@ static int evergreen_crtc_do_set_base(struct drm_crtc *crtc, case 16: fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565)); +#ifdef __BIG_ENDIAN + fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); +#endif break; case 24: case 32: fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888)); +#ifdef __BIG_ENDIAN + fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); +#endif break; default: DRM_ERROR("Unsupported screen depth %d\n", @@ -1106,6 +1111,7 @@ static int evergreen_crtc_do_set_base(struct drm_crtc *crtc, WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, (u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK); WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); + WREG32(EVERGREEN_GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); @@ -1127,12 +1133,6 @@ static int evergreen_crtc_do_set_base(struct drm_crtc *crtc, WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset, (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); - if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) - WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, - EVERGREEN_INTERLEAVE_EN); - else - WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0); - if (!atomic && fb && fb != crtc->fb) { radeon_fb = to_radeon_framebuffer(fb); rbo = radeon_fb->obj->driver_private; @@ -1162,6 +1162,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, struct drm_framebuffer *target_fb; uint64_t fb_location; uint32_t fb_format, fb_pitch_pixels, tiling_flags; + u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE; int r; /* no fb bound */ @@ -1215,12 +1216,18 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, fb_format = AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | AVIVO_D1GRPH_CONTROL_16BPP_RGB565; +#ifdef __BIG_ENDIAN + fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT; +#endif break; case 24: case 32: fb_format = AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; +#ifdef __BIG_ENDIAN + fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT; +#endif break; default: DRM_ERROR("Unsupported screen depth %d\n", @@ -1260,6 +1267,8 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, (u32) fb_location); WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); + if (rdev->family >= CHIP_R600) + WREG32(R600_D1GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); @@ -1281,12 +1290,6 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); - if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) - WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, - AVIVO_D1MODE_INTERLEAVE_EN); - else - WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0); - if (!atomic && fb && fb != crtc->fb) { radeon_fb = to_radeon_framebuffer(fb); rbo = radeon_fb->obj->driver_private; @@ -1310,7 +1313,7 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, struct radeon_device *rdev = dev->dev_private; if (ASIC_IS_DCE4(rdev)) - return evergreen_crtc_do_set_base(crtc, old_fb, x, y, 0); + return dce4_crtc_do_set_base(crtc, old_fb, x, y, 0); else if (ASIC_IS_AVIVO(rdev)) return avivo_crtc_do_set_base(crtc, old_fb, x, y, 0); else @@ -1325,7 +1328,7 @@ int atombios_crtc_set_base_atomic(struct drm_crtc *crtc, struct radeon_device *rdev = dev->dev_private; if (ASIC_IS_DCE4(rdev)) - return evergreen_crtc_do_set_base(crtc, fb, x, y, 1); + return dce4_crtc_do_set_base(crtc, fb, x, y, 1); else if (ASIC_IS_AVIVO(rdev)) return avivo_crtc_do_set_base(crtc, fb, x, y, 1); else diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 4e7778d44b8d..695de9a38506 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -187,9 +187,9 @@ static int dp_link_clock_for_mode_clock(u8 dpcd[DP_DPCD_SIZE], int mode_clock) int dp_mode_valid(u8 dpcd[DP_DPCD_SIZE], int mode_clock) { int lanes = dp_lanes_for_mode_clock(dpcd, mode_clock); - int bw = dp_lanes_for_mode_clock(dpcd, mode_clock); + int dp_clock = dp_link_clock_for_mode_clock(dpcd, mode_clock); - if ((lanes == 0) || (bw == 0)) + if ((lanes == 0) || (dp_clock == 0)) return MODE_CLOCK_HIGH; return MODE_OK; diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index a8973acb3987..d270b3ff896b 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -97,26 +97,29 @@ u32 evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) } /* get temperature in millidegrees */ -u32 evergreen_get_temp(struct radeon_device *rdev) +int evergreen_get_temp(struct radeon_device *rdev) { u32 temp = (RREG32(CG_MULT_THERMAL_STATUS) & ASIC_T_MASK) >> ASIC_T_SHIFT; u32 actual_temp = 0; - if ((temp >> 10) & 1) - actual_temp = 0; - else if ((temp >> 9) & 1) + if (temp & 0x400) + actual_temp = -256; + else if (temp & 0x200) actual_temp = 255; - else - actual_temp = (temp >> 1) & 0xff; + else if (temp & 0x100) { + actual_temp = temp & 0x1ff; + actual_temp |= ~0x1ff; + } else + actual_temp = temp & 0xff; - return actual_temp * 1000; + return (actual_temp * 1000) / 2; } -u32 sumo_get_temp(struct radeon_device *rdev) +int sumo_get_temp(struct radeon_device *rdev) { u32 temp = RREG32(CG_THERMAL_STATUS) & 0xff; - u32 actual_temp = (temp >> 1) & 0xff; + int actual_temp = temp - 49; return actual_temp * 1000; } @@ -1182,6 +1185,22 @@ static void evergreen_mc_program(struct radeon_device *rdev) /* * CP. */ +void evergreen_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) +{ + /* set to DX10/11 mode */ + radeon_ring_write(rdev, PACKET3(PACKET3_MODE_CONTROL, 0)); + radeon_ring_write(rdev, 1); + /* FIXME: implement */ + radeon_ring_write(rdev, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); + radeon_ring_write(rdev, +#ifdef __BIG_ENDIAN + (2 << 0) | +#endif + (ib->gpu_addr & 0xFFFFFFFC)); + radeon_ring_write(rdev, upper_32_bits(ib->gpu_addr) & 0xFF); + radeon_ring_write(rdev, ib->length_dw); +} + static int evergreen_cp_load_microcode(struct radeon_device *rdev) { @@ -1192,7 +1211,11 @@ static int evergreen_cp_load_microcode(struct radeon_device *rdev) return -EINVAL; r700_cp_stop(rdev); - WREG32(CP_RB_CNTL, RB_NO_UPDATE | (15 << 8) | (3 << 0)); + WREG32(CP_RB_CNTL, +#ifdef __BIG_ENDIAN + BUF_SWAP_32BIT | +#endif + RB_NO_UPDATE | RB_BLKSZ(15) | RB_BUFSZ(3)); fw_data = (const __be32 *)rdev->pfp_fw->data; WREG32(CP_PFP_UCODE_ADDR, 0); @@ -1233,7 +1256,7 @@ static int evergreen_cp_start(struct radeon_device *rdev) cp_me = 0xff; WREG32(CP_ME_CNTL, cp_me); - r = radeon_ring_lock(rdev, evergreen_default_size + 15); + r = radeon_ring_lock(rdev, evergreen_default_size + 19); if (r) { DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r); return r; @@ -1266,6 +1289,11 @@ static int evergreen_cp_start(struct radeon_device *rdev) radeon_ring_write(rdev, 0xffffffff); radeon_ring_write(rdev, 0xffffffff); + radeon_ring_write(rdev, 0xc0026900); + radeon_ring_write(rdev, 0x00000316); + radeon_ring_write(rdev, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */ + radeon_ring_write(rdev, 0x00000010); /* */ + radeon_ring_unlock_commit(rdev); return 0; @@ -1306,7 +1334,11 @@ int evergreen_cp_resume(struct radeon_device *rdev) WREG32(CP_RB_WPTR, 0); /* set the wb address wether it's enabled or not */ - WREG32(CP_RB_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC); + WREG32(CP_RB_RPTR_ADDR, +#ifdef __BIG_ENDIAN + RB_RPTR_SWAP(2) | +#endif + ((rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC)); WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFF); WREG32(SCRATCH_ADDR, ((rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET) >> 8) & 0xFFFFFFFF); @@ -2072,6 +2104,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev) WREG32(VGT_CACHE_INVALIDATION, vgt_cache_invalidation); WREG32(VGT_GS_VERTEX_REUSE, 16); + WREG32(PA_SU_LINE_STIPPLE_VALUE, 0); WREG32(PA_SC_LINE_STIPPLE_STATE, 0); WREG32(VGT_VERTEX_REUSE_BLOCK_CNTL, 14); @@ -2201,6 +2234,9 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev) struct evergreen_mc_save save; u32 grbm_reset = 0; + if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE)) + return 0; + dev_info(rdev->dev, "GPU softreset \n"); dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n", RREG32(GRBM_STATUS)); @@ -2603,8 +2639,8 @@ restart_ih: while (rptr != wptr) { /* wptr/rptr are in bytes! */ ring_index = rptr / 4; - src_id = rdev->ih.ring[ring_index] & 0xff; - src_data = rdev->ih.ring[ring_index + 1] & 0xfffffff; + src_id = le32_to_cpu(rdev->ih.ring[ring_index]) & 0xff; + src_data = le32_to_cpu(rdev->ih.ring[ring_index + 1]) & 0xfffffff; switch (src_id) { case 1: /* D1 vblank/vline */ diff --git a/drivers/gpu/drm/radeon/evergreen_blit_kms.c b/drivers/gpu/drm/radeon/evergreen_blit_kms.c index b758dc7f2f2c..2adfb03f479b 100644 --- a/drivers/gpu/drm/radeon/evergreen_blit_kms.c +++ b/drivers/gpu/drm/radeon/evergreen_blit_kms.c @@ -55,7 +55,7 @@ set_render_target(struct radeon_device *rdev, int format, if (h < 8) h = 8; - cb_color_info = ((format << 2) | (1 << 24)); + cb_color_info = ((format << 2) | (1 << 24) | (1 << 8)); pitch = (w / 8) - 1; slice = ((w * h) / 64) - 1; @@ -133,6 +133,9 @@ set_vtx_resource(struct radeon_device *rdev, u64 gpu_addr) /* high addr, stride */ sq_vtx_constant_word2 = ((upper_32_bits(gpu_addr) & 0xff) | (16 << 8)); +#ifdef __BIG_ENDIAN + sq_vtx_constant_word2 |= (2 << 30); +#endif /* xyzw swizzles */ sq_vtx_constant_word3 = (0 << 3) | (1 << 6) | (2 << 9) | (3 << 12); @@ -173,7 +176,7 @@ set_tex_resource(struct radeon_device *rdev, sq_tex_resource_word0 = (1 << 0); /* 2D */ sq_tex_resource_word0 |= ((((pitch >> 3) - 1) << 6) | ((w - 1) << 18)); - sq_tex_resource_word1 = ((h - 1) << 0); + sq_tex_resource_word1 = ((h - 1) << 0) | (1 << 28); /* xyzw swizzles */ sq_tex_resource_word4 = (0 << 16) | (1 << 19) | (2 << 22) | (3 << 25); @@ -221,7 +224,11 @@ draw_auto(struct radeon_device *rdev) radeon_ring_write(rdev, DI_PT_RECTLIST); radeon_ring_write(rdev, PACKET3(PACKET3_INDEX_TYPE, 0)); - radeon_ring_write(rdev, DI_INDEX_SIZE_16_BIT); + radeon_ring_write(rdev, +#ifdef __BIG_ENDIAN + (2 << 2) | +#endif + DI_INDEX_SIZE_16_BIT); radeon_ring_write(rdev, PACKET3(PACKET3_NUM_INSTANCES, 0)); radeon_ring_write(rdev, 1); @@ -232,7 +239,7 @@ draw_auto(struct radeon_device *rdev) } -/* emits 30 */ +/* emits 36 */ static void set_default_state(struct radeon_device *rdev) { @@ -245,6 +252,8 @@ set_default_state(struct radeon_device *rdev) int num_hs_threads, num_ls_threads; int num_ps_stack_entries, num_vs_stack_entries, num_gs_stack_entries, num_es_stack_entries; int num_hs_stack_entries, num_ls_stack_entries; + u64 gpu_addr; + int dwords; switch (rdev->family) { case CHIP_CEDAR: @@ -497,6 +506,18 @@ set_default_state(struct radeon_device *rdev) radeon_ring_write(rdev, 0x00000000); radeon_ring_write(rdev, 0x00000000); + /* set to DX10/11 mode */ + radeon_ring_write(rdev, PACKET3(PACKET3_MODE_CONTROL, 0)); + radeon_ring_write(rdev, 1); + + /* emit an IB pointing at default state */ + dwords = ALIGN(rdev->r600_blit.state_len, 0x10); + gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.state_offset; + radeon_ring_write(rdev, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); + radeon_ring_write(rdev, gpu_addr & 0xFFFFFFFC); + radeon_ring_write(rdev, upper_32_bits(gpu_addr) & 0xFF); + radeon_ring_write(rdev, dwords); + } static inline uint32_t i2f(uint32_t input) @@ -527,8 +548,10 @@ static inline uint32_t i2f(uint32_t input) int evergreen_blit_init(struct radeon_device *rdev) { u32 obj_size; - int r; + int i, r, dwords; void *ptr; + u32 packet2s[16]; + int num_packet2s = 0; /* pin copy shader into vram if already initialized */ if (rdev->r600_blit.shader_obj) @@ -536,8 +559,17 @@ int evergreen_blit_init(struct radeon_device *rdev) mutex_init(&rdev->r600_blit.mutex); rdev->r600_blit.state_offset = 0; - rdev->r600_blit.state_len = 0; - obj_size = 0; + + rdev->r600_blit.state_len = evergreen_default_size; + + dwords = rdev->r600_blit.state_len; + while (dwords & 0xf) { + packet2s[num_packet2s++] = cpu_to_le32(PACKET2(0)); + dwords++; + } + + obj_size = dwords * 4; + obj_size = ALIGN(obj_size, 256); rdev->r600_blit.vs_offset = obj_size; obj_size += evergreen_vs_size * 4; @@ -567,8 +599,16 @@ int evergreen_blit_init(struct radeon_device *rdev) return r; } - memcpy(ptr + rdev->r600_blit.vs_offset, evergreen_vs, evergreen_vs_size * 4); - memcpy(ptr + rdev->r600_blit.ps_offset, evergreen_ps, evergreen_ps_size * 4); + memcpy_toio(ptr + rdev->r600_blit.state_offset, + evergreen_default_state, rdev->r600_blit.state_len * 4); + + if (num_packet2s) + memcpy_toio(ptr + rdev->r600_blit.state_offset + (rdev->r600_blit.state_len * 4), + packet2s, num_packet2s * 4); + for (i = 0; i < evergreen_vs_size; i++) + *(u32 *)((unsigned long)ptr + rdev->r600_blit.vs_offset + i * 4) = cpu_to_le32(evergreen_vs[i]); + for (i = 0; i < evergreen_ps_size; i++) + *(u32 *)((unsigned long)ptr + rdev->r600_blit.ps_offset + i * 4) = cpu_to_le32(evergreen_ps[i]); radeon_bo_kunmap(rdev->r600_blit.shader_obj); radeon_bo_unreserve(rdev->r600_blit.shader_obj); @@ -652,7 +692,7 @@ int evergreen_blit_prepare_copy(struct radeon_device *rdev, int size_bytes) /* calculate number of loops correctly */ ring_size = num_loops * dwords_per_loop; /* set default + shaders */ - ring_size += 46; /* shaders + def state */ + ring_size += 52; /* shaders + def state */ ring_size += 10; /* fence emit for VB IB */ ring_size += 5; /* done copy */ ring_size += 10; /* fence emit for done copy */ @@ -660,7 +700,7 @@ int evergreen_blit_prepare_copy(struct radeon_device *rdev, int size_bytes) if (r) return r; - set_default_state(rdev); /* 30 */ + set_default_state(rdev); /* 36 */ set_shaders(rdev); /* 16 */ return 0; } diff --git a/drivers/gpu/drm/radeon/evergreen_blit_shaders.c b/drivers/gpu/drm/radeon/evergreen_blit_shaders.c index ef1d28c07fbf..3a10399e0066 100644 --- a/drivers/gpu/drm/radeon/evergreen_blit_shaders.c +++ b/drivers/gpu/drm/radeon/evergreen_blit_shaders.c @@ -311,11 +311,19 @@ const u32 evergreen_vs[] = 0x00000000, 0x3c000000, 0x67961001, +#ifdef __BIG_ENDIAN + 0x000a0000, +#else 0x00080000, +#endif 0x00000000, 0x1c000000, 0x67961000, +#ifdef __BIG_ENDIAN + 0x00020008, +#else 0x00000008, +#endif 0x00000000, }; diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 36d32d83d866..eb4acf4528ff 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -98,6 +98,7 @@ #define BUF_SWAP_32BIT (2 << 16) #define CP_RB_RPTR 0x8700 #define CP_RB_RPTR_ADDR 0xC10C +#define RB_RPTR_SWAP(x) ((x) << 0) #define CP_RB_RPTR_ADDR_HI 0xC110 #define CP_RB_RPTR_WR 0xC108 #define CP_RB_WPTR 0xC114 @@ -240,6 +241,7 @@ #define FORCE_EOV_MAX_CLK_CNT(x) ((x) << 0) #define FORCE_EOV_MAX_REZ_CNT(x) ((x) << 16) #define PA_SC_LINE_STIPPLE 0x28A0C +#define PA_SU_LINE_STIPPLE_VALUE 0x8A60 #define PA_SC_LINE_STIPPLE_STATE 0x8B10 #define SCRATCH_REG0 0x8500 @@ -652,6 +654,7 @@ #define PACKET3_DISPATCH_DIRECT 0x15 #define PACKET3_DISPATCH_INDIRECT 0x16 #define PACKET3_INDIRECT_BUFFER_END 0x17 +#define PACKET3_MODE_CONTROL 0x18 #define PACKET3_SET_PREDICATION 0x20 #define PACKET3_REG_RMW 0x21 #define PACKET3_COND_EXEC 0x22 diff --git a/drivers/gpu/drm/radeon/mkregtable.c b/drivers/gpu/drm/radeon/mkregtable.c index 607241c6a8a9..5a82b6b75849 100644 --- a/drivers/gpu/drm/radeon/mkregtable.c +++ b/drivers/gpu/drm/radeon/mkregtable.c @@ -673,8 +673,10 @@ static int parser_auth(struct table *t, const char *filename) last_reg = strtol(last_reg_s, NULL, 16); do { - if (fgets(buf, 1024, file) == NULL) + if (fgets(buf, 1024, file) == NULL) { + fclose(file); return -1; + } len = strlen(buf); if (ftell(file) == end) done = 1; @@ -685,6 +687,7 @@ static int parser_auth(struct table *t, const char *filename) fprintf(stderr, "Error matching regular expression %d in %s\n", r, filename); + fclose(file); return -1; } else { buf[match[0].rm_eo] = 0; diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 46da5142b131..56deae5bf02e 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -1031,8 +1031,8 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size) WREG32(RADEON_CP_CSQ_MODE, REG_SET(RADEON_INDIRECT2_START, indirect2_start) | REG_SET(RADEON_INDIRECT1_START, indirect1_start)); - WREG32(0x718, 0); - WREG32(0x744, 0x00004D4D); + WREG32(RADEON_CP_RB_WPTR_DELAY, 0); + WREG32(RADEON_CP_CSQ_MODE, 0x00004D4D); WREG32(RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIBM_INDBM); radeon_ring_start(rdev); r = radeon_ring_test(rdev); @@ -1427,6 +1427,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p, } track->zb.robj = reloc->robj; track->zb.offset = idx_value; + track->zb_dirty = true; ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); break; case RADEON_RB3D_COLOROFFSET: @@ -1439,6 +1440,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p, } track->cb[0].robj = reloc->robj; track->cb[0].offset = idx_value; + track->cb_dirty = true; ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); break; case RADEON_PP_TXOFFSET_0: @@ -1454,6 +1456,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p, } ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); track->textures[i].robj = reloc->robj; + track->tex_dirty = true; break; case RADEON_PP_CUBIC_OFFSET_T0_0: case RADEON_PP_CUBIC_OFFSET_T0_1: @@ -1471,6 +1474,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p, track->textures[0].cube_info[i].offset = idx_value; ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); track->textures[0].cube_info[i].robj = reloc->robj; + track->tex_dirty = true; break; case RADEON_PP_CUBIC_OFFSET_T1_0: case RADEON_PP_CUBIC_OFFSET_T1_1: @@ -1488,6 +1492,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p, track->textures[1].cube_info[i].offset = idx_value; ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); track->textures[1].cube_info[i].robj = reloc->robj; + track->tex_dirty = true; break; case RADEON_PP_CUBIC_OFFSET_T2_0: case RADEON_PP_CUBIC_OFFSET_T2_1: @@ -1505,9 +1510,12 @@ static int r100_packet0_check(struct radeon_cs_parser *p, track->textures[2].cube_info[i].offset = idx_value; ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); track->textures[2].cube_info[i].robj = reloc->robj; + track->tex_dirty = true; break; case RADEON_RE_WIDTH_HEIGHT: track->maxy = ((idx_value >> 16) & 0x7FF); + track->cb_dirty = true; + track->zb_dirty = true; break; case RADEON_RB3D_COLORPITCH: r = r100_cs_packet_next_reloc(p, &reloc); @@ -1528,9 +1536,11 @@ static int r100_packet0_check(struct radeon_cs_parser *p, ib[idx] = tmp; track->cb[0].pitch = idx_value & RADEON_COLORPITCH_MASK; + track->cb_dirty = true; break; case RADEON_RB3D_DEPTHPITCH: track->zb.pitch = idx_value & RADEON_DEPTHPITCH_MASK; + track->zb_dirty = true; break; case RADEON_RB3D_CNTL: switch ((idx_value >> RADEON_RB3D_COLOR_FORMAT_SHIFT) & 0x1f) { @@ -1555,6 +1565,8 @@ static int r100_packet0_check(struct radeon_cs_parser *p, return -EINVAL; } track->z_enabled = !!(idx_value & RADEON_Z_ENABLE); + track->cb_dirty = true; + track->zb_dirty = true; break; case RADEON_RB3D_ZSTENCILCNTL: switch (idx_value & 0xf) { @@ -1572,6 +1584,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p, default: break; } + track->zb_dirty = true; break; case RADEON_RB3D_ZPASS_ADDR: r = r100_cs_packet_next_reloc(p, &reloc); @@ -1588,6 +1601,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p, uint32_t temp = idx_value >> 4; for (i = 0; i < track->num_texture; i++) track->textures[i].enabled = !!(temp & (1 << i)); + track->tex_dirty = true; } break; case RADEON_SE_VF_CNTL: @@ -1602,12 +1616,14 @@ static int r100_packet0_check(struct radeon_cs_parser *p, i = (reg - RADEON_PP_TEX_SIZE_0) / 8; track->textures[i].width = (idx_value & RADEON_TEX_USIZE_MASK) + 1; track->textures[i].height = ((idx_value & RADEON_TEX_VSIZE_MASK) >> RADEON_TEX_VSIZE_SHIFT) + 1; + track->tex_dirty = true; break; case RADEON_PP_TEX_PITCH_0: case RADEON_PP_TEX_PITCH_1: case RADEON_PP_TEX_PITCH_2: i = (reg - RADEON_PP_TEX_PITCH_0) / 8; track->textures[i].pitch = idx_value + 32; + track->tex_dirty = true; break; case RADEON_PP_TXFILTER_0: case RADEON_PP_TXFILTER_1: @@ -1621,6 +1637,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p, tmp = (idx_value >> 27) & 0x7; if (tmp == 2 || tmp == 6) track->textures[i].roundup_h = false; + track->tex_dirty = true; break; case RADEON_PP_TXFORMAT_0: case RADEON_PP_TXFORMAT_1: @@ -1673,6 +1690,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p, } track->textures[i].cube_info[4].width = 1 << ((idx_value >> 16) & 0xf); track->textures[i].cube_info[4].height = 1 << ((idx_value >> 20) & 0xf); + track->tex_dirty = true; break; case RADEON_PP_CUBIC_FACES_0: case RADEON_PP_CUBIC_FACES_1: @@ -1683,6 +1701,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p, track->textures[i].cube_info[face].width = 1 << ((tmp >> (face * 8)) & 0xf); track->textures[i].cube_info[face].height = 1 << ((tmp >> ((face * 8) + 4)) & 0xf); } + track->tex_dirty = true; break; default: printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n", @@ -2347,10 +2366,10 @@ void r100_vga_set_state(struct radeon_device *rdev, bool state) temp = RREG32(RADEON_CONFIG_CNTL); if (state == false) { - temp &= ~(1<<8); - temp |= (1<<9); + temp &= ~RADEON_CFG_VGA_RAM_EN; + temp |= RADEON_CFG_VGA_IO_DIS; } else { - temp &= ~(1<<9); + temp &= ~RADEON_CFG_VGA_IO_DIS; } WREG32(RADEON_CONFIG_CNTL, temp); } @@ -3318,9 +3337,9 @@ int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track) unsigned long size; unsigned prim_walk; unsigned nverts; - unsigned num_cb = track->num_cb; + unsigned num_cb = track->cb_dirty ? track->num_cb : 0; - if (!track->zb_cb_clear && !track->color_channel_mask && + if (num_cb && !track->zb_cb_clear && !track->color_channel_mask && !track->blend_read_enable) num_cb = 0; @@ -3341,7 +3360,9 @@ int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track) return -EINVAL; } } - if (track->z_enabled) { + track->cb_dirty = false; + + if (track->zb_dirty && track->z_enabled) { if (track->zb.robj == NULL) { DRM_ERROR("[drm] No buffer for z buffer !\n"); return -EINVAL; @@ -3358,6 +3379,28 @@ int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track) return -EINVAL; } } + track->zb_dirty = false; + + if (track->aa_dirty && track->aaresolve) { + if (track->aa.robj == NULL) { + DRM_ERROR("[drm] No buffer for AA resolve buffer %d !\n", i); + return -EINVAL; + } + /* I believe the format comes from colorbuffer0. */ + size = track->aa.pitch * track->cb[0].cpp * track->maxy; + size += track->aa.offset; + if (size > radeon_bo_size(track->aa.robj)) { + DRM_ERROR("[drm] Buffer too small for AA resolve buffer %d " + "(need %lu have %lu) !\n", i, size, + radeon_bo_size(track->aa.robj)); + DRM_ERROR("[drm] AA resolve buffer %d (%u %u %u %u)\n", + i, track->aa.pitch, track->cb[0].cpp, + track->aa.offset, track->maxy); + return -EINVAL; + } + } + track->aa_dirty = false; + prim_walk = (track->vap_vf_cntl >> 4) & 0x3; if (track->vap_vf_cntl & (1 << 14)) { nverts = track->vap_alt_nverts; @@ -3417,13 +3460,23 @@ int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track) prim_walk); return -EINVAL; } - return r100_cs_track_texture_check(rdev, track); + + if (track->tex_dirty) { + track->tex_dirty = false; + return r100_cs_track_texture_check(rdev, track); + } + return 0; } void r100_cs_track_clear(struct radeon_device *rdev, struct r100_cs_track *track) { unsigned i, face; + track->cb_dirty = true; + track->zb_dirty = true; + track->tex_dirty = true; + track->aa_dirty = true; + if (rdev->family < CHIP_R300) { track->num_cb = 1; if (rdev->family <= CHIP_RS200) @@ -3437,6 +3490,8 @@ void r100_cs_track_clear(struct radeon_device *rdev, struct r100_cs_track *track track->num_texture = 16; track->maxy = 4096; track->separate_cube = 0; + track->aaresolve = true; + track->aa.robj = NULL; } for (i = 0; i < track->num_cb; i++) { @@ -3522,7 +3577,7 @@ int r100_ring_test(struct radeon_device *rdev) if (i < rdev->usec_timeout) { DRM_INFO("ring test succeeded in %d usecs\n", i); } else { - DRM_ERROR("radeon: ring test failed (sracth(0x%04X)=0x%08X)\n", + DRM_ERROR("radeon: ring test failed (scratch(0x%04X)=0x%08X)\n", scratch, tmp); r = -EINVAL; } diff --git a/drivers/gpu/drm/radeon/r100_track.h b/drivers/gpu/drm/radeon/r100_track.h index af65600e6564..2fef9de7f363 100644 --- a/drivers/gpu/drm/radeon/r100_track.h +++ b/drivers/gpu/drm/radeon/r100_track.h @@ -52,14 +52,7 @@ struct r100_cs_track_texture { unsigned compress_format; }; -struct r100_cs_track_limits { - unsigned num_cb; - unsigned num_texture; - unsigned max_levels; -}; - struct r100_cs_track { - struct radeon_device *rdev; unsigned num_cb; unsigned num_texture; unsigned maxy; @@ -73,11 +66,17 @@ struct r100_cs_track { struct r100_cs_track_array arrays[11]; struct r100_cs_track_cb cb[R300_MAX_CB]; struct r100_cs_track_cb zb; + struct r100_cs_track_cb aa; struct r100_cs_track_texture textures[R300_TRACK_MAX_TEXTURE]; bool z_enabled; bool separate_cube; bool zb_cb_clear; bool blend_read_enable; + bool cb_dirty; + bool zb_dirty; + bool tex_dirty; + bool aa_dirty; + bool aaresolve; }; int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track); diff --git a/drivers/gpu/drm/radeon/r200.c b/drivers/gpu/drm/radeon/r200.c index d2408c395619..f24058300413 100644 --- a/drivers/gpu/drm/radeon/r200.c +++ b/drivers/gpu/drm/radeon/r200.c @@ -184,6 +184,7 @@ int r200_packet0_check(struct radeon_cs_parser *p, } track->zb.robj = reloc->robj; track->zb.offset = idx_value; + track->zb_dirty = true; ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); break; case RADEON_RB3D_COLOROFFSET: @@ -196,6 +197,7 @@ int r200_packet0_check(struct radeon_cs_parser *p, } track->cb[0].robj = reloc->robj; track->cb[0].offset = idx_value; + track->cb_dirty = true; ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); break; case R200_PP_TXOFFSET_0: @@ -214,6 +216,7 @@ int r200_packet0_check(struct radeon_cs_parser *p, } ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); track->textures[i].robj = reloc->robj; + track->tex_dirty = true; break; case R200_PP_CUBIC_OFFSET_F1_0: case R200_PP_CUBIC_OFFSET_F2_0: @@ -257,9 +260,12 @@ int r200_packet0_check(struct radeon_cs_parser *p, track->textures[i].cube_info[face - 1].offset = idx_value; ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); track->textures[i].cube_info[face - 1].robj = reloc->robj; + track->tex_dirty = true; break; case RADEON_RE_WIDTH_HEIGHT: track->maxy = ((idx_value >> 16) & 0x7FF); + track->cb_dirty = true; + track->zb_dirty = true; break; case RADEON_RB3D_COLORPITCH: r = r100_cs_packet_next_reloc(p, &reloc); @@ -280,9 +286,11 @@ int r200_packet0_check(struct radeon_cs_parser *p, ib[idx] = tmp; track->cb[0].pitch = idx_value & RADEON_COLORPITCH_MASK; + track->cb_dirty = true; break; case RADEON_RB3D_DEPTHPITCH: track->zb.pitch = idx_value & RADEON_DEPTHPITCH_MASK; + track->zb_dirty = true; break; case RADEON_RB3D_CNTL: switch ((idx_value >> RADEON_RB3D_COLOR_FORMAT_SHIFT) & 0x1f) { @@ -312,6 +320,8 @@ int r200_packet0_check(struct radeon_cs_parser *p, } track->z_enabled = !!(idx_value & RADEON_Z_ENABLE); + track->cb_dirty = true; + track->zb_dirty = true; break; case RADEON_RB3D_ZSTENCILCNTL: switch (idx_value & 0xf) { @@ -329,6 +339,7 @@ int r200_packet0_check(struct radeon_cs_parser *p, default: break; } + track->zb_dirty = true; break; case RADEON_RB3D_ZPASS_ADDR: r = r100_cs_packet_next_reloc(p, &reloc); @@ -345,6 +356,7 @@ int r200_packet0_check(struct radeon_cs_parser *p, uint32_t temp = idx_value >> 4; for (i = 0; i < track->num_texture; i++) track->textures[i].enabled = !!(temp & (1 << i)); + track->tex_dirty = true; } break; case RADEON_SE_VF_CNTL: @@ -369,6 +381,7 @@ int r200_packet0_check(struct radeon_cs_parser *p, i = (reg - R200_PP_TXSIZE_0) / 32; track->textures[i].width = (idx_value & RADEON_TEX_USIZE_MASK) + 1; track->textures[i].height = ((idx_value & RADEON_TEX_VSIZE_MASK) >> RADEON_TEX_VSIZE_SHIFT) + 1; + track->tex_dirty = true; break; case R200_PP_TXPITCH_0: case R200_PP_TXPITCH_1: @@ -378,6 +391,7 @@ int r200_packet0_check(struct radeon_cs_parser *p, case R200_PP_TXPITCH_5: i = (reg - R200_PP_TXPITCH_0) / 32; track->textures[i].pitch = idx_value + 32; + track->tex_dirty = true; break; case R200_PP_TXFILTER_0: case R200_PP_TXFILTER_1: @@ -394,6 +408,7 @@ int r200_packet0_check(struct radeon_cs_parser *p, tmp = (idx_value >> 27) & 0x7; if (tmp == 2 || tmp == 6) track->textures[i].roundup_h = false; + track->tex_dirty = true; break; case R200_PP_TXMULTI_CTL_0: case R200_PP_TXMULTI_CTL_1: @@ -432,6 +447,7 @@ int r200_packet0_check(struct radeon_cs_parser *p, track->textures[i].tex_coord_type = 1; break; } + track->tex_dirty = true; break; case R200_PP_TXFORMAT_0: case R200_PP_TXFORMAT_1: @@ -488,6 +504,7 @@ int r200_packet0_check(struct radeon_cs_parser *p, } track->textures[i].cube_info[4].width = 1 << ((idx_value >> 16) & 0xf); track->textures[i].cube_info[4].height = 1 << ((idx_value >> 20) & 0xf); + track->tex_dirty = true; break; case R200_PP_CUBIC_FACES_0: case R200_PP_CUBIC_FACES_1: @@ -501,6 +518,7 @@ int r200_packet0_check(struct radeon_cs_parser *p, track->textures[i].cube_info[face].width = 1 << ((tmp >> (face * 8)) & 0xf); track->textures[i].cube_info[face].height = 1 << ((tmp >> ((face * 8) + 4)) & 0xf); } + track->tex_dirty = true; break; default: printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n", diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index cf862ca580bf..069efa8c8ecf 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -69,6 +69,9 @@ void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev) mb(); } +#define R300_PTE_WRITEABLE (1 << 2) +#define R300_PTE_READABLE (1 << 3) + int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) { void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; @@ -78,7 +81,7 @@ int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) } addr = (lower_32_bits(addr) >> 8) | ((upper_32_bits(addr) & 0xff) << 24) | - 0xc; + R300_PTE_WRITEABLE | R300_PTE_READABLE; /* on x86 we want this to be CPU endian, on powerpc * on powerpc without HW swappers, it'll get swapped on way * into VRAM - so no need for cpu_to_le32 on VRAM tables */ @@ -135,7 +138,7 @@ int rv370_pcie_gart_enable(struct radeon_device *rdev) WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_LO, rdev->mc.vram_start); WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_HI, 0); /* Clear error */ - WREG32_PCIE(0x18, 0); + WREG32_PCIE(RADEON_PCIE_TX_GART_ERROR, 0); tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); tmp |= RADEON_PCIE_TX_GART_EN; tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; @@ -664,6 +667,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p, } track->cb[i].robj = reloc->robj; track->cb[i].offset = idx_value; + track->cb_dirty = true; ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); break; case R300_ZB_DEPTHOFFSET: @@ -676,6 +680,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p, } track->zb.robj = reloc->robj; track->zb.offset = idx_value; + track->zb_dirty = true; ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); break; case R300_TX_OFFSET_0: @@ -714,6 +719,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p, tmp |= tile_flags; ib[idx] = tmp; track->textures[i].robj = reloc->robj; + track->tex_dirty = true; break; /* Tracked registers */ case 0x2084: @@ -740,6 +746,8 @@ static int r300_packet0_check(struct radeon_cs_parser *p, if (p->rdev->family < CHIP_RV515) { track->maxy -= 1440; } + track->cb_dirty = true; + track->zb_dirty = true; break; case 0x4E00: /* RB3D_CCTL */ @@ -749,6 +757,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p, return -EINVAL; } track->num_cb = ((idx_value >> 5) & 0x3) + 1; + track->cb_dirty = true; break; case 0x4E38: case 0x4E3C: @@ -811,6 +820,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p, ((idx_value >> 21) & 0xF)); return -EINVAL; } + track->cb_dirty = true; break; case 0x4F00: /* ZB_CNTL */ @@ -819,6 +829,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p, } else { track->z_enabled = false; } + track->zb_dirty = true; break; case 0x4F10: /* ZB_FORMAT */ @@ -835,6 +846,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p, (idx_value & 0xF)); return -EINVAL; } + track->zb_dirty = true; break; case 0x4F24: /* ZB_DEPTHPITCH */ @@ -858,14 +870,17 @@ static int r300_packet0_check(struct radeon_cs_parser *p, ib[idx] = tmp; track->zb.pitch = idx_value & 0x3FFC; + track->zb_dirty = true; break; case 0x4104: + /* TX_ENABLE */ for (i = 0; i < 16; i++) { bool enabled; enabled = !!(idx_value & (1 << i)); track->textures[i].enabled = enabled; } + track->tex_dirty = true; break; case 0x44C0: case 0x44C4: @@ -895,6 +910,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p, track->textures[i].compress_format = R100_TRACK_COMP_NONE; break; case R300_TX_FORMAT_X16: + case R300_TX_FORMAT_FL_I16: case R300_TX_FORMAT_Y8X8: case R300_TX_FORMAT_Z5Y6X5: case R300_TX_FORMAT_Z6Y5X5: @@ -907,6 +923,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p, track->textures[i].compress_format = R100_TRACK_COMP_NONE; break; case R300_TX_FORMAT_Y16X16: + case R300_TX_FORMAT_FL_I16A16: case R300_TX_FORMAT_Z11Y11X10: case R300_TX_FORMAT_Z10Y11X11: case R300_TX_FORMAT_W8Z8Y8X8: @@ -948,8 +965,8 @@ static int r300_packet0_check(struct radeon_cs_parser *p, DRM_ERROR("Invalid texture format %u\n", (idx_value & 0x1F)); return -EINVAL; - break; } + track->tex_dirty = true; break; case 0x4400: case 0x4404: @@ -977,6 +994,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p, if (tmp == 2 || tmp == 4 || tmp == 6) { track->textures[i].roundup_h = false; } + track->tex_dirty = true; break; case 0x4500: case 0x4504: @@ -1014,6 +1032,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p, DRM_ERROR("Forbidden bit TXFORMAT_MSB\n"); return -EINVAL; } + track->tex_dirty = true; break; case 0x4480: case 0x4484: @@ -1043,6 +1062,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p, track->textures[i].use_pitch = !!tmp; tmp = (idx_value >> 22) & 0xF; track->textures[i].txdepth = tmp; + track->tex_dirty = true; break; case R300_ZB_ZPASS_ADDR: r = r100_cs_packet_next_reloc(p, &reloc); @@ -1057,6 +1077,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p, case 0x4e0c: /* RB3D_COLOR_CHANNEL_MASK */ track->color_channel_mask = idx_value; + track->cb_dirty = true; break; case 0x43a4: /* SC_HYPERZ_EN */ @@ -1070,6 +1091,8 @@ static int r300_packet0_check(struct radeon_cs_parser *p, case 0x4f1c: /* ZB_BW_CNTL */ track->zb_cb_clear = !!(idx_value & (1 << 5)); + track->cb_dirty = true; + track->zb_dirty = true; if (p->rdev->hyperz_filp != p->filp) { if (idx_value & (R300_HIZ_ENABLE | R300_RD_COMP_ENABLE | @@ -1081,8 +1104,28 @@ static int r300_packet0_check(struct radeon_cs_parser *p, case 0x4e04: /* RB3D_BLENDCNTL */ track->blend_read_enable = !!(idx_value & (1 << 2)); + track->cb_dirty = true; + break; + case R300_RB3D_AARESOLVE_OFFSET: + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for ib[%d]=0x%04X\n", + idx, reg); + r100_cs_dump_packet(p, pkt); + return r; + } + track->aa.robj = reloc->robj; + track->aa.offset = idx_value; + track->aa_dirty = true; + ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); + break; + case R300_RB3D_AARESOLVE_PITCH: + track->aa.pitch = idx_value & 0x3FFE; + track->aa_dirty = true; break; - case 0x4f28: /* ZB_DEPTHCLEARVALUE */ + case R300_RB3D_AARESOLVE_CTL: + track->aaresolve = idx_value & 0x1; + track->aa_dirty = true; break; case 0x4f30: /* ZB_MASK_OFFSET */ case 0x4f34: /* ZB_ZMASK_PITCH */ diff --git a/drivers/gpu/drm/radeon/r300_reg.h b/drivers/gpu/drm/radeon/r300_reg.h index 1a0d5362cd79..f0bce399c9f3 100644 --- a/drivers/gpu/drm/radeon/r300_reg.h +++ b/drivers/gpu/drm/radeon/r300_reg.h @@ -1371,6 +1371,8 @@ #define R300_RB3D_COLORPITCH2 0x4E40 /* GUESS */ #define R300_RB3D_COLORPITCH3 0x4E44 /* GUESS */ +#define R300_RB3D_AARESOLVE_OFFSET 0x4E80 +#define R300_RB3D_AARESOLVE_PITCH 0x4E84 #define R300_RB3D_AARESOLVE_CTL 0x4E88 /* gap */ diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index c387346f93a9..0b59ed7c7d2c 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -96,7 +96,7 @@ void r420_pipes_init(struct radeon_device *rdev) "programming pipes. Bad things might happen.\n"); } /* get max number of pipes */ - gb_pipe_select = RREG32(0x402C); + gb_pipe_select = RREG32(R400_GB_PIPE_SELECT); num_pipes = ((gb_pipe_select >> 12) & 3) + 1; /* SE chips have 1 pipe */ diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index 3c8677f9e385..2ce80d976568 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -79,8 +79,8 @@ static void r520_gpu_init(struct radeon_device *rdev) WREG32(0x4128, 0xFF); } r420_pipes_init(rdev); - gb_pipe_select = RREG32(0x402C); - tmp = RREG32(0x170C); + gb_pipe_select = RREG32(R400_GB_PIPE_SELECT); + tmp = RREG32(R300_DST_PIPE_CONFIG); pipe_select_current = (tmp >> 2) & 3; tmp = (1 << pipe_select_current) | (((gb_pipe_select >> 8) & 0xF) << 4); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index aca2236268fa..de88624d5f87 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -97,12 +97,16 @@ void r600_irq_disable(struct radeon_device *rdev); static void r600_pcie_gen2_enable(struct radeon_device *rdev); /* get temperature in millidegrees */ -u32 rv6xx_get_temp(struct radeon_device *rdev) +int rv6xx_get_temp(struct radeon_device *rdev) { u32 temp = (RREG32(CG_THERMAL_STATUS) & ASIC_T_MASK) >> ASIC_T_SHIFT; + int actual_temp = temp & 0xff; - return temp * 1000; + if (temp & 0x100) + actual_temp -= 256; + + return actual_temp * 1000; } void r600_pm_get_dynpm_state(struct radeon_device *rdev) @@ -1287,6 +1291,9 @@ int r600_gpu_soft_reset(struct radeon_device *rdev) S_008014_CB2_BUSY(1) | S_008014_CB3_BUSY(1); u32 tmp; + if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE)) + return 0; + dev_info(rdev->dev, "GPU softreset \n"); dev_info(rdev->dev, " R_008010_GRBM_STATUS=0x%08X\n", RREG32(R_008010_GRBM_STATUS)); @@ -2098,7 +2105,11 @@ static int r600_cp_load_microcode(struct radeon_device *rdev) r600_cp_stop(rdev); - WREG32(CP_RB_CNTL, RB_NO_UPDATE | RB_BLKSZ(15) | RB_BUFSZ(3)); + WREG32(CP_RB_CNTL, +#ifdef __BIG_ENDIAN + BUF_SWAP_32BIT | +#endif + RB_NO_UPDATE | RB_BLKSZ(15) | RB_BUFSZ(3)); /* Reset cp */ WREG32(GRBM_SOFT_RESET, SOFT_RESET_CP); @@ -2185,7 +2196,11 @@ int r600_cp_resume(struct radeon_device *rdev) WREG32(CP_RB_WPTR, 0); /* set the wb address whether it's enabled or not */ - WREG32(CP_RB_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC); + WREG32(CP_RB_RPTR_ADDR, +#ifdef __BIG_ENDIAN + RB_RPTR_SWAP(2) | +#endif + ((rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC)); WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFF); WREG32(SCRATCH_ADDR, ((rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET) >> 8) & 0xFFFFFFFF); @@ -2621,7 +2636,11 @@ void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) { /* FIXME: implement */ radeon_ring_write(rdev, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); - radeon_ring_write(rdev, ib->gpu_addr & 0xFFFFFFFC); + radeon_ring_write(rdev, +#ifdef __BIG_ENDIAN + (2 << 0) | +#endif + (ib->gpu_addr & 0xFFFFFFFC)); radeon_ring_write(rdev, upper_32_bits(ib->gpu_addr) & 0xFF); radeon_ring_write(rdev, ib->length_dw); } @@ -3290,8 +3309,8 @@ restart_ih: while (rptr != wptr) { /* wptr/rptr are in bytes! */ ring_index = rptr / 4; - src_id = rdev->ih.ring[ring_index] & 0xff; - src_data = rdev->ih.ring[ring_index + 1] & 0xfffffff; + src_id = le32_to_cpu(rdev->ih.ring[ring_index]) & 0xff; + src_data = le32_to_cpu(rdev->ih.ring[ring_index + 1]) & 0xfffffff; switch (src_id) { case 1: /* D1 vblank/vline */ diff --git a/drivers/gpu/drm/radeon/r600_blit.c b/drivers/gpu/drm/radeon/r600_blit.c index ca5c29f70779..7f1043448d25 100644 --- a/drivers/gpu/drm/radeon/r600_blit.c +++ b/drivers/gpu/drm/radeon/r600_blit.c @@ -137,9 +137,9 @@ set_shaders(struct drm_device *dev) ps = (u32 *) ((char *)dev->agp_buffer_map->handle + dev_priv->blit_vb->offset + 256); for (i = 0; i < r6xx_vs_size; i++) - vs[i] = r6xx_vs[i]; + vs[i] = cpu_to_le32(r6xx_vs[i]); for (i = 0; i < r6xx_ps_size; i++) - ps[i] = r6xx_ps[i]; + ps[i] = cpu_to_le32(r6xx_ps[i]); dev_priv->blit_vb->used = 512; @@ -192,6 +192,9 @@ set_vtx_resource(drm_radeon_private_t *dev_priv, u64 gpu_addr) DRM_DEBUG("\n"); sq_vtx_constant_word2 = (((gpu_addr >> 32) & 0xff) | (16 << 8)); +#ifdef __BIG_ENDIAN + sq_vtx_constant_word2 |= (2 << 30); +#endif BEGIN_RING(9); OUT_RING(CP_PACKET3(R600_IT_SET_RESOURCE, 7)); @@ -291,7 +294,11 @@ draw_auto(drm_radeon_private_t *dev_priv) OUT_RING(DI_PT_RECTLIST); OUT_RING(CP_PACKET3(R600_IT_INDEX_TYPE, 0)); +#ifdef __BIG_ENDIAN + OUT_RING((2 << 2) | DI_INDEX_SIZE_16_BIT); +#else OUT_RING(DI_INDEX_SIZE_16_BIT); +#endif OUT_RING(CP_PACKET3(R600_IT_NUM_INSTANCES, 0)); OUT_RING(1); diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c index 86e5aa07f0db..41f7aafc97c4 100644 --- a/drivers/gpu/drm/radeon/r600_blit_kms.c +++ b/drivers/gpu/drm/radeon/r600_blit_kms.c @@ -54,7 +54,7 @@ set_render_target(struct radeon_device *rdev, int format, if (h < 8) h = 8; - cb_color_info = ((format << 2) | (1 << 27)); + cb_color_info = ((format << 2) | (1 << 27) | (1 << 8)); pitch = (w / 8) - 1; slice = ((w * h) / 64) - 1; @@ -165,6 +165,9 @@ set_vtx_resource(struct radeon_device *rdev, u64 gpu_addr) u32 sq_vtx_constant_word2; sq_vtx_constant_word2 = ((upper_32_bits(gpu_addr) & 0xff) | (16 << 8)); +#ifdef __BIG_ENDIAN + sq_vtx_constant_word2 |= (2 << 30); +#endif radeon_ring_write(rdev, PACKET3(PACKET3_SET_RESOURCE, 7)); radeon_ring_write(rdev, 0x460); @@ -199,7 +202,7 @@ set_tex_resource(struct radeon_device *rdev, if (h < 1) h = 1; - sq_tex_resource_word0 = (1 << 0); + sq_tex_resource_word0 = (1 << 0) | (1 << 3); sq_tex_resource_word0 |= ((((pitch >> 3) - 1) << 8) | ((w - 1) << 19)); @@ -253,7 +256,11 @@ draw_auto(struct radeon_device *rdev) radeon_ring_write(rdev, DI_PT_RECTLIST); radeon_ring_write(rdev, PACKET3(PACKET3_INDEX_TYPE, 0)); - radeon_ring_write(rdev, DI_INDEX_SIZE_16_BIT); + radeon_ring_write(rdev, +#ifdef __BIG_ENDIAN + (2 << 2) | +#endif + DI_INDEX_SIZE_16_BIT); radeon_ring_write(rdev, PACKET3(PACKET3_NUM_INSTANCES, 0)); radeon_ring_write(rdev, 1); @@ -424,7 +431,11 @@ set_default_state(struct radeon_device *rdev) dwords = ALIGN(rdev->r600_blit.state_len, 0x10); gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.state_offset; radeon_ring_write(rdev, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); - radeon_ring_write(rdev, gpu_addr & 0xFFFFFFFC); + radeon_ring_write(rdev, +#ifdef __BIG_ENDIAN + (2 << 0) | +#endif + (gpu_addr & 0xFFFFFFFC)); radeon_ring_write(rdev, upper_32_bits(gpu_addr) & 0xFF); radeon_ring_write(rdev, dwords); @@ -467,7 +478,7 @@ static inline uint32_t i2f(uint32_t input) int r600_blit_init(struct radeon_device *rdev) { u32 obj_size; - int r, dwords; + int i, r, dwords; void *ptr; u32 packet2s[16]; int num_packet2s = 0; @@ -486,7 +497,7 @@ int r600_blit_init(struct radeon_device *rdev) dwords = rdev->r600_blit.state_len; while (dwords & 0xf) { - packet2s[num_packet2s++] = PACKET2(0); + packet2s[num_packet2s++] = cpu_to_le32(PACKET2(0)); dwords++; } @@ -529,8 +540,10 @@ int r600_blit_init(struct radeon_device *rdev) if (num_packet2s) memcpy_toio(ptr + rdev->r600_blit.state_offset + (rdev->r600_blit.state_len * 4), packet2s, num_packet2s * 4); - memcpy(ptr + rdev->r600_blit.vs_offset, r6xx_vs, r6xx_vs_size * 4); - memcpy(ptr + rdev->r600_blit.ps_offset, r6xx_ps, r6xx_ps_size * 4); + for (i = 0; i < r6xx_vs_size; i++) + *(u32 *)((unsigned long)ptr + rdev->r600_blit.vs_offset + i * 4) = cpu_to_le32(r6xx_vs[i]); + for (i = 0; i < r6xx_ps_size; i++) + *(u32 *)((unsigned long)ptr + rdev->r600_blit.ps_offset + i * 4) = cpu_to_le32(r6xx_ps[i]); radeon_bo_kunmap(rdev->r600_blit.shader_obj); radeon_bo_unreserve(rdev->r600_blit.shader_obj); diff --git a/drivers/gpu/drm/radeon/r600_blit_shaders.c b/drivers/gpu/drm/radeon/r600_blit_shaders.c index e8151c1d55b2..2d1f6c5ee2a7 100644 --- a/drivers/gpu/drm/radeon/r600_blit_shaders.c +++ b/drivers/gpu/drm/radeon/r600_blit_shaders.c @@ -684,7 +684,11 @@ const u32 r6xx_vs[] = 0x00000000, 0x3c000000, 0x68cd1000, +#ifdef __BIG_ENDIAN + 0x000a0000, +#else 0x00080000, +#endif 0x00000000, }; diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c index 4f4cd8b286d5..c3ab959bdc7c 100644 --- a/drivers/gpu/drm/radeon/r600_cp.c +++ b/drivers/gpu/drm/radeon/r600_cp.c @@ -396,6 +396,9 @@ static void r600_cp_load_microcode(drm_radeon_private_t *dev_priv) r600_do_cp_stop(dev_priv); RADEON_WRITE(R600_CP_RB_CNTL, +#ifdef __BIG_ENDIAN + R600_BUF_SWAP_32BIT | +#endif R600_RB_NO_UPDATE | R600_RB_BLKSZ(15) | R600_RB_BUFSZ(3)); @@ -486,9 +489,12 @@ static void r700_cp_load_microcode(drm_radeon_private_t *dev_priv) r600_do_cp_stop(dev_priv); RADEON_WRITE(R600_CP_RB_CNTL, +#ifdef __BIG_ENDIAN + R600_BUF_SWAP_32BIT | +#endif R600_RB_NO_UPDATE | - (15 << 8) | - (3 << 0)); + R600_RB_BLKSZ(15) | + R600_RB_BUFSZ(3)); RADEON_WRITE(R600_GRBM_SOFT_RESET, R600_SOFT_RESET_CP); RADEON_READ(R600_GRBM_SOFT_RESET); @@ -550,8 +556,12 @@ static void r600_test_writeback(drm_radeon_private_t *dev_priv) if (!dev_priv->writeback_works) { /* Disable writeback to avoid unnecessary bus master transfer */ - RADEON_WRITE(R600_CP_RB_CNTL, RADEON_READ(R600_CP_RB_CNTL) | - RADEON_RB_NO_UPDATE); + RADEON_WRITE(R600_CP_RB_CNTL, +#ifdef __BIG_ENDIAN + R600_BUF_SWAP_32BIT | +#endif + RADEON_READ(R600_CP_RB_CNTL) | + R600_RB_NO_UPDATE); RADEON_WRITE(R600_SCRATCH_UMSK, 0); } } @@ -575,7 +585,11 @@ int r600_do_engine_reset(struct drm_device *dev) RADEON_WRITE(R600_CP_RB_WPTR_DELAY, 0); cp_rb_cntl = RADEON_READ(R600_CP_RB_CNTL); - RADEON_WRITE(R600_CP_RB_CNTL, R600_RB_RPTR_WR_ENA); + RADEON_WRITE(R600_CP_RB_CNTL, +#ifdef __BIG_ENDIAN + R600_BUF_SWAP_32BIT | +#endif + R600_RB_RPTR_WR_ENA); RADEON_WRITE(R600_CP_RB_RPTR_WR, cp_ptr); RADEON_WRITE(R600_CP_RB_WPTR, cp_ptr); @@ -1838,7 +1852,10 @@ static void r600_cp_init_ring_buffer(struct drm_device *dev, + dev_priv->gart_vm_start; } RADEON_WRITE(R600_CP_RB_RPTR_ADDR, - rptr_addr & 0xffffffff); +#ifdef __BIG_ENDIAN + (2 << 0) | +#endif + (rptr_addr & 0xfffffffc)); RADEON_WRITE(R600_CP_RB_RPTR_ADDR_HI, upper_32_bits(rptr_addr)); @@ -1889,7 +1906,7 @@ static void r600_cp_init_ring_buffer(struct drm_device *dev, { u64 scratch_addr; - scratch_addr = RADEON_READ(R600_CP_RB_RPTR_ADDR); + scratch_addr = RADEON_READ(R600_CP_RB_RPTR_ADDR) & 0xFFFFFFFC; scratch_addr |= ((u64)RADEON_READ(R600_CP_RB_RPTR_ADDR_HI)) << 32; scratch_addr += R600_SCRATCH_REG_OFFSET; scratch_addr >>= 8; diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 7831e0890210..153095fba62f 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -295,17 +295,18 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) } if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", - __func__, __LINE__, pitch); + dev_warn(p->dev, "%s:%d cb pitch (%d, 0x%x, %d) invalid\n", + __func__, __LINE__, pitch, pitch_align, array_mode); return -EINVAL; } if (!IS_ALIGNED(height, height_align)) { - dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", - __func__, __LINE__, height); + dev_warn(p->dev, "%s:%d cb height (%d, 0x%x, %d) invalid\n", + __func__, __LINE__, height, height_align, array_mode); return -EINVAL; } if (!IS_ALIGNED(base_offset, base_align)) { - dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset); + dev_warn(p->dev, "%s offset[%d] 0x%llx 0x%llx, %d not aligned\n", __func__, i, + base_offset, base_align, array_mode); return -EINVAL; } @@ -320,7 +321,10 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) * broken userspace. */ } else { - dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i])); + dev_warn(p->dev, "%s offset[%d] %d %d %d %lu too big\n", __func__, i, + array_mode, + track->cb_color_bo_offset[i], tmp, + radeon_bo_size(track->cb_color_bo[i])); return -EINVAL; } } @@ -455,17 +459,18 @@ static int r600_cs_track_check(struct radeon_cs_parser *p) } if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n", - __func__, __LINE__, pitch); + dev_warn(p->dev, "%s:%d db pitch (%d, 0x%x, %d) invalid\n", + __func__, __LINE__, pitch, pitch_align, array_mode); return -EINVAL; } if (!IS_ALIGNED(height, height_align)) { - dev_warn(p->dev, "%s:%d db height (%d) invalid\n", - __func__, __LINE__, height); + dev_warn(p->dev, "%s:%d db height (%d, 0x%x, %d) invalid\n", + __func__, __LINE__, height, height_align, array_mode); return -EINVAL; } if (!IS_ALIGNED(base_offset, base_align)) { - dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset); + dev_warn(p->dev, "%s offset[%d] 0x%llx, 0x%llx, %d not aligned\n", __func__, i, + base_offset, base_align, array_mode); return -EINVAL; } @@ -473,9 +478,10 @@ static int r600_cs_track_check(struct radeon_cs_parser *p) nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1; tmp = ntiles * bpe * 64 * nviews; if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) { - dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %u have %lu)\n", - track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset, - radeon_bo_size(track->db_bo)); + dev_warn(p->dev, "z/stencil buffer (%d) too small (0x%08X %d %d %d -> %u have %lu)\n", + array_mode, + track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset, + radeon_bo_size(track->db_bo)); return -EINVAL; } } @@ -1227,18 +1233,18 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 i /* XXX check height as well... */ if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n", - __func__, __LINE__, pitch); + dev_warn(p->dev, "%s:%d tex pitch (%d, 0x%x, %d) invalid\n", + __func__, __LINE__, pitch, pitch_align, G_038000_TILE_MODE(word0)); return -EINVAL; } if (!IS_ALIGNED(base_offset, base_align)) { - dev_warn(p->dev, "%s:%d tex base offset (0x%llx) invalid\n", - __func__, __LINE__, base_offset); + dev_warn(p->dev, "%s:%d tex base offset (0x%llx, 0x%llx, %d) invalid\n", + __func__, __LINE__, base_offset, base_align, G_038000_TILE_MODE(word0)); return -EINVAL; } if (!IS_ALIGNED(mip_offset, base_align)) { - dev_warn(p->dev, "%s:%d tex mip offset (0x%llx) invalid\n", - __func__, __LINE__, mip_offset); + dev_warn(p->dev, "%s:%d tex mip offset (0x%llx, 0x%llx, %d) invalid\n", + __func__, __LINE__, mip_offset, base_align, G_038000_TILE_MODE(word0)); return -EINVAL; } diff --git a/drivers/gpu/drm/radeon/r600_reg.h b/drivers/gpu/drm/radeon/r600_reg.h index 33cda016b083..f869897c7456 100644 --- a/drivers/gpu/drm/radeon/r600_reg.h +++ b/drivers/gpu/drm/radeon/r600_reg.h @@ -81,7 +81,11 @@ #define R600_MEDIUM_VID_LOWER_GPIO_CNTL 0x720 #define R600_LOW_VID_LOWER_GPIO_CNTL 0x724 - +#define R600_D1GRPH_SWAP_CONTROL 0x610C +# define R600_D1GRPH_SWAP_ENDIAN_NONE (0 << 0) +# define R600_D1GRPH_SWAP_ENDIAN_16BIT (1 << 0) +# define R600_D1GRPH_SWAP_ENDIAN_32BIT (2 << 0) +# define R600_D1GRPH_SWAP_ENDIAN_64BIT (3 << 0) #define R600_HDP_NONSURFACE_BASE 0x2c04 diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index a5d898b4bad2..04bac0bbd3ec 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -154,13 +154,14 @@ #define ROQ_IB2_START(x) ((x) << 8) #define CP_RB_BASE 0xC100 #define CP_RB_CNTL 0xC104 -#define RB_BUFSZ(x) ((x)<<0) -#define RB_BLKSZ(x) ((x)<<8) -#define RB_NO_UPDATE (1<<27) -#define RB_RPTR_WR_ENA (1<<31) +#define RB_BUFSZ(x) ((x) << 0) +#define RB_BLKSZ(x) ((x) << 8) +#define RB_NO_UPDATE (1 << 27) +#define RB_RPTR_WR_ENA (1 << 31) #define BUF_SWAP_32BIT (2 << 16) #define CP_RB_RPTR 0x8700 #define CP_RB_RPTR_ADDR 0xC10C +#define RB_RPTR_SWAP(x) ((x) << 0) #define CP_RB_RPTR_ADDR_HI 0xC110 #define CP_RB_RPTR_WR 0xC108 #define CP_RB_WPTR 0xC114 diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 71d2a554bbe6..56c48b67ef3d 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -179,10 +179,10 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev); void radeon_atombios_get_power_modes(struct radeon_device *rdev); void radeon_atom_set_voltage(struct radeon_device *rdev, u16 level); void rs690_pm_info(struct radeon_device *rdev); -extern u32 rv6xx_get_temp(struct radeon_device *rdev); -extern u32 rv770_get_temp(struct radeon_device *rdev); -extern u32 evergreen_get_temp(struct radeon_device *rdev); -extern u32 sumo_get_temp(struct radeon_device *rdev); +extern int rv6xx_get_temp(struct radeon_device *rdev); +extern int rv770_get_temp(struct radeon_device *rdev); +extern int evergreen_get_temp(struct radeon_device *rdev); +extern int sumo_get_temp(struct radeon_device *rdev); /* * Fences. @@ -812,8 +812,7 @@ struct radeon_pm { fixed20_12 sclk; fixed20_12 mclk; fixed20_12 needed_bandwidth; - /* XXX: use a define for num power modes */ - struct radeon_power_state power_state[8]; + struct radeon_power_state *power_state; /* number of valid power states */ int num_power_states; int current_power_state_index; diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 3a1b16186224..e75d63b8e21d 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -759,7 +759,7 @@ static struct radeon_asic evergreen_asic = { .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush, .gart_set_page = &rs600_gart_set_page, .ring_test = &r600_ring_test, - .ring_ib_execute = &r600_ring_ib_execute, + .ring_ib_execute = &evergreen_ring_ib_execute, .irq_set = &evergreen_irq_set, .irq_process = &evergreen_irq_process, .get_vblank_counter = &evergreen_get_vblank_counter, @@ -805,7 +805,7 @@ static struct radeon_asic sumo_asic = { .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush, .gart_set_page = &rs600_gart_set_page, .ring_test = &r600_ring_test, - .ring_ib_execute = &r600_ring_ib_execute, + .ring_ib_execute = &evergreen_ring_ib_execute, .irq_set = &evergreen_irq_set, .irq_process = &evergreen_irq_process, .get_vblank_counter = &evergreen_get_vblank_counter, @@ -848,7 +848,7 @@ static struct radeon_asic btc_asic = { .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush, .gart_set_page = &rs600_gart_set_page, .ring_test = &r600_ring_test, - .ring_ib_execute = &r600_ring_ib_execute, + .ring_ib_execute = &evergreen_ring_ib_execute, .irq_set = &evergreen_irq_set, .irq_process = &evergreen_irq_process, .get_vblank_counter = &evergreen_get_vblank_counter, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index e01f07718539..c59bd98a2029 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -355,6 +355,7 @@ int evergreen_resume(struct radeon_device *rdev); bool evergreen_gpu_is_lockup(struct radeon_device *rdev); int evergreen_asic_reset(struct radeon_device *rdev); void evergreen_bandwidth_update(struct radeon_device *rdev); +void evergreen_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); int evergreen_copy_blit(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_pages, struct radeon_fence *fence); diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 1573202a6418..02d5c415f499 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -88,7 +88,7 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_dev /* some evergreen boards have bad data for this entry */ if (ASIC_IS_DCE4(rdev)) { if ((i == 7) && - (gpio->usClkMaskRegisterIndex == 0x1936) && + (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1936) && (gpio->sucI2cId.ucAccess == 0)) { gpio->sucI2cId.ucAccess = 0x97; gpio->ucDataMaskShift = 8; @@ -101,7 +101,7 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_dev /* some DCE3 boards have bad data for this entry */ if (ASIC_IS_DCE3(rdev)) { if ((i == 4) && - (gpio->usClkMaskRegisterIndex == 0x1fda) && + (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1fda) && (gpio->sucI2cId.ucAccess == 0x94)) gpio->sucI2cId.ucAccess = 0x14; } @@ -172,7 +172,7 @@ void radeon_atombios_i2c_init(struct radeon_device *rdev) /* some evergreen boards have bad data for this entry */ if (ASIC_IS_DCE4(rdev)) { if ((i == 7) && - (gpio->usClkMaskRegisterIndex == 0x1936) && + (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1936) && (gpio->sucI2cId.ucAccess == 0)) { gpio->sucI2cId.ucAccess = 0x97; gpio->ucDataMaskShift = 8; @@ -185,7 +185,7 @@ void radeon_atombios_i2c_init(struct radeon_device *rdev) /* some DCE3 boards have bad data for this entry */ if (ASIC_IS_DCE3(rdev)) { if ((i == 4) && - (gpio->usClkMaskRegisterIndex == 0x1fda) && + (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1fda) && (gpio->sucI2cId.ucAccess == 0x94)) gpio->sucI2cId.ucAccess = 0x14; } @@ -252,7 +252,7 @@ static inline struct radeon_gpio_rec radeon_lookup_gpio(struct radeon_device *rd pin = &gpio_info->asGPIO_Pin[i]; if (id == pin->ucGPIO_ID) { gpio.id = pin->ucGPIO_ID; - gpio.reg = pin->usGpioPin_AIndex * 4; + gpio.reg = le16_to_cpu(pin->usGpioPin_AIndex) * 4; gpio.mask = (1 << pin->ucGpioPinBitShift); gpio.valid = true; break; @@ -387,15 +387,11 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, *line_mux = 0x90; } - /* mac rv630 */ - if ((dev->pdev->device == 0x9588) && - (dev->pdev->subsystem_vendor == 0x106b) && - (dev->pdev->subsystem_device == 0x00a6)) { - if ((supported_device == ATOM_DEVICE_TV1_SUPPORT) && - (*connector_type == DRM_MODE_CONNECTOR_DVII)) { - *connector_type = DRM_MODE_CONNECTOR_9PinDIN; - *line_mux = CONNECTOR_7PIN_DIN_ENUM_ID1; - } + /* mac rv630, rv730, others */ + if ((supported_device == ATOM_DEVICE_TV1_SUPPORT) && + (*connector_type == DRM_MODE_CONNECTOR_DVII)) { + *connector_type = DRM_MODE_CONNECTOR_9PinDIN; + *line_mux = CONNECTOR_7PIN_DIN_ENUM_ID1; } /* ASUS HD 3600 XT board lists the DVI port as HDMI */ @@ -1167,16 +1163,6 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) p1pll->pll_out_min = 64800; else p1pll->pll_out_min = 20000; - } else if (p1pll->pll_out_min > 64800) { - /* Limiting the pll output range is a good thing generally as - * it limits the number of possible pll combinations for a given - * frequency presumably to the ones that work best on each card. - * However, certain duallink DVI monitors seem to like - * pll combinations that would be limited by this at least on - * pre-DCE 3.0 r6xx hardware. This might need to be adjusted per - * family. - */ - p1pll->pll_out_min = 64800; } p1pll->pll_in_min = @@ -1288,11 +1274,11 @@ bool radeon_atombios_sideport_present(struct radeon_device *rdev) data_offset); switch (crev) { case 1: - if (igp_info->info.ulBootUpMemoryClock) + if (le32_to_cpu(igp_info->info.ulBootUpMemoryClock)) return true; break; case 2: - if (igp_info->info_2.ulBootUpSidePortClock) + if (le32_to_cpu(igp_info->info_2.ulBootUpSidePortClock)) return true; break; default: @@ -1456,7 +1442,7 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev, for (i = 0; i < num_indices; i++) { if ((ss_info->info.asSpreadSpectrum[i].ucClockIndication == id) && - (clock <= ss_info->info.asSpreadSpectrum[i].ulTargetClockRange)) { + (clock <= le32_to_cpu(ss_info->info.asSpreadSpectrum[i].ulTargetClockRange))) { ss->percentage = le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadSpectrumPercentage); ss->type = ss_info->info.asSpreadSpectrum[i].ucSpreadSpectrumMode; @@ -1470,7 +1456,7 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev, sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2); for (i = 0; i < num_indices; i++) { if ((ss_info->info_2.asSpreadSpectrum[i].ucClockIndication == id) && - (clock <= ss_info->info_2.asSpreadSpectrum[i].ulTargetClockRange)) { + (clock <= le32_to_cpu(ss_info->info_2.asSpreadSpectrum[i].ulTargetClockRange))) { ss->percentage = le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadSpectrumPercentage); ss->type = ss_info->info_2.asSpreadSpectrum[i].ucSpreadSpectrumMode; @@ -1484,7 +1470,7 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev, sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3); for (i = 0; i < num_indices; i++) { if ((ss_info->info_3.asSpreadSpectrum[i].ucClockIndication == id) && - (clock <= ss_info->info_3.asSpreadSpectrum[i].ulTargetClockRange)) { + (clock <= le32_to_cpu(ss_info->info_3.asSpreadSpectrum[i].ulTargetClockRange))) { ss->percentage = le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadSpectrumPercentage); ss->type = ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode; @@ -1567,8 +1553,8 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct if (misc & ATOM_DOUBLE_CLOCK_MODE) lvds->native_mode.flags |= DRM_MODE_FLAG_DBLSCAN; - lvds->native_mode.width_mm = lvds_info->info.sLCDTiming.usImageHSize; - lvds->native_mode.height_mm = lvds_info->info.sLCDTiming.usImageVSize; + lvds->native_mode.width_mm = le16_to_cpu(lvds_info->info.sLCDTiming.usImageHSize); + lvds->native_mode.height_mm = le16_to_cpu(lvds_info->info.sLCDTiming.usImageVSize); /* set crtc values */ drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V); @@ -1583,13 +1569,13 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct lvds->linkb = false; /* parse the lcd record table */ - if (lvds_info->info.usModePatchTableOffset) { + if (le16_to_cpu(lvds_info->info.usModePatchTableOffset)) { ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record; ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record; bool bad_record = false; u8 *record = (u8 *)(mode_info->atom_context->bios + data_offset + - lvds_info->info.usModePatchTableOffset); + le16_to_cpu(lvds_info->info.usModePatchTableOffset)); while (*record != ATOM_RECORD_END_TYPE) { switch (*record) { case LCD_MODE_PATCH_RECORD_MODE_TYPE: @@ -1991,6 +1977,9 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) num_modes = power_info->info.ucNumOfPowerModeEntries; if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK) num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK; + rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * num_modes, GFP_KERNEL); + if (!rdev->pm.power_state) + return state_index; /* last mode is usually default, array is low to high */ for (i = 0; i < num_modes; i++) { rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; @@ -2200,7 +2189,7 @@ static u16 radeon_atombios_get_default_vddc(struct radeon_device *rdev) firmware_info = (union firmware_info *)(mode_info->atom_context->bios + data_offset); - vddc = firmware_info->info_14.usBootUpVDDCVoltage; + vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage); } return vddc; @@ -2295,7 +2284,7 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev, rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = VOLTAGE_SW; rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = - clock_info->evergreen.usVDDC; + le16_to_cpu(clock_info->evergreen.usVDDC); } else { sclk = le16_to_cpu(clock_info->r600.usEngineClockLow); sclk |= clock_info->r600.ucEngineClockHigh << 16; @@ -2306,7 +2295,7 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev, rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = VOLTAGE_SW; rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = - clock_info->r600.usVDDC; + le16_to_cpu(clock_info->r600.usVDDC); } if (rdev->flags & RADEON_IS_IGP) { @@ -2342,6 +2331,10 @@ static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev) power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController); + rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * + power_info->pplib.ucNumStates, GFP_KERNEL); + if (!rdev->pm.power_state) + return state_index; /* first mode is usually default, followed by low to high */ for (i = 0; i < power_info->pplib.ucNumStates; i++) { mode_index = 0; @@ -2415,13 +2408,17 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController); state_array = (struct StateArray *) (mode_info->atom_context->bios + data_offset + - power_info->pplib.usStateArrayOffset); + le16_to_cpu(power_info->pplib.usStateArrayOffset)); clock_info_array = (struct ClockInfoArray *) (mode_info->atom_context->bios + data_offset + - power_info->pplib.usClockInfoArrayOffset); + le16_to_cpu(power_info->pplib.usClockInfoArrayOffset)); non_clock_info_array = (struct NonClockInfoArray *) (mode_info->atom_context->bios + data_offset + - power_info->pplib.usNonClockInfoArrayOffset); + le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); + rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * + state_array->ucNumEntries, GFP_KERNEL); + if (!rdev->pm.power_state) + return state_index; for (i = 0; i < state_array->ucNumEntries; i++) { mode_index = 0; power_state = (union pplib_power_state *)&state_array->states[i]; @@ -2495,19 +2492,22 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) break; } } else { - /* add the default mode */ - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_DEFAULT; - rdev->pm.power_state[state_index].num_clock_modes = 1; - rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk; - rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk; - rdev->pm.power_state[state_index].default_clock_mode = - &rdev->pm.power_state[state_index].clock_info[0]; - rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; - rdev->pm.power_state[state_index].pcie_lanes = 16; - rdev->pm.default_power_state_index = state_index; - rdev->pm.power_state[state_index].flags = 0; - state_index++; + rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state), GFP_KERNEL); + if (rdev->pm.power_state) { + /* add the default mode */ + rdev->pm.power_state[state_index].type = + POWER_STATE_TYPE_DEFAULT; + rdev->pm.power_state[state_index].num_clock_modes = 1; + rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk; + rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk; + rdev->pm.power_state[state_index].default_clock_mode = + &rdev->pm.power_state[state_index].clock_info[0]; + rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; + rdev->pm.power_state[state_index].pcie_lanes = 16; + rdev->pm.default_power_state_index = state_index; + rdev->pm.power_state[state_index].flags = 0; + state_index++; + } } rdev->pm.num_power_states = state_index; @@ -2533,7 +2533,7 @@ uint32_t radeon_atom_get_engine_clock(struct radeon_device *rdev) int index = GetIndexIntoMasterTable(COMMAND, GetEngineClock); atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - return args.ulReturnEngineClock; + return le32_to_cpu(args.ulReturnEngineClock); } uint32_t radeon_atom_get_memory_clock(struct radeon_device *rdev) @@ -2542,7 +2542,7 @@ uint32_t radeon_atom_get_memory_clock(struct radeon_device *rdev) int index = GetIndexIntoMasterTable(COMMAND, GetMemoryClock); atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - return args.ulReturnMemoryClock; + return le32_to_cpu(args.ulReturnMemoryClock); } void radeon_atom_set_engine_clock(struct radeon_device *rdev, @@ -2551,7 +2551,7 @@ void radeon_atom_set_engine_clock(struct radeon_device *rdev, SET_ENGINE_CLOCK_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, SetEngineClock); - args.ulTargetEngineClock = eng_clock; /* 10 khz */ + args.ulTargetEngineClock = cpu_to_le32(eng_clock); /* 10 khz */ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } @@ -2565,7 +2565,7 @@ void radeon_atom_set_memory_clock(struct radeon_device *rdev, if (rdev->flags & RADEON_IS_IGP) return; - args.ulTargetMemoryClock = mem_clock; /* 10 khz */ + args.ulTargetMemoryClock = cpu_to_le32(mem_clock); /* 10 khz */ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } @@ -2623,7 +2623,7 @@ void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev) bios_2_scratch &= ~ATOM_S2_VRI_BRIGHT_ENABLE; /* tell the bios not to handle mode switching */ - bios_6_scratch |= (ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH | ATOM_S6_ACC_MODE); + bios_6_scratch |= ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH; if (rdev->family >= CHIP_R600) { WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch); @@ -2674,10 +2674,13 @@ void radeon_atom_output_lock(struct drm_encoder *encoder, bool lock) else bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH); - if (lock) + if (lock) { bios_6_scratch |= ATOM_S6_CRITICAL_STATE; - else + bios_6_scratch &= ~ATOM_S6_ACC_MODE; + } else { bios_6_scratch &= ~ATOM_S6_CRITICAL_STATE; + bios_6_scratch |= ATOM_S6_ACC_MODE; + } if (rdev->family >= CHIP_R600) WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch); diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 591fcae8f224..cf7c8d5b4ec2 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -1504,6 +1504,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) (rdev->pdev->subsystem_device == 0x4a48)) { /* Mac X800 */ rdev->mode_info.connector_table = CT_MAC_X800; + } else if ((rdev->pdev->device == 0x4150) && + (rdev->pdev->subsystem_vendor == 0x1002) && + (rdev->pdev->subsystem_device == 0x4150)) { + /* Mac G5 9600 */ + rdev->mode_info.connector_table = CT_MAC_G5_9600; } else #endif /* CONFIG_PPC_PMAC */ #ifdef CONFIG_PPC64 @@ -2022,6 +2027,48 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I, &hpd); break; + case CT_MAC_G5_9600: + DRM_INFO("Connector Table: %d (mac g5 9600)\n", + rdev->mode_info.connector_table); + /* DVI - tv dac, dvo */ + ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0); + hpd.hpd = RADEON_HPD_1; /* ??? */ + radeon_add_legacy_encoder(dev, + radeon_get_encoder_enum(dev, + ATOM_DEVICE_DFP2_SUPPORT, + 0), + ATOM_DEVICE_DFP2_SUPPORT); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_enum(dev, + ATOM_DEVICE_CRT2_SUPPORT, + 2), + ATOM_DEVICE_CRT2_SUPPORT); + radeon_add_legacy_connector(dev, 0, + ATOM_DEVICE_DFP2_SUPPORT | + ATOM_DEVICE_CRT2_SUPPORT, + DRM_MODE_CONNECTOR_DVII, &ddc_i2c, + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I, + &hpd); + /* ADC - primary dac, internal tmds */ + ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); + hpd.hpd = RADEON_HPD_2; /* ??? */ + radeon_add_legacy_encoder(dev, + radeon_get_encoder_enum(dev, + ATOM_DEVICE_DFP1_SUPPORT, + 0), + ATOM_DEVICE_DFP1_SUPPORT); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_enum(dev, + ATOM_DEVICE_CRT1_SUPPORT, + 1), + ATOM_DEVICE_CRT1_SUPPORT); + radeon_add_legacy_connector(dev, 1, + ATOM_DEVICE_DFP1_SUPPORT | + ATOM_DEVICE_CRT1_SUPPORT, + DRM_MODE_CONNECTOR_DVII, &ddc_i2c, + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I, + &hpd); + break; default: DRM_INFO("Connector table: %d (invalid)\n", rdev->mode_info.connector_table); @@ -2442,6 +2489,17 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) rdev->pm.default_power_state_index = -1; + /* allocate 2 power states */ + rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * 2, GFP_KERNEL); + if (!rdev->pm.power_state) { + rdev->pm.default_power_state_index = state_index; + rdev->pm.num_power_states = 0; + + rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; + rdev->pm.current_clock_mode_index = 0; + return; + } + if (rdev->flags & RADEON_IS_MOBILITY) { offset = combios_get_table_offset(dev, COMBIOS_POWERPLAY_INFO_TABLE); if (offset) { diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 26091d602b84..4954e2d6ffa2 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -891,9 +891,9 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) pci_disable_device(dev->pdev); pci_set_power_state(dev->pdev, PCI_D3hot); } - acquire_console_sem(); + console_lock(); radeon_fbdev_set_suspend(rdev, 1); - release_console_sem(); + console_unlock(); return 0; } @@ -905,11 +905,11 @@ int radeon_resume_kms(struct drm_device *dev) if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; - acquire_console_sem(); + console_lock(); pci_set_power_state(dev->pdev, PCI_D0); pci_restore_state(dev->pdev); if (pci_enable_device(dev->pdev)) { - release_console_sem(); + console_unlock(); return -1; } pci_set_master(dev->pdev); @@ -920,7 +920,7 @@ int radeon_resume_kms(struct drm_device *dev) radeon_restore_bios_scratch_regs(rdev); radeon_fbdev_set_suspend(rdev, 0); - release_console_sem(); + console_unlock(); /* reset hpd state */ radeon_hpd_init(rdev); @@ -936,8 +936,11 @@ int radeon_resume_kms(struct drm_device *dev) int radeon_gpu_reset(struct radeon_device *rdev) { int r; + int resched; radeon_save_bios_scratch_regs(rdev); + /* block TTM */ + resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); radeon_suspend(rdev); r = radeon_asic_reset(rdev); @@ -946,6 +949,7 @@ int radeon_gpu_reset(struct radeon_device *rdev) radeon_resume(rdev); radeon_restore_bios_scratch_regs(rdev); drm_helper_resume_force_mode(rdev->ddev); + ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); return 0; } /* bad news, how to tell it to userspace ? */ diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index d26dabf878d9..0e657095de7c 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -780,6 +780,125 @@ static int radeon_ddc_dump(struct drm_connector *connector) return ret; } +/* avivo */ +static void avivo_get_fb_div(struct radeon_pll *pll, + u32 target_clock, + u32 post_div, + u32 ref_div, + u32 *fb_div, + u32 *frac_fb_div) +{ + u32 tmp = post_div * ref_div; + + tmp *= target_clock; + *fb_div = tmp / pll->reference_freq; + *frac_fb_div = tmp % pll->reference_freq; + + if (*fb_div > pll->max_feedback_div) + *fb_div = pll->max_feedback_div; + else if (*fb_div < pll->min_feedback_div) + *fb_div = pll->min_feedback_div; +} + +static u32 avivo_get_post_div(struct radeon_pll *pll, + u32 target_clock) +{ + u32 vco, post_div, tmp; + + if (pll->flags & RADEON_PLL_USE_POST_DIV) + return pll->post_div; + + if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) { + if (pll->flags & RADEON_PLL_IS_LCD) + vco = pll->lcd_pll_out_min; + else + vco = pll->pll_out_min; + } else { + if (pll->flags & RADEON_PLL_IS_LCD) + vco = pll->lcd_pll_out_max; + else + vco = pll->pll_out_max; + } + + post_div = vco / target_clock; + tmp = vco % target_clock; + + if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) { + if (tmp) + post_div++; + } else { + if (!tmp) + post_div--; + } + + if (post_div > pll->max_post_div) + post_div = pll->max_post_div; + else if (post_div < pll->min_post_div) + post_div = pll->min_post_div; + + return post_div; +} + +#define MAX_TOLERANCE 10 + +void radeon_compute_pll_avivo(struct radeon_pll *pll, + u32 freq, + u32 *dot_clock_p, + u32 *fb_div_p, + u32 *frac_fb_div_p, + u32 *ref_div_p, + u32 *post_div_p) +{ + u32 target_clock = freq / 10; + u32 post_div = avivo_get_post_div(pll, target_clock); + u32 ref_div = pll->min_ref_div; + u32 fb_div = 0, frac_fb_div = 0, tmp; + + if (pll->flags & RADEON_PLL_USE_REF_DIV) + ref_div = pll->reference_div; + + if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { + avivo_get_fb_div(pll, target_clock, post_div, ref_div, &fb_div, &frac_fb_div); + frac_fb_div = (100 * frac_fb_div) / pll->reference_freq; + if (frac_fb_div >= 5) { + frac_fb_div -= 5; + frac_fb_div = frac_fb_div / 10; + frac_fb_div++; + } + if (frac_fb_div >= 10) { + fb_div++; + frac_fb_div = 0; + } + } else { + while (ref_div <= pll->max_ref_div) { + avivo_get_fb_div(pll, target_clock, post_div, ref_div, + &fb_div, &frac_fb_div); + if (frac_fb_div >= (pll->reference_freq / 2)) + fb_div++; + frac_fb_div = 0; + tmp = (pll->reference_freq * fb_div) / (post_div * ref_div); + tmp = (tmp * 10000) / target_clock; + + if (tmp > (10000 + MAX_TOLERANCE)) + ref_div++; + else if (tmp >= (10000 - MAX_TOLERANCE)) + break; + else + ref_div++; + } + } + + *dot_clock_p = ((pll->reference_freq * fb_div * 10) + (pll->reference_freq * frac_fb_div)) / + (ref_div * post_div * 10); + *fb_div_p = fb_div; + *frac_fb_div_p = frac_fb_div; + *ref_div_p = ref_div; + *post_div_p = post_div; + DRM_DEBUG_KMS("%d, pll dividers - fb: %d.%d ref: %d, post %d\n", + *dot_clock_p, fb_div, frac_fb_div, ref_div, post_div); +} + +/* pre-avivo */ static inline uint32_t radeon_div(uint64_t n, uint32_t d) { uint64_t mod; @@ -790,13 +909,13 @@ static inline uint32_t radeon_div(uint64_t n, uint32_t d) return n; } -void radeon_compute_pll(struct radeon_pll *pll, - uint64_t freq, - uint32_t *dot_clock_p, - uint32_t *fb_div_p, - uint32_t *frac_fb_div_p, - uint32_t *ref_div_p, - uint32_t *post_div_p) +void radeon_compute_pll_legacy(struct radeon_pll *pll, + uint64_t freq, + uint32_t *dot_clock_p, + uint32_t *fb_div_p, + uint32_t *frac_fb_div_p, + uint32_t *ref_div_p, + uint32_t *post_div_p) { uint32_t min_ref_div = pll->min_ref_div; uint32_t max_ref_div = pll->max_ref_div; @@ -826,6 +945,9 @@ void radeon_compute_pll(struct radeon_pll *pll, pll_out_max = pll->pll_out_max; } + if (pll_out_min > 64800) + pll_out_min = 64800; + if (pll->flags & RADEON_PLL_USE_REF_DIV) min_ref_div = max_ref_div = pll->reference_div; else { @@ -849,7 +971,7 @@ void radeon_compute_pll(struct radeon_pll *pll, max_fractional_feed_div = pll->max_frac_feedback_div; } - for (post_div = max_post_div; post_div >= min_post_div; --post_div) { + for (post_div = min_post_div; post_div <= max_post_div; ++post_div) { uint32_t ref_div; if ((pll->flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1)) @@ -965,6 +1087,10 @@ void radeon_compute_pll(struct radeon_pll *pll, *frac_fb_div_p = best_frac_feedback_div; *ref_div_p = best_ref_div; *post_div_p = best_post_div; + DRM_DEBUG_KMS("%d %d, pll dividers - fb: %d.%d ref: %d, post %d\n", + freq, best_freq / 1000, best_feedback_div, best_frac_feedback_div, + best_ref_div, best_post_div); + } static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index d5680a0c87af..275b26a708d6 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -48,7 +48,7 @@ * - 2.5.0 - add get accel 2 to work around ddx breakage for evergreen * - 2.6.0 - add tiling config query (r6xx+), add initial HiZ support (r300->r500) * 2.7.0 - fixups for r600 2D tiling support. (no external ABI change), add eg dyn gpr regs - * 2.8.0 - pageflip support, r500 US_FORMAT regs. r500 ARGB2101010 colorbuf, r300->r500 CMASK + * 2.8.0 - pageflip support, r500 US_FORMAT regs. r500 ARGB2101010 colorbuf, r300->r500 CMASK, clock crystal query */ #define KMS_DRIVER_MAJOR 2 #define KMS_DRIVER_MINOR 8 diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h index 448eba89d1e6..5cba46b9779a 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.h +++ b/drivers/gpu/drm/radeon/radeon_drv.h @@ -1524,6 +1524,7 @@ extern u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index); #define R600_CP_RB_CNTL 0xc104 # define R600_RB_BUFSZ(x) ((x) << 0) # define R600_RB_BLKSZ(x) ((x) << 8) +# define R600_BUF_SWAP_32BIT (2 << 16) # define R600_RB_NO_UPDATE (1 << 27) # define R600_RB_RPTR_WR_ENA (1 << 31) #define R600_CP_RB_RPTR_WR 0xc108 diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 8fd184286c0b..b4274883227f 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -641,7 +641,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) switch (connector->connector_type) { case DRM_MODE_CONNECTOR_DVII: case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */ - if (drm_detect_monitor_audio(radeon_connector->edid)) { + if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) { /* fix me */ if (ASIC_IS_DCE4(rdev)) return ATOM_ENCODER_MODE_DVI; @@ -655,7 +655,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) case DRM_MODE_CONNECTOR_DVID: case DRM_MODE_CONNECTOR_HDMIA: default: - if (drm_detect_monitor_audio(radeon_connector->edid)) { + if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) { /* fix me */ if (ASIC_IS_DCE4(rdev)) return ATOM_ENCODER_MODE_DVI; @@ -673,7 +673,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) return ATOM_ENCODER_MODE_DP; - else if (drm_detect_monitor_audio(radeon_connector->edid)) { + else if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) { /* fix me */ if (ASIC_IS_DCE4(rdev)) return ATOM_ENCODER_MODE_DVI; @@ -910,7 +910,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t args.v1.ucAction = action; if (action == ATOM_TRANSMITTER_ACTION_INIT) { - args.v1.usInitInfo = connector_object_id; + args.v1.usInitInfo = cpu_to_le16(connector_object_id); } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { args.v1.asMode.ucLaneSel = lane_num; args.v1.asMode.ucLaneSet = lane_set; @@ -1063,7 +1063,7 @@ atombios_set_edp_panel_power(struct drm_connector *connector, int action) if (!ASIC_IS_DCE4(rdev)) return; - if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) || + if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) && (action != ATOM_TRANSMITTER_ACTION_POWER_OFF)) return; @@ -1140,7 +1140,7 @@ atombios_external_encoder_setup(struct drm_encoder *encoder, case 3: args.v3.sExtEncoder.ucAction = action; if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT) - args.v3.sExtEncoder.usConnectorId = connector_object_id; + args.v3.sExtEncoder.usConnectorId = cpu_to_le16(connector_object_id); else args.v3.sExtEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); args.v3.sExtEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); @@ -1570,11 +1570,21 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder, } /* set scaler clears this on some chips */ - /* XXX check DCE4 */ - if (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))) { - if (ASIC_IS_AVIVO(rdev) && (mode->flags & DRM_MODE_FLAG_INTERLACE)) - WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, - AVIVO_D1MODE_INTERLEAVE_EN); + if (ASIC_IS_AVIVO(rdev) && + (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)))) { + if (ASIC_IS_DCE4(rdev)) { + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, + EVERGREEN_INTERLEAVE_EN); + else + WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0); + } else { + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, + AVIVO_D1MODE_INTERLEAVE_EN); + else + WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0); + } } } diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index a289646e8aa4..9ec830c77af0 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -110,11 +110,14 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev) int radeon_irq_kms_init(struct radeon_device *rdev) { + int i; int r = 0; INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func); spin_lock_init(&rdev->irq.sw_lock); + for (i = 0; i < rdev->num_crtc; i++) + spin_lock_init(&rdev->irq.pflip_lock[i]); r = drm_vblank_init(rdev->ddev, rdev->num_crtc); if (r) { return r; diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 28a53e4a925f..8387d32caaa7 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -201,6 +201,10 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) } radeon_set_filp_rights(dev, &rdev->cmask_filp, filp, &value); break; + case RADEON_INFO_CLOCK_CRYSTAL_FREQ: + /* return clock value in KHz */ + value = rdev->clock.spll.reference_freq * 10; + break; default: DRM_DEBUG_KMS("Invalid request %d\n", info->request); return -EINVAL; @@ -243,6 +247,8 @@ void radeon_driver_preclose_kms(struct drm_device *dev, struct radeon_device *rdev = dev->dev_private; if (rdev->hyperz_filp == file_priv) rdev->hyperz_filp = NULL; + if (rdev->cmask_filp == file_priv) + rdev->cmask_filp = NULL; } /* diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index ace2e6384d40..cf0638c3b7c7 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -778,9 +778,9 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) DRM_DEBUG_KMS("\n"); if (!use_bios_divs) { - radeon_compute_pll(pll, mode->clock, - &freq, &feedback_div, &frac_fb_div, - &reference_div, &post_divider); + radeon_compute_pll_legacy(pll, mode->clock, + &freq, &feedback_div, &frac_fb_div, + &reference_div, &post_divider); for (post_div = &post_divs[0]; post_div->divider; ++post_div) { if (post_div->divider == post_divider) diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 12bdeab91c86..a670caaee29e 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -149,6 +149,7 @@ struct radeon_tmds_pll { #define RADEON_PLL_PREFER_CLOSEST_LOWER (1 << 11) #define RADEON_PLL_USE_POST_DIV (1 << 12) #define RADEON_PLL_IS_LCD (1 << 13) +#define RADEON_PLL_PREFER_MINM_OVER_MAXP (1 << 14) struct radeon_pll { /* reference frequency */ @@ -208,6 +209,7 @@ enum radeon_connector_table { CT_EMAC, CT_RN50_POWER, CT_MAC_X800, + CT_MAC_G5_9600, }; enum radeon_dvo_chip { @@ -510,13 +512,21 @@ extern bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev, struct radeon_atom_ss *ss, int id, u32 clock); -extern void radeon_compute_pll(struct radeon_pll *pll, - uint64_t freq, - uint32_t *dot_clock_p, - uint32_t *fb_div_p, - uint32_t *frac_fb_div_p, - uint32_t *ref_div_p, - uint32_t *post_div_p); +extern void radeon_compute_pll_legacy(struct radeon_pll *pll, + uint64_t freq, + uint32_t *dot_clock_p, + uint32_t *fb_div_p, + uint32_t *frac_fb_div_p, + uint32_t *ref_div_p, + uint32_t *post_div_p); + +extern void radeon_compute_pll_avivo(struct radeon_pll *pll, + u32 freq, + u32 *dot_clock_p, + u32 *fb_div_p, + u32 *frac_fb_div_p, + u32 *ref_div_p, + u32 *post_div_p); extern void radeon_setup_encoder_clones(struct drm_device *dev); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 3b1b2bf9cdd5..2aed03bde4b2 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -430,7 +430,7 @@ static ssize_t radeon_hwmon_show_temp(struct device *dev, { struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); struct radeon_device *rdev = ddev->dev_private; - u32 temp; + int temp; switch (rdev->pm.int_thermal_type) { case THERMAL_TYPE_RV6XX: @@ -646,6 +646,9 @@ void radeon_pm_fini(struct radeon_device *rdev) #endif } + if (rdev->pm.power_state) + kfree(rdev->pm.power_state); + radeon_hwmon_fini(rdev); } diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index 3cd4dace57c7..ec93a75369e6 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -375,6 +375,8 @@ #define RADEON_CONFIG_APER_SIZE 0x0108 #define RADEON_CONFIG_BONDS 0x00e8 #define RADEON_CONFIG_CNTL 0x00e0 +# define RADEON_CFG_VGA_RAM_EN (1 << 8) +# define RADEON_CFG_VGA_IO_DIS (1 << 9) # define RADEON_CFG_ATI_REV_A11 (0 << 16) # define RADEON_CFG_ATI_REV_A12 (1 << 16) # define RADEON_CFG_ATI_REV_A13 (2 << 16) diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 1272e4b6a1d4..e5b2cf10cbf4 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -787,9 +787,9 @@ static int radeon_ttm_debugfs_init(struct radeon_device *rdev) radeon_mem_types_list[i].show = &radeon_mm_dump_table; radeon_mem_types_list[i].driver_features = 0; if (i == 0) - radeon_mem_types_list[i].data = &rdev->mman.bdev.man[TTM_PL_VRAM].priv; + radeon_mem_types_list[i].data = rdev->mman.bdev.man[TTM_PL_VRAM].priv; else - radeon_mem_types_list[i].data = &rdev->mman.bdev.man[TTM_PL_TT].priv; + radeon_mem_types_list[i].data = rdev->mman.bdev.man[TTM_PL_TT].priv; } /* Add ttm page pool to debugfs */ diff --git a/drivers/gpu/drm/radeon/reg_srcs/r300 b/drivers/gpu/drm/radeon/reg_srcs/r300 index b506ec1cab4b..e8a1786b6426 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/r300 +++ b/drivers/gpu/drm/radeon/reg_srcs/r300 @@ -683,9 +683,7 @@ r300 0x4f60 0x4DF4 US_ALU_CONST_G_31 0x4DF8 US_ALU_CONST_B_31 0x4DFC US_ALU_CONST_A_31 -0x4E04 RB3D_BLENDCNTL_R3 0x4E08 RB3D_ABLENDCNTL_R3 -0x4E0C RB3D_COLOR_CHANNEL_MASK 0x4E10 RB3D_CONSTANT_COLOR 0x4E14 RB3D_COLOR_CLEAR_VALUE 0x4E18 RB3D_ROPCNTL_R3 @@ -706,13 +704,11 @@ r300 0x4f60 0x4E74 RB3D_CMASK_WRINDEX 0x4E78 RB3D_CMASK_DWORD 0x4E7C RB3D_CMASK_RDINDEX -0x4E80 RB3D_AARESOLVE_OFFSET -0x4E84 RB3D_AARESOLVE_PITCH -0x4E88 RB3D_AARESOLVE_CTL 0x4EA0 RB3D_DISCARD_SRC_PIXEL_LTE_THRESHOLD 0x4EA4 RB3D_DISCARD_SRC_PIXEL_GTE_THRESHOLD 0x4F04 ZB_ZSTENCILCNTL 0x4F08 ZB_STENCILREFMASK 0x4F14 ZB_ZTOP 0x4F18 ZB_ZCACHE_CTLSTAT +0x4F28 ZB_DEPTHCLEARVALUE 0x4F58 ZB_ZPASS_DATA diff --git a/drivers/gpu/drm/radeon/reg_srcs/r420 b/drivers/gpu/drm/radeon/reg_srcs/r420 index 8c1214c2390f..722074e21e2f 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/r420 +++ b/drivers/gpu/drm/radeon/reg_srcs/r420 @@ -130,7 +130,6 @@ r420 0x4f60 0x401C GB_SELECT 0x4020 GB_AA_CONFIG 0x4024 GB_FIFO_SIZE -0x4028 GB_Z_PEQ_CONFIG 0x4100 TX_INVALTAGS 0x4200 GA_POINT_S0 0x4204 GA_POINT_T0 @@ -750,9 +749,7 @@ r420 0x4f60 0x4DF4 US_ALU_CONST_G_31 0x4DF8 US_ALU_CONST_B_31 0x4DFC US_ALU_CONST_A_31 -0x4E04 RB3D_BLENDCNTL_R3 0x4E08 RB3D_ABLENDCNTL_R3 -0x4E0C RB3D_COLOR_CHANNEL_MASK 0x4E10 RB3D_CONSTANT_COLOR 0x4E14 RB3D_COLOR_CLEAR_VALUE 0x4E18 RB3D_ROPCNTL_R3 @@ -773,13 +770,11 @@ r420 0x4f60 0x4E74 RB3D_CMASK_WRINDEX 0x4E78 RB3D_CMASK_DWORD 0x4E7C RB3D_CMASK_RDINDEX -0x4E80 RB3D_AARESOLVE_OFFSET -0x4E84 RB3D_AARESOLVE_PITCH -0x4E88 RB3D_AARESOLVE_CTL 0x4EA0 RB3D_DISCARD_SRC_PIXEL_LTE_THRESHOLD 0x4EA4 RB3D_DISCARD_SRC_PIXEL_GTE_THRESHOLD 0x4F04 ZB_ZSTENCILCNTL 0x4F08 ZB_STENCILREFMASK 0x4F14 ZB_ZTOP 0x4F18 ZB_ZCACHE_CTLSTAT +0x4F28 ZB_DEPTHCLEARVALUE 0x4F58 ZB_ZPASS_DATA diff --git a/drivers/gpu/drm/radeon/reg_srcs/rs600 b/drivers/gpu/drm/radeon/reg_srcs/rs600 index 0828d80396f2..d9f62866bbc1 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/rs600 +++ b/drivers/gpu/drm/radeon/reg_srcs/rs600 @@ -749,9 +749,7 @@ rs600 0x6d40 0x4DF4 US_ALU_CONST_G_31 0x4DF8 US_ALU_CONST_B_31 0x4DFC US_ALU_CONST_A_31 -0x4E04 RB3D_BLENDCNTL_R3 0x4E08 RB3D_ABLENDCNTL_R3 -0x4E0C RB3D_COLOR_CHANNEL_MASK 0x4E10 RB3D_CONSTANT_COLOR 0x4E14 RB3D_COLOR_CLEAR_VALUE 0x4E18 RB3D_ROPCNTL_R3 @@ -772,13 +770,11 @@ rs600 0x6d40 0x4E74 RB3D_CMASK_WRINDEX 0x4E78 RB3D_CMASK_DWORD 0x4E7C RB3D_CMASK_RDINDEX -0x4E80 RB3D_AARESOLVE_OFFSET -0x4E84 RB3D_AARESOLVE_PITCH -0x4E88 RB3D_AARESOLVE_CTL 0x4EA0 RB3D_DISCARD_SRC_PIXEL_LTE_THRESHOLD 0x4EA4 RB3D_DISCARD_SRC_PIXEL_GTE_THRESHOLD 0x4F04 ZB_ZSTENCILCNTL 0x4F08 ZB_STENCILREFMASK 0x4F14 ZB_ZTOP 0x4F18 ZB_ZCACHE_CTLSTAT +0x4F28 ZB_DEPTHCLEARVALUE 0x4F58 ZB_ZPASS_DATA diff --git a/drivers/gpu/drm/radeon/reg_srcs/rv515 b/drivers/gpu/drm/radeon/reg_srcs/rv515 index ef422bbacfc1..911a8fbd32bb 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/rv515 +++ b/drivers/gpu/drm/radeon/reg_srcs/rv515 @@ -164,7 +164,6 @@ rv515 0x6d40 0x401C GB_SELECT 0x4020 GB_AA_CONFIG 0x4024 GB_FIFO_SIZE -0x4028 GB_Z_PEQ_CONFIG 0x4100 TX_INVALTAGS 0x4114 SU_TEX_WRAP_PS3 0x4118 PS3_ENABLE @@ -461,9 +460,7 @@ rv515 0x6d40 0x4DF4 US_ALU_CONST_G_31 0x4DF8 US_ALU_CONST_B_31 0x4DFC US_ALU_CONST_A_31 -0x4E04 RB3D_BLENDCNTL_R3 0x4E08 RB3D_ABLENDCNTL_R3 -0x4E0C RB3D_COLOR_CHANNEL_MASK 0x4E10 RB3D_CONSTANT_COLOR 0x4E14 RB3D_COLOR_CLEAR_VALUE 0x4E18 RB3D_ROPCNTL_R3 @@ -484,9 +481,6 @@ rv515 0x6d40 0x4E74 RB3D_CMASK_WRINDEX 0x4E78 RB3D_CMASK_DWORD 0x4E7C RB3D_CMASK_RDINDEX -0x4E80 RB3D_AARESOLVE_OFFSET -0x4E84 RB3D_AARESOLVE_PITCH -0x4E88 RB3D_AARESOLVE_CTL 0x4EA0 RB3D_DISCARD_SRC_PIXEL_LTE_THRESHOLD 0x4EA4 RB3D_DISCARD_SRC_PIXEL_GTE_THRESHOLD 0x4EF8 RB3D_CONSTANT_COLOR_AR @@ -496,4 +490,5 @@ rv515 0x6d40 0x4F14 ZB_ZTOP 0x4F18 ZB_ZCACHE_CTLSTAT 0x4F58 ZB_ZPASS_DATA +0x4F28 ZB_DEPTHCLEARVALUE 0x4FD4 ZB_STENCILREFMASK_BF diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 5512e4e5e636..c76283d9eb3d 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -203,6 +203,9 @@ void rs400_gart_fini(struct radeon_device *rdev) radeon_gart_table_ram_free(rdev); } +#define RS400_PTE_WRITEABLE (1 << 2) +#define RS400_PTE_READABLE (1 << 3) + int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) { uint32_t entry; @@ -213,7 +216,7 @@ int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) entry = (lower_32_bits(addr) & PAGE_MASK) | ((upper_32_bits(addr) & 0xff) << 4) | - 0xc; + RS400_PTE_WRITEABLE | RS400_PTE_READABLE; entry = cpu_to_le32(entry); rdev->gart.table.ram.ptr[i] = entry; return 0; @@ -226,8 +229,8 @@ int rs400_mc_wait_for_idle(struct radeon_device *rdev) for (i = 0; i < rdev->usec_timeout; i++) { /* read MC_STATUS */ - tmp = RREG32(0x0150); - if (tmp & (1 << 2)) { + tmp = RREG32(RADEON_MC_STATUS); + if (tmp & RADEON_MC_IDLE) { return 0; } DRM_UDELAY(1); @@ -241,7 +244,7 @@ void rs400_gpu_init(struct radeon_device *rdev) r420_pipes_init(rdev); if (rs400_mc_wait_for_idle(rdev)) { printk(KERN_WARNING "rs400: Failed to wait MC idle while " - "programming pipes. Bad things might happen. %08x\n", RREG32(0x150)); + "programming pipes. Bad things might happen. %08x\n", RREG32(RADEON_MC_STATUS)); } } @@ -300,9 +303,9 @@ static int rs400_debugfs_gart_info(struct seq_file *m, void *data) seq_printf(m, "MCCFG_AGP_BASE_2 0x%08x\n", tmp); tmp = RREG32_MC(RS690_MCCFG_AGP_LOCATION); seq_printf(m, "MCCFG_AGP_LOCATION 0x%08x\n", tmp); - tmp = RREG32_MC(0x100); + tmp = RREG32_MC(RS690_MCCFG_FB_LOCATION); seq_printf(m, "MCCFG_FB_LOCATION 0x%08x\n", tmp); - tmp = RREG32(0x134); + tmp = RREG32(RS690_HDP_FB_LOCATION); seq_printf(m, "HDP_FB_LOCATION 0x%08x\n", tmp); } else { tmp = RREG32(RADEON_AGP_BASE); diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index 0137d3e3728d..6638c8e4c81b 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -77,9 +77,9 @@ void rs690_pm_info(struct radeon_device *rdev) switch (crev) { case 1: tmp.full = dfixed_const(100); - rdev->pm.igp_sideport_mclk.full = dfixed_const(info->info.ulBootUpMemoryClock); + rdev->pm.igp_sideport_mclk.full = dfixed_const(le32_to_cpu(info->info.ulBootUpMemoryClock)); rdev->pm.igp_sideport_mclk.full = dfixed_div(rdev->pm.igp_sideport_mclk, tmp); - if (info->info.usK8MemoryClock) + if (le16_to_cpu(info->info.usK8MemoryClock)) rdev->pm.igp_system_mclk.full = dfixed_const(le16_to_cpu(info->info.usK8MemoryClock)); else if (rdev->clock.default_mclk) { rdev->pm.igp_system_mclk.full = dfixed_const(rdev->clock.default_mclk); @@ -91,16 +91,16 @@ void rs690_pm_info(struct radeon_device *rdev) break; case 2: tmp.full = dfixed_const(100); - rdev->pm.igp_sideport_mclk.full = dfixed_const(info->info_v2.ulBootUpSidePortClock); + rdev->pm.igp_sideport_mclk.full = dfixed_const(le32_to_cpu(info->info_v2.ulBootUpSidePortClock)); rdev->pm.igp_sideport_mclk.full = dfixed_div(rdev->pm.igp_sideport_mclk, tmp); - if (info->info_v2.ulBootUpUMAClock) - rdev->pm.igp_system_mclk.full = dfixed_const(info->info_v2.ulBootUpUMAClock); + if (le32_to_cpu(info->info_v2.ulBootUpUMAClock)) + rdev->pm.igp_system_mclk.full = dfixed_const(le32_to_cpu(info->info_v2.ulBootUpUMAClock)); else if (rdev->clock.default_mclk) rdev->pm.igp_system_mclk.full = dfixed_const(rdev->clock.default_mclk); else rdev->pm.igp_system_mclk.full = dfixed_const(66700); rdev->pm.igp_system_mclk.full = dfixed_div(rdev->pm.igp_system_mclk, tmp); - rdev->pm.igp_ht_link_clk.full = dfixed_const(info->info_v2.ulHTLinkFreq); + rdev->pm.igp_ht_link_clk.full = dfixed_const(le32_to_cpu(info->info_v2.ulHTLinkFreq)); rdev->pm.igp_ht_link_clk.full = dfixed_div(rdev->pm.igp_ht_link_clk, tmp); rdev->pm.igp_ht_link_width.full = dfixed_const(le16_to_cpu(info->info_v2.usMinHTLinkWidth)); break; diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 5d569f41f4ae..64b57af93714 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -69,13 +69,13 @@ void rv515_ring_start(struct radeon_device *rdev) ISYNC_CPSCRATCH_IDLEGUI); radeon_ring_write(rdev, PACKET0(WAIT_UNTIL, 0)); radeon_ring_write(rdev, WAIT_2D_IDLECLEAN | WAIT_3D_IDLECLEAN); - radeon_ring_write(rdev, PACKET0(0x170C, 0)); - radeon_ring_write(rdev, 1 << 31); + radeon_ring_write(rdev, PACKET0(R300_DST_PIPE_CONFIG, 0)); + radeon_ring_write(rdev, R300_PIPE_AUTO_CONFIG); radeon_ring_write(rdev, PACKET0(GB_SELECT, 0)); radeon_ring_write(rdev, 0); radeon_ring_write(rdev, PACKET0(GB_ENABLE, 0)); radeon_ring_write(rdev, 0); - radeon_ring_write(rdev, PACKET0(0x42C8, 0)); + radeon_ring_write(rdev, PACKET0(R500_SU_REG_DEST, 0)); radeon_ring_write(rdev, (1 << rdev->num_gb_pipes) - 1); radeon_ring_write(rdev, PACKET0(VAP_INDEX_OFFSET, 0)); radeon_ring_write(rdev, 0); @@ -153,8 +153,8 @@ void rv515_gpu_init(struct radeon_device *rdev) } rv515_vga_render_disable(rdev); r420_pipes_init(rdev); - gb_pipe_select = RREG32(0x402C); - tmp = RREG32(0x170C); + gb_pipe_select = RREG32(R400_GB_PIPE_SELECT); + tmp = RREG32(R300_DST_PIPE_CONFIG); pipe_select_current = (tmp >> 2) & 3; tmp = (1 << pipe_select_current) | (((gb_pipe_select >> 8) & 0xF) << 4); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 491dc9000655..d8ba67690656 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -78,18 +78,23 @@ u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) } /* get temperature in millidegrees */ -u32 rv770_get_temp(struct radeon_device *rdev) +int rv770_get_temp(struct radeon_device *rdev) { u32 temp = (RREG32(CG_MULT_THERMAL_STATUS) & ASIC_T_MASK) >> ASIC_T_SHIFT; - u32 actual_temp = 0; - - if ((temp >> 9) & 1) - actual_temp = 0; - else - actual_temp = (temp >> 1) & 0xff; - - return actual_temp * 1000; + int actual_temp; + + if (temp & 0x400) + actual_temp = -256; + else if (temp & 0x200) + actual_temp = 255; + else if (temp & 0x100) { + actual_temp = temp & 0x1ff; + actual_temp |= ~0x1ff; + } else + actual_temp = temp & 0xff; + + return (actual_temp * 1000) / 2; } void rv770_pm_misc(struct radeon_device *rdev) @@ -316,7 +321,11 @@ static int rv770_cp_load_microcode(struct radeon_device *rdev) return -EINVAL; r700_cp_stop(rdev); - WREG32(CP_RB_CNTL, RB_NO_UPDATE | (15 << 8) | (3 << 0)); + WREG32(CP_RB_CNTL, +#ifdef __BIG_ENDIAN + BUF_SWAP_32BIT | +#endif + RB_NO_UPDATE | RB_BLKSZ(15) | RB_BUFSZ(3)); /* Reset cp */ WREG32(GRBM_SOFT_RESET, SOFT_RESET_CP); diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index abc8cf5a3672..79fa588e9ed5 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h @@ -76,10 +76,10 @@ #define ROQ_IB1_START(x) ((x) << 0) #define ROQ_IB2_START(x) ((x) << 8) #define CP_RB_CNTL 0xC104 -#define RB_BUFSZ(x) ((x)<<0) -#define RB_BLKSZ(x) ((x)<<8) -#define RB_NO_UPDATE (1<<27) -#define RB_RPTR_WR_ENA (1<<31) +#define RB_BUFSZ(x) ((x) << 0) +#define RB_BLKSZ(x) ((x) << 8) +#define RB_NO_UPDATE (1 << 27) +#define RB_RPTR_WR_ENA (1 << 31) #define BUF_SWAP_32BIT (2 << 16) #define CP_RB_RPTR 0x8700 #define CP_RB_RPTR_ADDR 0xC10C diff --git a/drivers/gpu/stub/Kconfig b/drivers/gpu/stub/Kconfig index 09aea5f1556d..70e60a4bb678 100644 --- a/drivers/gpu/stub/Kconfig +++ b/drivers/gpu/stub/Kconfig @@ -1,11 +1,13 @@ config STUB_POULSBO tristate "Intel GMA500 Stub Driver" depends on PCI + depends on NET # for THERMAL # Poulsbo stub depends on ACPI_VIDEO when ACPI is enabled # but for select to work, need to select ACPI_VIDEO's dependencies, ick select BACKLIGHT_CLASS_DEVICE if ACPI select INPUT if ACPI select ACPI_VIDEO if ACPI + select THERMAL if ACPI help Choose this option if you have a system that has Intel GMA500 (Poulsbo) integrated graphics. If M is selected, the module will diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index c380c65da417..ace2b1623b21 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -636,7 +636,7 @@ int vga_client_register(struct pci_dev *pdev, void *cookie, void (*irq_set_state)(void *cookie, bool state), unsigned int (*set_vga_decode)(void *cookie, bool decode)) { - int ret = -1; + int ret = -ENODEV; struct vga_device *vgadev; unsigned long flags; diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index ce0372f0615e..4c0743660e9c 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -1072,6 +1072,7 @@ static int applesmc_create_nodes(struct applesmc_node_group *groups, int num) node->sda.dev_attr.show = grp->show; node->sda.dev_attr.store = grp->store; attr = &node->sda.dev_attr.attr; + sysfs_attr_init(attr); attr->name = node->name; attr->mode = S_IRUGO | (grp->store ? S_IWUSR : 0); ret = sysfs_create_file(&pdev->dev.kobj, attr); diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index 2d68cf3c223b..b5e892017e0c 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -13,6 +13,7 @@ #include <linux/list.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/dmi.h> #include <acpi/acpi.h> #include <acpi/acpixf.h> @@ -22,6 +23,21 @@ #define ATK_HID "ATK0110" +static bool new_if; +module_param(new_if, bool, 0); +MODULE_PARM_DESC(new_if, "Override detection heuristic and force the use of the new ATK0110 interface"); + +static const struct dmi_system_id __initconst atk_force_new_if[] = { + { + /* Old interface has broken MCH temp monitoring */ + .ident = "Asus Sabertooth X58", + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "SABERTOOTH X58") + } + }, + { } +}; + /* Minimum time between readings, enforced in order to avoid * hogging the CPU. */ @@ -1302,7 +1318,9 @@ static int atk_probe_if(struct atk_data *data) * analysis of multiple DSDTs indicates that when both interfaces * are present the new one (GGRP/GITM) is not functional. */ - if (data->rtmp_handle && data->rvlt_handle && data->rfan_handle) + if (new_if) + dev_info(dev, "Overriding interface detection\n"); + if (data->rtmp_handle && data->rvlt_handle && data->rfan_handle && !new_if) data->old_interface = true; else if (data->enumerate_handle && data->read_handle && data->write_handle) @@ -1420,6 +1438,9 @@ static int __init atk0110_init(void) return -EBUSY; } + if (dmi_check_system(atk_force_new_if)) + new_if = true; + ret = acpi_bus_register_driver(&atk_driver); if (ret) pr_info("acpi_bus_register_driver failed: %d\n", ret); diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index 5dea9faa1656..cd2a6e437aec 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -344,7 +344,7 @@ static int emc1403_remove(struct i2c_client *client) } static const unsigned short emc1403_address_list[] = { - 0x18, 0x2a, 0x4c, 0x4d, I2C_CLIENT_END + 0x18, 0x29, 0x4c, 0x4d, I2C_CLIENT_END }; static const struct i2c_device_id emc1403_idtable[] = { diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c index 1b674b7d4584..d805e8e57967 100644 --- a/drivers/hwmon/lis3lv02d.c +++ b/drivers/hwmon/lis3lv02d.c @@ -957,7 +957,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev) /* bail if we did not get an IRQ from the bus layer */ if (!dev->irq) { - pr_err("No IRQ. Disabling /dev/freefall\n"); + pr_debug("No IRQ. Disabling /dev/freefall\n"); goto out; } diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index 776aeb3019d2..508cb291f71b 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -98,6 +98,9 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END }; * value, it uses signed 8-bit values with LSB = 1 degree Celsius. * For remote temperature, low and high limits, it uses signed 11-bit values * with LSB = 0.125 degree Celsius, left-justified in 16-bit registers. + * For LM64 the actual remote diode temperature is 16 degree Celsius higher + * than the register reading. Remote temperature setpoints have to be + * adapted accordingly. */ #define FAN_FROM_REG(reg) ((reg) == 0xFFFC || (reg) == 0 ? 0 : \ @@ -165,6 +168,8 @@ struct lm63_data { struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ + int kind; + int temp2_offset; /* registers values */ u8 config, config_fan; @@ -247,16 +252,34 @@ static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dum return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2); } -static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, - char *buf) +/* + * There are 8bit registers for both local(temp1) and remote(temp2) sensor. + * For remote sensor registers temp2_offset has to be considered, + * for local sensor it must not. + * So we need separate 8bit accessors for local and remote sensor. + */ +static ssize_t show_local_temp8(struct device *dev, + struct device_attribute *devattr, + char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm63_data *data = lm63_update_device(dev); return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index])); } -static ssize_t set_temp8(struct device *dev, struct device_attribute *dummy, - const char *buf, size_t count) +static ssize_t show_remote_temp8(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index]) + + data->temp2_offset); +} + +static ssize_t set_local_temp8(struct device *dev, + struct device_attribute *dummy, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); @@ -274,7 +297,8 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index])); + return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index]) + + data->temp2_offset); } static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, @@ -294,7 +318,7 @@ static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, int nr = attr->index; mutex_lock(&data->update_lock); - data->temp11[nr] = TEMP11_TO_REG(val); + data->temp11[nr] = TEMP11_TO_REG(val - data->temp2_offset); i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], data->temp11[nr] >> 8); i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], @@ -310,6 +334,7 @@ static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute { struct lm63_data *data = lm63_update_device(dev); return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[2]) + + data->temp2_offset - TEMP8_FROM_REG(data->temp2_crit_hyst)); } @@ -324,7 +349,7 @@ static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute * long hyst; mutex_lock(&data->update_lock); - hyst = TEMP8_FROM_REG(data->temp8[2]) - val; + hyst = TEMP8_FROM_REG(data->temp8[2]) + data->temp2_offset - val; i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST, HYST_TO_REG(hyst)); mutex_unlock(&data->update_lock); @@ -355,16 +380,21 @@ static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan, static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1); static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL); -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0); -static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8, - set_temp8, 1); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_local_temp8, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_local_temp8, + set_local_temp8, 1); static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, set_temp11, 1); static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, set_temp11, 2); -static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp8, NULL, 2); +/* + * On LM63, temp2_crit can be set only once, which should be job + * of the bootloader. + */ +static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_remote_temp8, + NULL, 2); static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst, set_temp2_crit_hyst); @@ -479,7 +509,12 @@ static int lm63_probe(struct i2c_client *new_client, data->valid = 0; mutex_init(&data->update_lock); - /* Initialize the LM63 chip */ + /* Set the device type */ + data->kind = id->driver_data; + if (data->kind == lm64) + data->temp2_offset = 16000; + + /* Initialize chip */ lm63_init_client(new_client); /* Register sysfs hooks */ diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index e38be1bcc01c..fbbfa24cf572 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -1079,7 +1079,7 @@ static void ib_sa_remove_one(struct ib_device *device) ib_unregister_event_handler(&sa_dev->event_handler); - flush_scheduled_work(); + flush_workqueue(ib_wq); for (i = 0; i <= sa_dev->end_port - sa_dev->start_port; ++i) { if (rdma_port_get_link_layer(device, i + 1) == IB_LINK_LAYER_INFINIBAND) { diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index ca12acf38379..ec1e9da1488b 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -636,6 +636,16 @@ static void ucma_copy_iboe_route(struct rdma_ucm_query_route_resp *resp, } } +static void ucma_copy_iw_route(struct rdma_ucm_query_route_resp *resp, + struct rdma_route *route) +{ + struct rdma_dev_addr *dev_addr; + + dev_addr = &route->addr.dev_addr; + rdma_addr_get_dgid(dev_addr, (union ib_gid *) &resp->ib_route[0].dgid); + rdma_addr_get_sgid(dev_addr, (union ib_gid *) &resp->ib_route[0].sgid); +} + static ssize_t ucma_query_route(struct ucma_file *file, const char __user *inbuf, int in_len, int out_len) @@ -670,8 +680,10 @@ static ssize_t ucma_query_route(struct ucma_file *file, resp.node_guid = (__force __u64) ctx->cm_id->device->node_guid; resp.port_num = ctx->cm_id->port_num; - if (rdma_node_get_transport(ctx->cm_id->device->node_type) == RDMA_TRANSPORT_IB) { - switch (rdma_port_get_link_layer(ctx->cm_id->device, ctx->cm_id->port_num)) { + switch (rdma_node_get_transport(ctx->cm_id->device->node_type)) { + case RDMA_TRANSPORT_IB: + switch (rdma_port_get_link_layer(ctx->cm_id->device, + ctx->cm_id->port_num)) { case IB_LINK_LAYER_INFINIBAND: ucma_copy_ib_route(&resp, &ctx->cm_id->route); break; @@ -681,6 +693,12 @@ static ssize_t ucma_query_route(struct ucma_file *file, default: break; } + break; + case RDMA_TRANSPORT_IWARP: + ucma_copy_iw_route(&resp, &ctx->cm_id->route); + break; + default: + break; } out: diff --git a/drivers/infiniband/hw/amso1100/c2_vq.c b/drivers/infiniband/hw/amso1100/c2_vq.c index 9ce7819b7b2e..2ec716fb2edb 100644 --- a/drivers/infiniband/hw/amso1100/c2_vq.c +++ b/drivers/infiniband/hw/amso1100/c2_vq.c @@ -107,7 +107,7 @@ struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev) r = kmalloc(sizeof(struct c2_vq_req), GFP_KERNEL); if (r) { init_waitqueue_head(&r->wait_object); - r->reply_msg = (u64) NULL; + r->reply_msg = 0; r->event = 0; r->cm_id = NULL; r->qp = NULL; @@ -123,7 +123,7 @@ struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev) */ void vq_req_free(struct c2_dev *c2dev, struct c2_vq_req *r) { - r->reply_msg = (u64) NULL; + r->reply_msg = 0; if (atomic_dec_and_test(&r->refcnt)) { kfree(r); } @@ -151,7 +151,7 @@ void vq_req_get(struct c2_dev *c2dev, struct c2_vq_req *r) void vq_req_put(struct c2_dev *c2dev, struct c2_vq_req *r) { if (atomic_dec_and_test(&r->refcnt)) { - if (r->reply_msg != (u64) NULL) + if (r->reply_msg != 0) vq_repbuf_free(c2dev, (void *) (unsigned long) r->reply_msg); kfree(r); diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 0dc62b1438be..8b00e6c46f01 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -380,7 +380,7 @@ static void send_flowc(struct c4iw_ep *ep, struct sk_buff *skb) 16)) | FW_WR_FLOWID(ep->hwtid)); flowc->mnemval[0].mnemonic = FW_FLOWC_MNEM_PFNVFN; - flowc->mnemval[0].val = cpu_to_be32(0); + flowc->mnemval[0].val = cpu_to_be32(PCI_FUNC(ep->com.dev->rdev.lldi.pdev->devfn) << 8); flowc->mnemval[1].mnemonic = FW_FLOWC_MNEM_CH; flowc->mnemval[1].val = cpu_to_be32(ep->tx_chan); flowc->mnemval[2].mnemonic = FW_FLOWC_MNEM_PORT; diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 20800900ef3f..4f0be25cab1a 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -220,7 +220,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, V_FW_RI_RES_WR_DCAEN(0) | V_FW_RI_RES_WR_DCACPU(0) | V_FW_RI_RES_WR_FBMIN(2) | - V_FW_RI_RES_WR_FBMAX(3) | + V_FW_RI_RES_WR_FBMAX(2) | V_FW_RI_RES_WR_CIDXFTHRESHO(0) | V_FW_RI_RES_WR_CIDXFTHRESH(0) | V_FW_RI_RES_WR_EQSIZE(eqsize)); @@ -243,7 +243,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, V_FW_RI_RES_WR_DCAEN(0) | V_FW_RI_RES_WR_DCACPU(0) | V_FW_RI_RES_WR_FBMIN(2) | - V_FW_RI_RES_WR_FBMAX(3) | + V_FW_RI_RES_WR_FBMAX(2) | V_FW_RI_RES_WR_CIDXFTHRESHO(0) | V_FW_RI_RES_WR_CIDXFTHRESH(0) | V_FW_RI_RES_WR_EQSIZE(eqsize)); diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index 3b4ec3238ceb..3d7f3664b67b 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c @@ -153,7 +153,8 @@ static int nes_inetaddr_event(struct notifier_block *notifier, nesdev, nesdev->netdev[0]->name); netdev = nesdev->netdev[0]; nesvnic = netdev_priv(netdev); - is_bonded = (netdev->master == event_netdev); + is_bonded = netif_is_bond_slave(netdev) && + (netdev->master == event_netdev); if ((netdev == event_netdev) || is_bonded) { if (nesvnic->rdma_enabled == 0) { nes_debug(NES_DBG_NETDEV, "Returning without processing event for %s since" diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 009ec814d517..ec3aa11c36cb 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -1118,7 +1118,7 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi return rc; } - if (nesvnic->netdev->master) + if (netif_is_bond_slave(netdev)) netdev = nesvnic->netdev->master; else netdev = nesvnic->netdev; diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 8b606fd64022..08c194861af5 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -2610,9 +2610,11 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) netif_carrier_on(nesvnic->netdev); spin_lock(&nesvnic->port_ibevent_lock); - if (nesdev->iw_status == 0) { - nesdev->iw_status = 1; - nes_port_ibevent(nesvnic); + if (nesvnic->of_device_registered) { + if (nesdev->iw_status == 0) { + nesdev->iw_status = 1; + nes_port_ibevent(nesvnic); + } } spin_unlock(&nesvnic->port_ibevent_lock); } @@ -2642,9 +2644,11 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) netif_carrier_off(nesvnic->netdev); spin_lock(&nesvnic->port_ibevent_lock); - if (nesdev->iw_status == 1) { - nesdev->iw_status = 0; - nes_port_ibevent(nesvnic); + if (nesvnic->of_device_registered) { + if (nesdev->iw_status == 1) { + nesdev->iw_status = 0; + nes_port_ibevent(nesvnic); + } } spin_unlock(&nesvnic->port_ibevent_lock); } @@ -2703,9 +2707,11 @@ void nes_recheck_link_status(struct work_struct *work) netif_carrier_on(nesvnic->netdev); spin_lock(&nesvnic->port_ibevent_lock); - if (nesdev->iw_status == 0) { - nesdev->iw_status = 1; - nes_port_ibevent(nesvnic); + if (nesvnic->of_device_registered) { + if (nesdev->iw_status == 0) { + nesdev->iw_status = 1; + nes_port_ibevent(nesvnic); + } } spin_unlock(&nesvnic->port_ibevent_lock); } @@ -2723,9 +2729,11 @@ void nes_recheck_link_status(struct work_struct *work) netif_carrier_off(nesvnic->netdev); spin_lock(&nesvnic->port_ibevent_lock); - if (nesdev->iw_status == 1) { - nesdev->iw_status = 0; - nes_port_ibevent(nesvnic); + if (nesvnic->of_device_registered) { + if (nesdev->iw_status == 1) { + nesdev->iw_status = 0; + nes_port_ibevent(nesvnic); + } } spin_unlock(&nesvnic->port_ibevent_lock); } diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 50cceb3ab885..b01809a82cb0 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -623,7 +623,6 @@ struct qib_chippport_specific { u8 ibmalfusesnap; struct qib_qsfp_data qsfp_data; char epmsgbuf[192]; /* for port error interrupt msg buffer */ - u8 bounced; }; static struct { @@ -1881,23 +1880,7 @@ static noinline void handle_7322_p_errors(struct qib_pportdata *ppd) IB_PHYSPORTSTATE_DISABLED) qib_set_ib_7322_lstate(ppd, 0, QLOGIC_IB_IBCC_LINKINITCMD_DISABLE); - else { - u32 lstate; - /* - * We need the current logical link state before - * lflags are set in handle_e_ibstatuschanged. - */ - lstate = qib_7322_iblink_state(ibcs); - - if (IS_QMH(dd) && !ppd->cpspec->bounced && - ltstate == IB_PHYSPORTSTATE_LINKUP && - (lstate >= IB_PORT_INIT && - lstate <= IB_PORT_ACTIVE)) { - ppd->cpspec->bounced = 1; - qib_7322_set_ib_cfg(ppd, QIB_IB_CFG_LSTATE, - IB_LINKCMD_DOWN | IB_LINKINITCMD_POLL); - } - + else /* * Since going into a recovery state causes the link * state to go down and since recovery is transitory, @@ -1911,7 +1894,6 @@ static noinline void handle_7322_p_errors(struct qib_pportdata *ppd) ltstate != IB_PHYSPORTSTATE_RECOVERY_WAITRMT && ltstate != IB_PHYSPORTSTATE_RECOVERY_IDLE) qib_handle_e_ibstatuschanged(ppd, ibcs); - } } if (*msg && iserr) qib_dev_porterr(dd, ppd->port, "%s error\n", msg); @@ -2381,6 +2363,11 @@ static int qib_7322_bringup_serdes(struct qib_pportdata *ppd) qib_write_kreg_port(ppd, krp_rcvctrl, ppd->p_rcvctrl); spin_unlock_irqrestore(&dd->cspec->rcvmod_lock, flags); + /* Hold the link state machine for mezz boards */ + if (IS_QMH(dd) || IS_QME(dd)) + qib_set_ib_7322_lstate(ppd, 0, + QLOGIC_IB_IBCC_LINKINITCMD_DISABLE); + /* Also enable IBSTATUSCHG interrupt. */ val = qib_read_kreg_port(ppd, krp_errmask); qib_write_kreg_port(ppd, krp_errmask, @@ -5702,6 +5689,11 @@ static void set_no_qsfp_atten(struct qib_devdata *dd, int change) ppd->cpspec->h1_val = h1; /* now change the IBC and serdes, overriding generic */ init_txdds_table(ppd, 1); + /* Re-enable the physical state machine on mezz boards + * now that the correct settings have been set. */ + if (IS_QMH(dd) || IS_QME(dd)) + qib_set_ib_7322_lstate(ppd, 0, + QLOGIC_IB_IBCC_LINKINITCMD_SLEEP); any++; } if (*nxt == '\n') diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c index 8245237b67ce..eca0c41f1226 100644 --- a/drivers/infiniband/hw/qib/qib_rc.c +++ b/drivers/infiniband/hw/qib/qib_rc.c @@ -1005,7 +1005,8 @@ void qib_rc_send_complete(struct qib_qp *qp, struct qib_ib_header *hdr) * there are still requests that haven't been acked. */ if ((psn & IB_BTH_REQ_ACK) && qp->s_acked != qp->s_tail && - !(qp->s_flags & (QIB_S_TIMER | QIB_S_WAIT_RNR | QIB_S_WAIT_PSN))) + !(qp->s_flags & (QIB_S_TIMER | QIB_S_WAIT_RNR | QIB_S_WAIT_PSN)) && + (ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK)) start_timer(qp); while (qp->s_last != qp->s_acked) { @@ -1439,6 +1440,8 @@ static void qib_rc_rcv_resp(struct qib_ibport *ibp, } spin_lock_irqsave(&qp->s_lock, flags); + if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK)) + goto ack_done; /* Ignore invalid responses. */ if (qib_cmp24(psn, qp->s_next_psn) >= 0) diff --git a/drivers/input/input.c b/drivers/input/input.c index 7985114beac7..11905b6a3023 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -75,7 +75,6 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz) * dev->event_lock held and interrupts disabled. */ static void input_pass_event(struct input_dev *dev, - struct input_handler *src_handler, unsigned int type, unsigned int code, int value) { struct input_handler *handler; @@ -94,15 +93,6 @@ static void input_pass_event(struct input_dev *dev, continue; handler = handle->handler; - - /* - * If this is the handler that injected this - * particular event we want to skip it to avoid - * filters firing again and again. - */ - if (handler == src_handler) - continue; - if (!handler->filter) { if (filtered) break; @@ -132,7 +122,7 @@ static void input_repeat_key(unsigned long data) if (test_bit(dev->repeat_key, dev->key) && is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) { - input_pass_event(dev, NULL, EV_KEY, dev->repeat_key, 2); + input_pass_event(dev, EV_KEY, dev->repeat_key, 2); if (dev->sync) { /* @@ -141,7 +131,7 @@ static void input_repeat_key(unsigned long data) * Otherwise assume that the driver will send * SYN_REPORT once it's done. */ - input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1); + input_pass_event(dev, EV_SYN, SYN_REPORT, 1); } if (dev->rep[REP_PERIOD]) @@ -174,7 +164,6 @@ static void input_stop_autorepeat(struct input_dev *dev) #define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE) static int input_handle_abs_event(struct input_dev *dev, - struct input_handler *src_handler, unsigned int code, int *pval) { bool is_mt_event; @@ -218,15 +207,13 @@ static int input_handle_abs_event(struct input_dev *dev, /* Flush pending "slot" event */ if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) { input_abs_set_val(dev, ABS_MT_SLOT, dev->slot); - input_pass_event(dev, src_handler, - EV_ABS, ABS_MT_SLOT, dev->slot); + input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot); } return INPUT_PASS_TO_HANDLERS; } static void input_handle_event(struct input_dev *dev, - struct input_handler *src_handler, unsigned int type, unsigned int code, int value) { int disposition = INPUT_IGNORE_EVENT; @@ -279,8 +266,7 @@ static void input_handle_event(struct input_dev *dev, case EV_ABS: if (is_event_supported(code, dev->absbit, ABS_MAX)) - disposition = input_handle_abs_event(dev, src_handler, - code, &value); + disposition = input_handle_abs_event(dev, code, &value); break; @@ -338,7 +324,7 @@ static void input_handle_event(struct input_dev *dev, dev->event(dev, type, code, value); if (disposition & INPUT_PASS_TO_HANDLERS) - input_pass_event(dev, src_handler, type, code, value); + input_pass_event(dev, type, code, value); } /** @@ -367,7 +353,7 @@ void input_event(struct input_dev *dev, spin_lock_irqsave(&dev->event_lock, flags); add_input_randomness(type, code, value); - input_handle_event(dev, NULL, type, code, value); + input_handle_event(dev, type, code, value); spin_unlock_irqrestore(&dev->event_lock, flags); } } @@ -397,8 +383,7 @@ void input_inject_event(struct input_handle *handle, rcu_read_lock(); grab = rcu_dereference(dev->grab); if (!grab || grab == handle) - input_handle_event(dev, handle->handler, - type, code, value); + input_handle_event(dev, type, code, value); rcu_read_unlock(); spin_unlock_irqrestore(&dev->event_lock, flags); @@ -611,10 +596,10 @@ static void input_dev_release_keys(struct input_dev *dev) for (code = 0; code <= KEY_MAX; code++) { if (is_event_supported(code, dev->keybit, KEY_MAX) && __test_and_clear_bit(code, dev->key)) { - input_pass_event(dev, NULL, EV_KEY, code, 0); + input_pass_event(dev, EV_KEY, code, 0); } } - input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1); + input_pass_event(dev, EV_SYN, SYN_REPORT, 1); } } @@ -889,9 +874,9 @@ int input_set_keycode(struct input_dev *dev, !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && __test_and_clear_bit(old_keycode, dev->key)) { - input_pass_event(dev, NULL, EV_KEY, old_keycode, 0); + input_pass_event(dev, EV_KEY, old_keycode, 0); if (dev->sync) - input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1); + input_pass_event(dev, EV_SYN, SYN_REPORT, 1); } out: diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 417507348bab..c7a92028f450 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -343,6 +343,16 @@ config KEYBOARD_NOMADIK To compile this driver as a module, choose M here: the module will be called nmk-ske-keypad. +config KEYBOARD_TEGRA + tristate "NVIDIA Tegra internal matrix keyboard controller support" + depends on ARCH_TEGRA + help + Say Y here if you want to use a matrix keyboard connected directly + to the internal keyboard controller on Tegra SoCs. + + To compile this driver as a module, choose M here: the + module will be called tegra-kbc. + config KEYBOARD_OPENCORES tristate "OpenCores Keyboard Controller" help diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 4e5571b72cda..468c627a2844 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o +obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 6069abe31e42..eb3006361ee4 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -322,7 +322,7 @@ static void gpio_keys_report_event(struct gpio_button_data *bdata) struct gpio_keys_button *button = bdata->button; struct input_dev *input = bdata->input; unsigned int type = button->type ?: EV_KEY; - int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low; + int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low; input_event(input, type, button->code, !!state); input_sync(input); @@ -410,8 +410,8 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev, if (!button->can_disable) irqflags |= IRQF_SHARED; - error = request_irq(irq, gpio_keys_isr, irqflags, desc, bdata); - if (error) { + error = request_any_context_irq(irq, gpio_keys_isr, irqflags, desc, bdata); + if (error < 0) { dev_err(dev, "Unable to claim irq %d; error %d\n", irq, error); goto fail3; diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c new file mode 100644 index 000000000000..ac471b77c18e --- /dev/null +++ b/drivers/input/keyboard/tegra-kbc.c @@ -0,0 +1,727 @@ +/* + * Keyboard class input driver for the NVIDIA Tegra SoC internal matrix + * keyboard controller + * + * Copyright (c) 2009-2011, NVIDIA Corporation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/input.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/clk.h> +#include <linux/slab.h> +#include <mach/clk.h> +#include <mach/kbc.h> + +#define KBC_MAX_DEBOUNCE_CNT 0x3ffu + +/* KBC row scan time and delay for beginning the row scan. */ +#define KBC_ROW_SCAN_TIME 16 +#define KBC_ROW_SCAN_DLY 5 + +/* KBC uses a 32KHz clock so a cycle = 1/32Khz */ +#define KBC_CYCLE_USEC 32 + +/* KBC Registers */ + +/* KBC Control Register */ +#define KBC_CONTROL_0 0x0 +#define KBC_FIFO_TH_CNT_SHIFT(cnt) (cnt << 14) +#define KBC_DEBOUNCE_CNT_SHIFT(cnt) (cnt << 4) +#define KBC_CONTROL_FIFO_CNT_INT_EN (1 << 3) +#define KBC_CONTROL_KBC_EN (1 << 0) + +/* KBC Interrupt Register */ +#define KBC_INT_0 0x4 +#define KBC_INT_FIFO_CNT_INT_STATUS (1 << 2) + +#define KBC_ROW_CFG0_0 0x8 +#define KBC_COL_CFG0_0 0x18 +#define KBC_INIT_DLY_0 0x28 +#define KBC_RPT_DLY_0 0x2c +#define KBC_KP_ENT0_0 0x30 +#define KBC_KP_ENT1_0 0x34 +#define KBC_ROW0_MASK_0 0x38 + +#define KBC_ROW_SHIFT 3 + +struct tegra_kbc { + void __iomem *mmio; + struct input_dev *idev; + unsigned int irq; + unsigned int wake_enable_rows; + unsigned int wake_enable_cols; + spinlock_t lock; + unsigned int repoll_dly; + unsigned long cp_dly_jiffies; + const struct tegra_kbc_platform_data *pdata; + unsigned short keycode[KBC_MAX_KEY]; + unsigned short current_keys[KBC_MAX_KPENT]; + unsigned int num_pressed_keys; + struct timer_list timer; + struct clk *clk; +}; + +static const u32 tegra_kbc_default_keymap[] = { + KEY(0, 2, KEY_W), + KEY(0, 3, KEY_S), + KEY(0, 4, KEY_A), + KEY(0, 5, KEY_Z), + KEY(0, 7, KEY_FN), + + KEY(1, 7, KEY_LEFTMETA), + + KEY(2, 6, KEY_RIGHTALT), + KEY(2, 7, KEY_LEFTALT), + + KEY(3, 0, KEY_5), + KEY(3, 1, KEY_4), + KEY(3, 2, KEY_R), + KEY(3, 3, KEY_E), + KEY(3, 4, KEY_F), + KEY(3, 5, KEY_D), + KEY(3, 6, KEY_X), + + KEY(4, 0, KEY_7), + KEY(4, 1, KEY_6), + KEY(4, 2, KEY_T), + KEY(4, 3, KEY_H), + KEY(4, 4, KEY_G), + KEY(4, 5, KEY_V), + KEY(4, 6, KEY_C), + KEY(4, 7, KEY_SPACE), + + KEY(5, 0, KEY_9), + KEY(5, 1, KEY_8), + KEY(5, 2, KEY_U), + KEY(5, 3, KEY_Y), + KEY(5, 4, KEY_J), + KEY(5, 5, KEY_N), + KEY(5, 6, KEY_B), + KEY(5, 7, KEY_BACKSLASH), + + KEY(6, 0, KEY_MINUS), + KEY(6, 1, KEY_0), + KEY(6, 2, KEY_O), + KEY(6, 3, KEY_I), + KEY(6, 4, KEY_L), + KEY(6, 5, KEY_K), + KEY(6, 6, KEY_COMMA), + KEY(6, 7, KEY_M), + + KEY(7, 1, KEY_EQUAL), + KEY(7, 2, KEY_RIGHTBRACE), + KEY(7, 3, KEY_ENTER), + KEY(7, 7, KEY_MENU), + + KEY(8, 4, KEY_RIGHTSHIFT), + KEY(8, 5, KEY_LEFTSHIFT), + + KEY(9, 5, KEY_RIGHTCTRL), + KEY(9, 7, KEY_LEFTCTRL), + + KEY(11, 0, KEY_LEFTBRACE), + KEY(11, 1, KEY_P), + KEY(11, 2, KEY_APOSTROPHE), + KEY(11, 3, KEY_SEMICOLON), + KEY(11, 4, KEY_SLASH), + KEY(11, 5, KEY_DOT), + + KEY(12, 0, KEY_F10), + KEY(12, 1, KEY_F9), + KEY(12, 2, KEY_BACKSPACE), + KEY(12, 3, KEY_3), + KEY(12, 4, KEY_2), + KEY(12, 5, KEY_UP), + KEY(12, 6, KEY_PRINT), + KEY(12, 7, KEY_PAUSE), + + KEY(13, 0, KEY_INSERT), + KEY(13, 1, KEY_DELETE), + KEY(13, 3, KEY_PAGEUP), + KEY(13, 4, KEY_PAGEDOWN), + KEY(13, 5, KEY_RIGHT), + KEY(13, 6, KEY_DOWN), + KEY(13, 7, KEY_LEFT), + + KEY(14, 0, KEY_F11), + KEY(14, 1, KEY_F12), + KEY(14, 2, KEY_F8), + KEY(14, 3, KEY_Q), + KEY(14, 4, KEY_F4), + KEY(14, 5, KEY_F3), + KEY(14, 6, KEY_1), + KEY(14, 7, KEY_F7), + + KEY(15, 0, KEY_ESC), + KEY(15, 1, KEY_GRAVE), + KEY(15, 2, KEY_F5), + KEY(15, 3, KEY_TAB), + KEY(15, 4, KEY_F1), + KEY(15, 5, KEY_F2), + KEY(15, 6, KEY_CAPSLOCK), + KEY(15, 7, KEY_F6), +}; + +static const struct matrix_keymap_data tegra_kbc_default_keymap_data = { + .keymap = tegra_kbc_default_keymap, + .keymap_size = ARRAY_SIZE(tegra_kbc_default_keymap), +}; + +static void tegra_kbc_report_released_keys(struct input_dev *input, + unsigned short old_keycodes[], + unsigned int old_num_keys, + unsigned short new_keycodes[], + unsigned int new_num_keys) +{ + unsigned int i, j; + + for (i = 0; i < old_num_keys; i++) { + for (j = 0; j < new_num_keys; j++) + if (old_keycodes[i] == new_keycodes[j]) + break; + + if (j == new_num_keys) + input_report_key(input, old_keycodes[i], 0); + } +} + +static void tegra_kbc_report_pressed_keys(struct input_dev *input, + unsigned char scancodes[], + unsigned short keycodes[], + unsigned int num_pressed_keys) +{ + unsigned int i; + + for (i = 0; i < num_pressed_keys; i++) { + input_event(input, EV_MSC, MSC_SCAN, scancodes[i]); + input_report_key(input, keycodes[i], 1); + } +} + +static void tegra_kbc_report_keys(struct tegra_kbc *kbc) +{ + unsigned char scancodes[KBC_MAX_KPENT]; + unsigned short keycodes[KBC_MAX_KPENT]; + u32 val = 0; + unsigned int i; + unsigned int num_down = 0; + unsigned long flags; + + spin_lock_irqsave(&kbc->lock, flags); + for (i = 0; i < KBC_MAX_KPENT; i++) { + if ((i % 4) == 0) + val = readl(kbc->mmio + KBC_KP_ENT0_0 + i); + + if (val & 0x80) { + unsigned int col = val & 0x07; + unsigned int row = (val >> 3) & 0x0f; + unsigned char scancode = + MATRIX_SCAN_CODE(row, col, KBC_ROW_SHIFT); + + scancodes[num_down] = scancode; + keycodes[num_down++] = kbc->keycode[scancode]; + } + + val >>= 8; + } + spin_unlock_irqrestore(&kbc->lock, flags); + + tegra_kbc_report_released_keys(kbc->idev, + kbc->current_keys, kbc->num_pressed_keys, + keycodes, num_down); + tegra_kbc_report_pressed_keys(kbc->idev, scancodes, keycodes, num_down); + input_sync(kbc->idev); + + memcpy(kbc->current_keys, keycodes, sizeof(kbc->current_keys)); + kbc->num_pressed_keys = num_down; +} + +static void tegra_kbc_keypress_timer(unsigned long data) +{ + struct tegra_kbc *kbc = (struct tegra_kbc *)data; + unsigned long flags; + u32 val; + unsigned int i; + + val = (readl(kbc->mmio + KBC_INT_0) >> 4) & 0xf; + if (val) { + unsigned long dly; + + tegra_kbc_report_keys(kbc); + + /* + * If more than one keys are pressed we need not wait + * for the repoll delay. + */ + dly = (val == 1) ? kbc->repoll_dly : 1; + mod_timer(&kbc->timer, jiffies + msecs_to_jiffies(dly)); + } else { + /* Release any pressed keys and exit the polling loop */ + for (i = 0; i < kbc->num_pressed_keys; i++) + input_report_key(kbc->idev, kbc->current_keys[i], 0); + input_sync(kbc->idev); + + kbc->num_pressed_keys = 0; + + /* All keys are released so enable the keypress interrupt */ + spin_lock_irqsave(&kbc->lock, flags); + val = readl(kbc->mmio + KBC_CONTROL_0); + val |= KBC_CONTROL_FIFO_CNT_INT_EN; + writel(val, kbc->mmio + KBC_CONTROL_0); + spin_unlock_irqrestore(&kbc->lock, flags); + } +} + +static irqreturn_t tegra_kbc_isr(int irq, void *args) +{ + struct tegra_kbc *kbc = args; + u32 val, ctl; + + /* + * Until all keys are released, defer further processing to + * the polling loop in tegra_kbc_keypress_timer + */ + ctl = readl(kbc->mmio + KBC_CONTROL_0); + ctl &= ~KBC_CONTROL_FIFO_CNT_INT_EN; + writel(ctl, kbc->mmio + KBC_CONTROL_0); + + /* + * Quickly bail out & reenable interrupts if the fifo threshold + * count interrupt wasn't the interrupt source + */ + val = readl(kbc->mmio + KBC_INT_0); + writel(val, kbc->mmio + KBC_INT_0); + + if (val & KBC_INT_FIFO_CNT_INT_STATUS) { + /* + * Schedule timer to run when hardware is in continuous + * polling mode. + */ + mod_timer(&kbc->timer, jiffies + kbc->cp_dly_jiffies); + } else { + ctl |= KBC_CONTROL_FIFO_CNT_INT_EN; + writel(ctl, kbc->mmio + KBC_CONTROL_0); + } + + return IRQ_HANDLED; +} + +static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter) +{ + const struct tegra_kbc_platform_data *pdata = kbc->pdata; + int i; + unsigned int rst_val; + + BUG_ON(pdata->wake_cnt > KBC_MAX_KEY); + rst_val = (filter && pdata->wake_cnt) ? ~0 : 0; + + for (i = 0; i < KBC_MAX_ROW; i++) + writel(rst_val, kbc->mmio + KBC_ROW0_MASK_0 + i * 4); + + if (filter) { + for (i = 0; i < pdata->wake_cnt; i++) { + u32 val, addr; + addr = pdata->wake_cfg[i].row * 4 + KBC_ROW0_MASK_0; + val = readl(kbc->mmio + addr); + val &= ~(1 << pdata->wake_cfg[i].col); + writel(val, kbc->mmio + addr); + } + } +} + +static void tegra_kbc_config_pins(struct tegra_kbc *kbc) +{ + const struct tegra_kbc_platform_data *pdata = kbc->pdata; + int i; + + for (i = 0; i < KBC_MAX_GPIO; i++) { + u32 r_shft = 5 * (i % 6); + u32 c_shft = 4 * (i % 8); + u32 r_mask = 0x1f << r_shft; + u32 c_mask = 0x0f << c_shft; + u32 r_offs = (i / 6) * 4 + KBC_ROW_CFG0_0; + u32 c_offs = (i / 8) * 4 + KBC_COL_CFG0_0; + u32 row_cfg = readl(kbc->mmio + r_offs); + u32 col_cfg = readl(kbc->mmio + c_offs); + + row_cfg &= ~r_mask; + col_cfg &= ~c_mask; + + if (pdata->pin_cfg[i].is_row) + row_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << r_shft; + else + col_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << c_shft; + + writel(row_cfg, kbc->mmio + r_offs); + writel(col_cfg, kbc->mmio + c_offs); + } +} + +static int tegra_kbc_start(struct tegra_kbc *kbc) +{ + const struct tegra_kbc_platform_data *pdata = kbc->pdata; + unsigned long flags; + unsigned int debounce_cnt; + u32 val = 0; + + clk_enable(kbc->clk); + + /* Reset the KBC controller to clear all previous status.*/ + tegra_periph_reset_assert(kbc->clk); + udelay(100); + tegra_periph_reset_deassert(kbc->clk); + udelay(100); + + tegra_kbc_config_pins(kbc); + tegra_kbc_setup_wakekeys(kbc, false); + + writel(pdata->repeat_cnt, kbc->mmio + KBC_RPT_DLY_0); + + /* Keyboard debounce count is maximum of 12 bits. */ + debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT); + val = KBC_DEBOUNCE_CNT_SHIFT(debounce_cnt); + val |= KBC_FIFO_TH_CNT_SHIFT(1); /* set fifo interrupt threshold to 1 */ + val |= KBC_CONTROL_FIFO_CNT_INT_EN; /* interrupt on FIFO threshold */ + val |= KBC_CONTROL_KBC_EN; /* enable */ + writel(val, kbc->mmio + KBC_CONTROL_0); + + /* + * Compute the delay(ns) from interrupt mode to continuous polling + * mode so the timer routine is scheduled appropriately. + */ + val = readl(kbc->mmio + KBC_INIT_DLY_0); + kbc->cp_dly_jiffies = usecs_to_jiffies((val & 0xfffff) * 32); + + kbc->num_pressed_keys = 0; + + /* + * Atomically clear out any remaining entries in the key FIFO + * and enable keyboard interrupts. + */ + spin_lock_irqsave(&kbc->lock, flags); + while (1) { + val = readl(kbc->mmio + KBC_INT_0); + val >>= 4; + if (!val) + break; + + val = readl(kbc->mmio + KBC_KP_ENT0_0); + val = readl(kbc->mmio + KBC_KP_ENT1_0); + } + writel(0x7, kbc->mmio + KBC_INT_0); + spin_unlock_irqrestore(&kbc->lock, flags); + + enable_irq(kbc->irq); + + return 0; +} + +static void tegra_kbc_stop(struct tegra_kbc *kbc) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&kbc->lock, flags); + val = readl(kbc->mmio + KBC_CONTROL_0); + val &= ~1; + writel(val, kbc->mmio + KBC_CONTROL_0); + spin_unlock_irqrestore(&kbc->lock, flags); + + disable_irq(kbc->irq); + del_timer_sync(&kbc->timer); + + clk_disable(kbc->clk); +} + +static int tegra_kbc_open(struct input_dev *dev) +{ + struct tegra_kbc *kbc = input_get_drvdata(dev); + + return tegra_kbc_start(kbc); +} + +static void tegra_kbc_close(struct input_dev *dev) +{ + struct tegra_kbc *kbc = input_get_drvdata(dev); + + return tegra_kbc_stop(kbc); +} + +static bool __devinit +tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata, + struct device *dev, unsigned int *num_rows) +{ + int i; + + *num_rows = 0; + + for (i = 0; i < KBC_MAX_GPIO; i++) { + const struct tegra_kbc_pin_cfg *pin_cfg = &pdata->pin_cfg[i]; + + if (pin_cfg->is_row) { + if (pin_cfg->num >= KBC_MAX_ROW) { + dev_err(dev, + "pin_cfg[%d]: invalid row number %d\n", + i, pin_cfg->num); + return false; + } + (*num_rows)++; + } else { + if (pin_cfg->num >= KBC_MAX_COL) { + dev_err(dev, + "pin_cfg[%d]: invalid column number %d\n", + i, pin_cfg->num); + return false; + } + } + } + + return true; +} + +static int __devinit tegra_kbc_probe(struct platform_device *pdev) +{ + const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data; + const struct matrix_keymap_data *keymap_data; + struct tegra_kbc *kbc; + struct input_dev *input_dev; + struct resource *res; + int irq; + int err; + int i; + int num_rows = 0; + unsigned int debounce_cnt; + unsigned int scan_time_rows; + + if (!pdata) + return -EINVAL; + + if (!tegra_kbc_check_pin_cfg(pdata, &pdev->dev, &num_rows)) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to get I/O memory\n"); + return -ENXIO; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get keyboard IRQ\n"); + return -ENXIO; + } + + kbc = kzalloc(sizeof(*kbc), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!kbc || !input_dev) { + err = -ENOMEM; + goto err_free_mem; + } + + kbc->pdata = pdata; + kbc->idev = input_dev; + kbc->irq = irq; + spin_lock_init(&kbc->lock); + setup_timer(&kbc->timer, tegra_kbc_keypress_timer, (unsigned long)kbc); + + res = request_mem_region(res->start, resource_size(res), pdev->name); + if (!res) { + dev_err(&pdev->dev, "failed to request I/O memory\n"); + err = -EBUSY; + goto err_free_mem; + } + + kbc->mmio = ioremap(res->start, resource_size(res)); + if (!kbc->mmio) { + dev_err(&pdev->dev, "failed to remap I/O memory\n"); + err = -ENXIO; + goto err_free_mem_region; + } + + kbc->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(kbc->clk)) { + dev_err(&pdev->dev, "failed to get keyboard clock\n"); + err = PTR_ERR(kbc->clk); + goto err_iounmap; + } + + kbc->wake_enable_rows = 0; + kbc->wake_enable_cols = 0; + for (i = 0; i < pdata->wake_cnt; i++) { + kbc->wake_enable_rows |= (1 << pdata->wake_cfg[i].row); + kbc->wake_enable_cols |= (1 << pdata->wake_cfg[i].col); + } + + /* + * The time delay between two consecutive reads of the FIFO is + * the sum of the repeat time and the time taken for scanning + * the rows. There is an additional delay before the row scanning + * starts. The repoll delay is computed in milliseconds. + */ + debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT); + scan_time_rows = (KBC_ROW_SCAN_TIME + debounce_cnt) * num_rows; + kbc->repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + pdata->repeat_cnt; + kbc->repoll_dly = ((kbc->repoll_dly * KBC_CYCLE_USEC) + 999) / 1000; + + input_dev->name = pdev->name; + input_dev->id.bustype = BUS_HOST; + input_dev->dev.parent = &pdev->dev; + input_dev->open = tegra_kbc_open; + input_dev->close = tegra_kbc_close; + + input_set_drvdata(input_dev, kbc); + + input_dev->evbit[0] = BIT_MASK(EV_KEY); + input_set_capability(input_dev, EV_MSC, MSC_SCAN); + + input_dev->keycode = kbc->keycode; + input_dev->keycodesize = sizeof(kbc->keycode[0]); + input_dev->keycodemax = ARRAY_SIZE(kbc->keycode); + + keymap_data = pdata->keymap_data ?: &tegra_kbc_default_keymap_data; + matrix_keypad_build_keymap(keymap_data, KBC_ROW_SHIFT, + input_dev->keycode, input_dev->keybit); + + err = request_irq(kbc->irq, tegra_kbc_isr, IRQF_TRIGGER_HIGH, + pdev->name, kbc); + if (err) { + dev_err(&pdev->dev, "failed to request keyboard IRQ\n"); + goto err_put_clk; + } + + disable_irq(kbc->irq); + + err = input_register_device(kbc->idev); + if (err) { + dev_err(&pdev->dev, "failed to register input device\n"); + goto err_free_irq; + } + + platform_set_drvdata(pdev, kbc); + device_init_wakeup(&pdev->dev, pdata->wakeup); + + return 0; + +err_free_irq: + free_irq(kbc->irq, pdev); +err_put_clk: + clk_put(kbc->clk); +err_iounmap: + iounmap(kbc->mmio); +err_free_mem_region: + release_mem_region(res->start, resource_size(res)); +err_free_mem: + input_free_device(kbc->idev); + kfree(kbc); + + return err; +} + +static int __devexit tegra_kbc_remove(struct platform_device *pdev) +{ + struct tegra_kbc *kbc = platform_get_drvdata(pdev); + struct resource *res; + + free_irq(kbc->irq, pdev); + clk_put(kbc->clk); + + input_unregister_device(kbc->idev); + iounmap(kbc->mmio); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + + kfree(kbc); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int tegra_kbc_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct tegra_kbc *kbc = platform_get_drvdata(pdev); + + if (device_may_wakeup(&pdev->dev)) { + tegra_kbc_setup_wakekeys(kbc, true); + enable_irq_wake(kbc->irq); + /* Forcefully clear the interrupt status */ + writel(0x7, kbc->mmio + KBC_INT_0); + msleep(30); + } else { + mutex_lock(&kbc->idev->mutex); + if (kbc->idev->users) + tegra_kbc_stop(kbc); + mutex_unlock(&kbc->idev->mutex); + } + + return 0; +} + +static int tegra_kbc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct tegra_kbc *kbc = platform_get_drvdata(pdev); + int err = 0; + + if (device_may_wakeup(&pdev->dev)) { + disable_irq_wake(kbc->irq); + tegra_kbc_setup_wakekeys(kbc, false); + } else { + mutex_lock(&kbc->idev->mutex); + if (kbc->idev->users) + err = tegra_kbc_start(kbc); + mutex_unlock(&kbc->idev->mutex); + } + + return err; +} +#endif + +static SIMPLE_DEV_PM_OPS(tegra_kbc_pm_ops, tegra_kbc_suspend, tegra_kbc_resume); + +static struct platform_driver tegra_kbc_driver = { + .probe = tegra_kbc_probe, + .remove = __devexit_p(tegra_kbc_remove), + .driver = { + .name = "tegra-kbc", + .owner = THIS_MODULE, + .pm = &tegra_kbc_pm_ops, + }, +}; + +static void __exit tegra_kbc_exit(void) +{ + platform_driver_unregister(&tegra_kbc_driver); +} +module_exit(tegra_kbc_exit); + +static int __init tegra_kbc_init(void) +{ + return platform_driver_register(&tegra_kbc_driver); +} +module_init(tegra_kbc_init); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Rakesh Iyer <riyer@nvidia.com>"); +MODULE_DESCRIPTION("Tegra matrix keyboard controller driver"); +MODULE_ALIAS("platform:tegra-kbc"); diff --git a/drivers/input/keyboard/tnetv107x-keypad.c b/drivers/input/keyboard/tnetv107x-keypad.c index b4a81ebfab92..c8f097a15d89 100644 --- a/drivers/input/keyboard/tnetv107x-keypad.c +++ b/drivers/input/keyboard/tnetv107x-keypad.c @@ -14,6 +14,7 @@ */ #include <linux/kernel.h> +#include <linux/err.h> #include <linux/errno.h> #include <linux/input.h> #include <linux/platform_device.h> @@ -219,9 +220,9 @@ static int __devinit keypad_probe(struct platform_device *pdev) } kp->clk = clk_get(dev, NULL); - if (!kp->clk) { + if (IS_ERR(kp->clk)) { dev_err(dev, "cannot claim device clock\n"); - error = -EINVAL; + error = PTR_ERR(kp->clk); goto error_clk; } diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c index 9dfd6e5f786f..1f38302a5951 100644 --- a/drivers/input/misc/ixp4xx-beeper.c +++ b/drivers/input/misc/ixp4xx-beeper.c @@ -69,11 +69,7 @@ static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned } if (value > 20 && value < 32767) -#ifndef FREQ - count = (ixp4xx_get_board_tick_rate() / (value * 4)) - 1; -#else - count = (FREQ / (value * 4)) - 1; -#endif + count = (IXP4XX_TIMER_FREQ / (value * 4)) - 1; ixp4xx_spkr_control(pin, count); diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 1f8e0108962e..7e64d01da2be 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -176,7 +176,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) /* request the IRQs */ err = request_irq(encoder->irq_a, &rotary_encoder_irq, - IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, DRV_NAME, encoder); if (err) { dev_err(&pdev->dev, "unable to request IRQ %d\n", @@ -185,7 +185,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) } err = request_irq(encoder->irq_b, &rotary_encoder_irq, - IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, DRV_NAME, encoder); if (err) { dev_err(&pdev->dev, "unable to request IRQ %d\n", diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index da392c22fc6c..aa186cf6c514 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -755,23 +755,26 @@ static int synaptics_reconnect(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; struct synaptics_data old_priv = *priv; + int retry = 0; + int error; - psmouse_reset(psmouse); + do { + psmouse_reset(psmouse); + error = synaptics_detect(psmouse, 0); + } while (error && ++retry < 3); - if (synaptics_detect(psmouse, 0)) + if (error) return -1; + if (retry > 1) + printk(KERN_DEBUG "Synaptics reconnected after %d tries\n", + retry); + if (synaptics_query_hardware(psmouse)) { printk(KERN_ERR "Unable to query Synaptics hardware.\n"); return -1; } - if (old_priv.identity != priv->identity || - old_priv.model_id != priv->model_id || - old_priv.capabilities != priv->capabilities || - old_priv.ext_cap != priv->ext_cap) - return -1; - if (synaptics_set_absolute_mode(psmouse)) { printk(KERN_ERR "Unable to initialize Synaptics hardware.\n"); return -1; @@ -782,6 +785,19 @@ static int synaptics_reconnect(struct psmouse *psmouse) return -1; } + if (old_priv.identity != priv->identity || + old_priv.model_id != priv->model_id || + old_priv.capabilities != priv->capabilities || + old_priv.ext_cap != priv->ext_cap) { + printk(KERN_ERR "Synaptics hardware appears to be different: " + "id(%ld-%ld), model(%ld-%ld), caps(%lx-%lx), ext(%lx-%lx).\n", + old_priv.identity, priv->identity, + old_priv.model_id, priv->model_id, + old_priv.capabilities, priv->capabilities, + old_priv.ext_cap, priv->ext_cap); + return -1; + } + return 0; } diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c index 448c7724beb9..852816567241 100644 --- a/drivers/input/serio/ct82c710.c +++ b/drivers/input/serio/ct82c710.c @@ -111,9 +111,11 @@ static void ct82c710_close(struct serio *serio) static int ct82c710_open(struct serio *serio) { unsigned char status; + int err; - if (request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL)) - return -1; + err = request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL); + if (err) + return err; status = inb_p(CT82C710_STATUS); @@ -131,7 +133,7 @@ static int ct82c710_open(struct serio *serio) status &= ~(CT82C710_ENABLE | CT82C710_INTS_ON); outb_p(status, CT82C710_STATUS); free_irq(CT82C710_IRQ, NULL); - return -1; + return -EBUSY; } return 0; diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index db5b0bca1a1a..7c38d1fbabf2 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -188,7 +188,8 @@ static void serio_free_event(struct serio_event *event) kfree(event); } -static void serio_remove_duplicate_events(struct serio_event *event) +static void serio_remove_duplicate_events(void *object, + enum serio_event_type type) { struct serio_event *e, *next; unsigned long flags; @@ -196,13 +197,13 @@ static void serio_remove_duplicate_events(struct serio_event *event) spin_lock_irqsave(&serio_event_lock, flags); list_for_each_entry_safe(e, next, &serio_event_list, node) { - if (event->object == e->object) { + if (object == e->object) { /* * If this event is of different type we should not * look further - we only suppress duplicate events * that were sent back-to-back. */ - if (event->type != e->type) + if (type != e->type) break; list_del_init(&e->node); @@ -245,7 +246,7 @@ static void serio_handle_event(struct work_struct *work) break; } - serio_remove_duplicate_events(event); + serio_remove_duplicate_events(event->object, event->type); serio_free_event(event); } @@ -436,10 +437,12 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute * } else if (!strncmp(buf, "rescan", count)) { serio_disconnect_port(serio); serio_find_driver(serio); + serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT); } else if ((drv = driver_find(buf, &serio_bus)) != NULL) { serio_disconnect_port(serio); error = serio_bind_driver(serio, to_serio_driver(drv)); put_driver(drv); + serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT); } else { error = -EINVAL; } diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 6e362de3f412..8755f5f3ad37 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -116,14 +116,15 @@ static void serport_ldisc_close(struct tty_struct *tty) /* * serport_ldisc_receive() is called by the low level tty driver when characters - * are ready for us. We forward the characters, one by one to the 'interrupt' - * routine. + * are ready for us. We forward the characters and flags, one by one to the + * 'interrupt' routine. */ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { struct serport *serport = (struct serport*) tty->disc_data; unsigned long flags; + unsigned int ch_flags; int i; spin_lock_irqsave(&serport->lock, flags); @@ -131,8 +132,23 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c if (!test_bit(SERPORT_ACTIVE, &serport->flags)) goto out; - for (i = 0; i < count; i++) - serio_interrupt(serport->serio, cp[i], 0); + for (i = 0; i < count; i++) { + switch (fp[i]) { + case TTY_FRAME: + ch_flags = SERIO_FRAME; + break; + + case TTY_PARITY: + ch_flags = SERIO_PARITY; + break; + + default: + ch_flags = 0; + break; + } + + serio_interrupt(serport->serio, cp[i], ch_flags); + } out: spin_unlock_irqrestore(&serport->lock, flags); diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index a29a7812bd46..7729e547ba65 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -201,6 +201,7 @@ int sparse_keymap_setup(struct input_dev *dev, break; case KE_SW: + case KE_VSW: __set_bit(EV_SW, dev->evbit); __set_bit(entry->sw.code, dev->swbit); break; diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index fc381498b798..cf8fb9f5d4a8 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -519,7 +519,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i /* Retrieve the physical and logical size for OEM devices */ error = wacom_retrieve_hid_descriptor(intf, features); if (error) - goto fail2; + goto fail3; wacom_setup_device_quirks(features); diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 518782999fea..367fa82a607e 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -1101,6 +1101,13 @@ void wacom_setup_device_quirks(struct wacom_features *features) } } +static unsigned int wacom_calculate_touch_res(unsigned int logical_max, + unsigned int physical_max) +{ + /* Touch physical dimensions are in 100th of mm */ + return (logical_max * 100) / physical_max; +} + void wacom_setup_input_capabilities(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { @@ -1228,8 +1235,12 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, case TABLETPC: if (features->device_type == BTN_TOOL_DOUBLETAP || features->device_type == BTN_TOOL_TRIPLETAP) { - input_set_abs_params(input_dev, ABS_RX, 0, features->x_phy, 0, 0); - input_set_abs_params(input_dev, ABS_RY, 0, features->y_phy, 0, 0); + input_abs_set_res(input_dev, ABS_X, + wacom_calculate_touch_res(features->x_max, + features->x_phy)); + input_abs_set_res(input_dev, ABS_Y, + wacom_calculate_touch_res(features->y_max, + features->y_phy)); __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); } @@ -1272,6 +1283,12 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, features->pressure_max, features->pressure_fuzz, 0); + input_abs_set_res(input_dev, ABS_X, + wacom_calculate_touch_res(features->x_max, + features->x_phy)); + input_abs_set_res(input_dev, ABS_Y, + wacom_calculate_touch_res(features->y_max, + features->y_phy)); } else if (features->device_type == BTN_TOOL_PEN) { __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); __set_bit(BTN_TOOL_PEN, input_dev->keybit); @@ -1426,6 +1443,10 @@ static struct wacom_features wacom_features_0xD3 = { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT }; static const struct wacom_features wacom_features_0xD4 = { "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 255, 63, BAMBOO_PT }; +static struct wacom_features wacom_features_0xD6 = + { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; +static struct wacom_features wacom_features_0xD7 = + { "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; static struct wacom_features wacom_features_0xD8 = { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT }; static struct wacom_features wacom_features_0xDA = @@ -1507,6 +1528,8 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0xD2) }, { USB_DEVICE_WACOM(0xD3) }, { USB_DEVICE_WACOM(0xD4) }, + { USB_DEVICE_WACOM(0xD6) }, + { USB_DEVICE_WACOM(0xD7) }, { USB_DEVICE_WACOM(0xD8) }, { USB_DEVICE_WACOM(0xDA) }, { USB_DEVICE_WACOM(0xDB) }, diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 14ea54b78e46..4bf2316e3284 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -941,28 +941,29 @@ static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads784 struct ads7846_platform_data *pdata = spi->dev.platform_data; int err; - /* REVISIT when the irq can be triggered active-low, or if for some + /* + * REVISIT when the irq can be triggered active-low, or if for some * reason the touchscreen isn't hooked up, we don't need to access * the pendown state. */ - if (!pdata->get_pendown_state && !gpio_is_valid(pdata->gpio_pendown)) { - dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n"); - return -EINVAL; - } if (pdata->get_pendown_state) { ts->get_pendown_state = pdata->get_pendown_state; - return 0; - } + } else if (gpio_is_valid(pdata->gpio_pendown)) { - err = gpio_request(pdata->gpio_pendown, "ads7846_pendown"); - if (err) { - dev_err(&spi->dev, "failed to request pendown GPIO%d\n", - pdata->gpio_pendown); - return err; - } + err = gpio_request(pdata->gpio_pendown, "ads7846_pendown"); + if (err) { + dev_err(&spi->dev, "failed to request pendown GPIO%d\n", + pdata->gpio_pendown); + return err; + } - ts->gpio_pendown = pdata->gpio_pendown; + ts->gpio_pendown = pdata->gpio_pendown; + + } else { + dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n"); + return -EINVAL; + } return 0; } @@ -1353,7 +1354,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) err_put_regulator: regulator_put(ts->reg); err_free_gpio: - if (ts->gpio_pendown != -1) + if (!ts->get_pendown_state) gpio_free(ts->gpio_pendown); err_cleanup_filter: if (ts->filter_cleanup) @@ -1383,8 +1384,13 @@ static int __devexit ads7846_remove(struct spi_device *spi) regulator_disable(ts->reg); regulator_put(ts->reg); - if (ts->gpio_pendown != -1) + if (!ts->get_pendown_state) { + /* + * If we are not using specialized pendown method we must + * have been relying on gpio we set up ourselves. + */ gpio_free(ts->gpio_pendown); + } if (ts->filter_cleanup) ts->filter_cleanup(ts->filter_data); diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c index f7fa9ef4cd65..1507ce108d5b 100644 --- a/drivers/input/touchscreen/bu21013_ts.c +++ b/drivers/input/touchscreen/bu21013_ts.c @@ -12,6 +12,7 @@ #include <linux/input.h> #include <linux/input/bu21013.h> #include <linux/slab.h> +#include <linux/regulator/consumer.h> #define PEN_DOWN_INTR 0 #define MAX_FINGERS 2 @@ -139,6 +140,7 @@ * @chip: pointer to the touch panel controller * @in_dev: pointer to the input device structure * @intr_pin: interrupt pin value + * @regulator: pointer to the Regulator used for touch screen * * Touch panel device data structure */ @@ -149,6 +151,7 @@ struct bu21013_ts_data { const struct bu21013_platform_device *chip; struct input_dev *in_dev; unsigned int intr_pin; + struct regulator *regulator; }; /** @@ -456,6 +459,20 @@ static int __devinit bu21013_probe(struct i2c_client *client, bu21013_data->in_dev = in_dev; bu21013_data->chip = pdata; bu21013_data->client = client; + + bu21013_data->regulator = regulator_get(&client->dev, "V-TOUCH"); + if (IS_ERR(bu21013_data->regulator)) { + dev_err(&client->dev, "regulator_get failed\n"); + error = PTR_ERR(bu21013_data->regulator); + goto err_free_mem; + } + + error = regulator_enable(bu21013_data->regulator); + if (error < 0) { + dev_err(&client->dev, "regulator enable failed\n"); + goto err_put_regulator; + } + bu21013_data->touch_stopped = false; init_waitqueue_head(&bu21013_data->wait); @@ -464,7 +481,7 @@ static int __devinit bu21013_probe(struct i2c_client *client, error = pdata->cs_en(pdata->cs_pin); if (error < 0) { dev_err(&client->dev, "chip init failed\n"); - goto err_free_mem; + goto err_disable_regulator; } } @@ -485,9 +502,9 @@ static int __devinit bu21013_probe(struct i2c_client *client, __set_bit(EV_ABS, in_dev->evbit); input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0, - pdata->x_max_res, 0, 0); + pdata->touch_x_max, 0, 0); input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0, - pdata->y_max_res, 0, 0); + pdata->touch_y_max, 0, 0); input_set_drvdata(in_dev, bu21013_data); error = request_threaded_irq(pdata->irq, NULL, bu21013_gpio_irq, @@ -513,6 +530,10 @@ err_free_irq: bu21013_free_irq(bu21013_data); err_cs_disable: pdata->cs_dis(pdata->cs_pin); +err_disable_regulator: + regulator_disable(bu21013_data->regulator); +err_put_regulator: + regulator_put(bu21013_data->regulator); err_free_mem: input_free_device(in_dev); kfree(bu21013_data); @@ -535,6 +556,10 @@ static int __devexit bu21013_remove(struct i2c_client *client) bu21013_data->chip->cs_dis(bu21013_data->chip->cs_pin); input_unregister_device(bu21013_data->in_dev); + + regulator_disable(bu21013_data->regulator); + regulator_put(bu21013_data->regulator); + kfree(bu21013_data); device_init_wakeup(&client->dev, false); @@ -561,6 +586,8 @@ static int bu21013_suspend(struct device *dev) else disable_irq(bu21013_data->chip->irq); + regulator_disable(bu21013_data->regulator); + return 0; } @@ -577,6 +604,12 @@ static int bu21013_resume(struct device *dev) struct i2c_client *client = bu21013_data->client; int retval; + retval = regulator_enable(bu21013_data->regulator); + if (retval < 0) { + dev_err(&client->dev, "bu21013 regulator enable failed\n"); + return retval; + } + retval = bu21013_init_chip(bu21013_data); if (retval < 0) { dev_err(&client->dev, "bu21013 controller config failed\n"); diff --git a/drivers/input/touchscreen/tnetv107x-ts.c b/drivers/input/touchscreen/tnetv107x-ts.c index cf1dba2e267c..22a3411e93c5 100644 --- a/drivers/input/touchscreen/tnetv107x-ts.c +++ b/drivers/input/touchscreen/tnetv107x-ts.c @@ -14,6 +14,7 @@ */ #include <linux/kernel.h> +#include <linux/err.h> #include <linux/errno.h> #include <linux/input.h> #include <linux/platform_device.h> @@ -289,9 +290,9 @@ static int __devinit tsc_probe(struct platform_device *pdev) } ts->clk = clk_get(dev, NULL); - if (!ts->clk) { + if (IS_ERR(ts->clk)) { dev_err(dev, "cannot claim device clock\n"); - error = -EINVAL; + error = PTR_ERR(ts->clk); goto error_clk; } diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c index 5cb8449c909d..c14412ef4648 100644 --- a/drivers/input/touchscreen/wacom_w8001.c +++ b/drivers/input/touchscreen/wacom_w8001.c @@ -51,6 +51,10 @@ MODULE_LICENSE("GPL"); #define W8001_PKTLEN_TPCCTL 11 /* control packet */ #define W8001_PKTLEN_TOUCH2FG 13 +/* resolution in points/mm */ +#define W8001_PEN_RESOLUTION 100 +#define W8001_TOUCH_RESOLUTION 10 + struct w8001_coord { u8 rdy; u8 tsw; @@ -198,7 +202,7 @@ static void parse_touchquery(u8 *data, struct w8001_touch_query *query) query->y = 1024; if (query->panel_res) query->x = query->y = (1 << query->panel_res); - query->panel_res = 10; + query->panel_res = W8001_TOUCH_RESOLUTION; } } @@ -394,6 +398,8 @@ static int w8001_setup(struct w8001 *w8001) input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0); input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0); + input_abs_set_res(dev, ABS_X, W8001_PEN_RESOLUTION); + input_abs_set_res(dev, ABS_Y, W8001_PEN_RESOLUTION); input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0); if (coord.tilt_x && coord.tilt_y) { input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0); @@ -418,14 +424,17 @@ static int w8001_setup(struct w8001 *w8001) w8001->max_touch_x = touch.x; w8001->max_touch_y = touch.y; - /* scale to pen maximum */ if (w8001->max_pen_x && w8001->max_pen_y) { + /* if pen is supported scale to pen maximum */ touch.x = w8001->max_pen_x; touch.y = w8001->max_pen_y; + touch.panel_res = W8001_PEN_RESOLUTION; } input_set_abs_params(dev, ABS_X, 0, touch.x, 0, 0); input_set_abs_params(dev, ABS_Y, 0, touch.y, 0, 0); + input_abs_set_res(dev, ABS_X, touch.panel_res); + input_abs_set_res(dev, ABS_Y, touch.panel_res); switch (touch.sensor_id) { case 0: diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c index 0858791978d8..cfff0c41d298 100644 --- a/drivers/isdn/hisax/isdnl2.c +++ b/drivers/isdn/hisax/isdnl2.c @@ -1247,10 +1247,10 @@ static void l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct sk_buff *skb, *oskb; + struct sk_buff *skb; struct Layer2 *l2 = &st->l2; u_char header[MAX_HEADER_LEN]; - int i; + int i, hdr_space_needed; int unsigned p1; u_long flags; @@ -1261,6 +1261,16 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) if (!skb) return; + hdr_space_needed = l2headersize(l2, 0); + if (hdr_space_needed > skb_headroom(skb)) { + struct sk_buff *orig_skb = skb; + + skb = skb_realloc_headroom(skb, hdr_space_needed); + if (!skb) { + dev_kfree_skb(orig_skb); + return; + } + } spin_lock_irqsave(&l2->lock, flags); if(test_bit(FLG_MOD128, &l2->flag)) p1 = (l2->vs - l2->va) % 128; @@ -1285,19 +1295,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) l2->vs = (l2->vs + 1) % 8; } spin_unlock_irqrestore(&l2->lock, flags); - p1 = skb->data - skb->head; - if (p1 >= i) - memcpy(skb_push(skb, i), header, i); - else { - printk(KERN_WARNING - "isdl2 pull_iqueue skb header(%d/%d) too short\n", i, p1); - oskb = skb; - skb = alloc_skb(oskb->len + i, GFP_ATOMIC); - memcpy(skb_put(skb, i), header, i); - skb_copy_from_linear_data(oskb, - skb_put(skb, oskb->len), oskb->len); - dev_kfree_skb(oskb); - } + memcpy(skb_push(skb, i), header, i); st->l2.l2l1(st, PH_PULL | INDICATION, skb); test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) { diff --git a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h index 729df4089385..18b801ad97a4 100644 --- a/drivers/isdn/hysdn/hysdn_defs.h +++ b/drivers/isdn/hysdn/hysdn_defs.h @@ -227,7 +227,6 @@ extern hysdn_card *card_root; /* pointer to first card */ /*************************/ /* im/exported functions */ /*************************/ -extern char *hysdn_getrev(const char *); /* hysdn_procconf.c */ extern int hysdn_procconf_init(void); /* init proc config filesys */ @@ -259,7 +258,6 @@ extern int hysdn_tx_cfgline(hysdn_card *, unsigned char *, /* hysdn_net.c */ extern unsigned int hynet_enable; -extern char *hysdn_net_revision; extern int hysdn_net_create(hysdn_card *); /* create a new net device */ extern int hysdn_net_release(hysdn_card *); /* delete the device */ extern char *hysdn_net_getname(hysdn_card *); /* get name of net interface */ diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c index b7cc5c2f08c6..0ab42ace1692 100644 --- a/drivers/isdn/hysdn/hysdn_init.c +++ b/drivers/isdn/hysdn/hysdn_init.c @@ -36,7 +36,6 @@ MODULE_DESCRIPTION("ISDN4Linux: Driver for HYSDN cards"); MODULE_AUTHOR("Werner Cornelius"); MODULE_LICENSE("GPL"); -static char *hysdn_init_revision = "$Revision: 1.6.6.6 $"; static int cardmax; /* number of found cards */ hysdn_card *card_root = NULL; /* pointer to first card */ static hysdn_card *card_last = NULL; /* pointer to first card */ @@ -49,25 +48,6 @@ static hysdn_card *card_last = NULL; /* pointer to first card */ /* Additionally newer versions may be activated without rebooting. */ /****************************************************************************/ -/******************************************************/ -/* extract revision number from string for log output */ -/******************************************************/ -char * -hysdn_getrev(const char *revision) -{ - char *rev; - char *p; - - if ((p = strchr(revision, ':'))) { - rev = p + 2; - p = strchr(rev, '$'); - *--p = 0; - } else - rev = "???"; - return rev; -} - - /****************************************************************************/ /* init_module is called once when the module is loaded to do all necessary */ /* things like autodetect... */ @@ -175,13 +155,9 @@ static int hysdn_have_procfs; static int __init hysdn_init(void) { - char tmp[50]; int rc; - strcpy(tmp, hysdn_init_revision); - printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp)); - strcpy(tmp, hysdn_net_revision); - printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp)); + printk(KERN_NOTICE "HYSDN: module loaded\n"); rc = pci_register_driver(&hysdn_pci_driver); if (rc) diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c index feec8d89d719..11f2cce26005 100644 --- a/drivers/isdn/hysdn/hysdn_net.c +++ b/drivers/isdn/hysdn/hysdn_net.c @@ -26,9 +26,6 @@ unsigned int hynet_enable = 0xffffffff; module_param(hynet_enable, uint, 0); -/* store the actual version for log reporting */ -char *hysdn_net_revision = "$Revision: 1.8.6.4 $"; - #define MAX_SKB_BUFFERS 20 /* number of buffers for keeping TX-data */ /****************************************************************************/ diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c index 96b3e39c3356..5fe83bd42061 100644 --- a/drivers/isdn/hysdn/hysdn_procconf.c +++ b/drivers/isdn/hysdn/hysdn_procconf.c @@ -23,7 +23,6 @@ #include "hysdn_defs.h" static DEFINE_MUTEX(hysdn_conf_mutex); -static char *hysdn_procconf_revision = "$Revision: 1.8.6.4 $"; #define INFO_OUT_LEN 80 /* length of info line including lf */ @@ -404,7 +403,7 @@ hysdn_procconf_init(void) card = card->next; /* next entry */ } - printk(KERN_NOTICE "HYSDN: procfs Rev. %s initialised\n", hysdn_getrev(hysdn_procconf_revision)); + printk(KERN_NOTICE "HYSDN: procfs initialised\n"); return (0); } /* hysdn_procconf_init */ diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index da3fa8dcdf5b..666daf77872e 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -69,6 +69,7 @@ static int led_pwm_probe(struct platform_device *pdev) led_dat->pwm = pwm_request(cur_led->pwm_id, cur_led->name); if (IS_ERR(led_dat->pwm)) { + ret = PTR_ERR(led_dat->pwm); dev_err(&pdev->dev, "unable to request PWM %d\n", cur_led->pwm_id); goto err; diff --git a/drivers/md/md.c b/drivers/md/md.c index b76cfc89e1b5..0cc30ecda4c1 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -287,6 +287,7 @@ static int md_make_request(struct request_queue *q, struct bio *bio) mddev_t *mddev = q->queuedata; int rv; int cpu; + unsigned int sectors; if (mddev == NULL || mddev->pers == NULL || !mddev->ready) { @@ -311,12 +312,16 @@ static int md_make_request(struct request_queue *q, struct bio *bio) atomic_inc(&mddev->active_io); rcu_read_unlock(); + /* + * save the sectors now since our bio can + * go away inside make_request + */ + sectors = bio_sectors(bio); rv = mddev->pers->make_request(mddev, bio); cpu = part_stat_lock(); part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]); - part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw], - bio_sectors(bio)); + part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw], sectors); part_stat_unlock(); if (atomic_dec_and_test(&mddev->active_io) && mddev->suspended) @@ -1947,8 +1952,6 @@ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev, int shared) __bdevname(dev, b)); return PTR_ERR(bdev); } - if (!shared) - set_bit(AllReserved, &rdev->flags); rdev->bdev = bdev; return err; } @@ -2465,6 +2468,9 @@ slot_store(mdk_rdev_t *rdev, const char *buf, size_t len) if (rdev->raid_disk != -1) return -EBUSY; + if (test_bit(MD_RECOVERY_RUNNING, &rdev->mddev->recovery)) + return -EBUSY; + if (rdev->mddev->pers->hot_add_disk == NULL) return -EINVAL; @@ -2610,12 +2616,11 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len) mddev_lock(mddev); list_for_each_entry(rdev2, &mddev->disks, same_set) - if (test_bit(AllReserved, &rdev2->flags) || - (rdev->bdev == rdev2->bdev && - rdev != rdev2 && - overlaps(rdev->data_offset, rdev->sectors, - rdev2->data_offset, - rdev2->sectors))) { + if (rdev->bdev == rdev2->bdev && + rdev != rdev2 && + overlaps(rdev->data_offset, rdev->sectors, + rdev2->data_offset, + rdev2->sectors)) { overlap = 1; break; } @@ -5578,6 +5583,8 @@ static int update_raid_disks(mddev_t *mddev, int raid_disks) mddev->delta_disks = raid_disks - mddev->raid_disks; rv = mddev->pers->check_reshape(mddev); + if (rv < 0) + mddev->delta_disks = 0; return rv; } @@ -6985,9 +6992,6 @@ void md_do_sync(mddev_t *mddev) } else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) mddev->resync_min = mddev->curr_resync_completed; mddev->curr_resync = 0; - if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) - mddev->curr_resync_completed = 0; - sysfs_notify(&mddev->kobj, NULL, "sync_completed"); wake_up(&resync_wait); set_bit(MD_RECOVERY_DONE, &mddev->recovery); md_wakeup_thread(mddev->thread); @@ -7028,7 +7032,7 @@ static int remove_and_add_spares(mddev_t *mddev) } } - if (mddev->degraded && ! mddev->ro && !mddev->recovery_disabled) { + if (mddev->degraded && !mddev->recovery_disabled) { list_for_each_entry(rdev, &mddev->disks, same_set) { if (rdev->raid_disk >= 0 && !test_bit(In_sync, &rdev->flags) && @@ -7151,7 +7155,20 @@ void md_check_recovery(mddev_t *mddev) /* Only thing we do on a ro array is remove * failed devices. */ - remove_and_add_spares(mddev); + mdk_rdev_t *rdev; + list_for_each_entry(rdev, &mddev->disks, same_set) + if (rdev->raid_disk >= 0 && + !test_bit(Blocked, &rdev->flags) && + test_bit(Faulty, &rdev->flags) && + atomic_read(&rdev->nr_pending)==0) { + if (mddev->pers->hot_remove_disk( + mddev, rdev->raid_disk)==0) { + char nm[20]; + sprintf(nm,"rd%d", rdev->raid_disk); + sysfs_remove_link(&mddev->kobj, nm); + rdev->raid_disk = -1; + } + } clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery); goto unlock; } diff --git a/drivers/md/md.h b/drivers/md/md.h index eec517ced31a..7e90b8593b2a 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -93,8 +93,6 @@ struct mdk_rdev_s #define Faulty 1 /* device is known to have a fault */ #define In_sync 2 /* device is in_sync with rest of array */ #define WriteMostly 4 /* Avoid reading if at all possible */ -#define AllReserved 6 /* If whole device is reserved for - * one array */ #define AutoDetected 7 /* added by auto-detect */ #define Blocked 8 /* An error occured on an externally * managed array, don't allow writes diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index a39f4c355e55..637a96855edb 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -179,6 +179,14 @@ static int create_strip_zones(mddev_t *mddev, raid0_conf_t **private_conf) rdev1->new_raid_disk = j; } + if (mddev->level == 1) { + /* taiking over a raid1 array- + * we have only one active disk + */ + j = 0; + rdev1->new_raid_disk = j; + } + if (j < 0 || j >= mddev->raid_disks) { printk(KERN_ERR "md/raid0:%s: bad disk number %d - " "aborting!\n", mdname(mddev), j); @@ -644,12 +652,38 @@ static void *raid0_takeover_raid10(mddev_t *mddev) return priv_conf; } +static void *raid0_takeover_raid1(mddev_t *mddev) +{ + raid0_conf_t *priv_conf; + + /* Check layout: + * - (N - 1) mirror drives must be already faulty + */ + if ((mddev->raid_disks - 1) != mddev->degraded) { + printk(KERN_ERR "md/raid0:%s: (N - 1) mirrors drives must be already faulty!\n", + mdname(mddev)); + return ERR_PTR(-EINVAL); + } + + /* Set new parameters */ + mddev->new_level = 0; + mddev->new_layout = 0; + mddev->new_chunk_sectors = 128; /* by default set chunk size to 64k */ + mddev->delta_disks = 1 - mddev->raid_disks; + /* make sure it will be not marked as dirty */ + mddev->recovery_cp = MaxSector; + + create_strip_zones(mddev, &priv_conf); + return priv_conf; +} + static void *raid0_takeover(mddev_t *mddev) { /* raid0 can take over: * raid4 - if all data disks are active. * raid5 - providing it is Raid4 layout and one disk is faulty * raid10 - assuming we have all necessary active disks + * raid1 - with (N -1) mirror drives faulty */ if (mddev->level == 4) return raid0_takeover_raid45(mddev); @@ -665,6 +699,12 @@ static void *raid0_takeover(mddev_t *mddev) if (mddev->level == 10) return raid0_takeover_raid10(mddev); + if (mddev->level == 1) + return raid0_takeover_raid1(mddev); + + printk(KERN_ERR "Takeover from raid%i to raid0 not supported\n", + mddev->level); + return ERR_PTR(-EINVAL); } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 69b659544390..3b607b28741b 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -2463,11 +2463,13 @@ static void *raid10_takeover_raid0(mddev_t *mddev) mddev->recovery_cp = MaxSector; conf = setup_conf(mddev); - if (!IS_ERR(conf)) + if (!IS_ERR(conf)) { list_for_each_entry(rdev, &mddev->disks, same_set) if (rdev->raid_disk >= 0) rdev->new_raid_disk = rdev->raid_disk * 2; - + conf->barrier = 1; + } + return conf; } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 5044babfcda0..702812824195 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5517,7 +5517,6 @@ static int raid5_start_reshape(mddev_t *mddev) raid5_conf_t *conf = mddev->private; mdk_rdev_t *rdev; int spares = 0; - int added_devices = 0; unsigned long flags; if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) @@ -5527,8 +5526,8 @@ static int raid5_start_reshape(mddev_t *mddev) return -ENOSPC; list_for_each_entry(rdev, &mddev->disks, same_set) - if ((rdev->raid_disk < 0 || rdev->raid_disk >= conf->raid_disks) - && !test_bit(Faulty, &rdev->flags)) + if (!test_bit(In_sync, &rdev->flags) + && !test_bit(Faulty, &rdev->flags)) spares++; if (spares - mddev->degraded < mddev->delta_disks - conf->max_degraded) @@ -5571,34 +5570,35 @@ static int raid5_start_reshape(mddev_t *mddev) * to correctly record the "partially reconstructed" state of * such devices during the reshape and confusion could result. */ - if (mddev->delta_disks >= 0) - list_for_each_entry(rdev, &mddev->disks, same_set) - if (rdev->raid_disk < 0 && - !test_bit(Faulty, &rdev->flags)) { - if (raid5_add_disk(mddev, rdev) == 0) { - char nm[20]; - if (rdev->raid_disk >= conf->previous_raid_disks) { - set_bit(In_sync, &rdev->flags); - added_devices++; - } else - rdev->recovery_offset = 0; - sprintf(nm, "rd%d", rdev->raid_disk); - if (sysfs_create_link(&mddev->kobj, - &rdev->kobj, nm)) - /* Failure here is OK */; - } else - break; - } else if (rdev->raid_disk >= conf->previous_raid_disks - && !test_bit(Faulty, &rdev->flags)) { - /* This is a spare that was manually added */ - set_bit(In_sync, &rdev->flags); - added_devices++; - } + if (mddev->delta_disks >= 0) { + int added_devices = 0; + list_for_each_entry(rdev, &mddev->disks, same_set) + if (rdev->raid_disk < 0 && + !test_bit(Faulty, &rdev->flags)) { + if (raid5_add_disk(mddev, rdev) == 0) { + char nm[20]; + if (rdev->raid_disk + >= conf->previous_raid_disks) { + set_bit(In_sync, &rdev->flags); + added_devices++; + } else + rdev->recovery_offset = 0; + sprintf(nm, "rd%d", rdev->raid_disk); + if (sysfs_create_link(&mddev->kobj, + &rdev->kobj, nm)) + /* Failure here is OK */; + } + } else if (rdev->raid_disk >= conf->previous_raid_disks + && !test_bit(Faulty, &rdev->flags)) { + /* This is a spare that was manually added */ + set_bit(In_sync, &rdev->flags); + added_devices++; + } - /* When a reshape changes the number of devices, ->degraded - * is measured against the larger of the pre and post number of - * devices.*/ - if (mddev->delta_disks > 0) { + /* When a reshape changes the number of devices, + * ->degraded is measured against the larger of the + * pre and post number of devices. + */ spin_lock_irqsave(&conf->device_lock, flags); mddev->degraded += (conf->raid_disks - conf->previous_raid_disks) - added_devices; diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index f011c5d9dea1..1c5cc65ea1e1 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -1,4 +1,4 @@ -/* ir-lirc-codec.c - ir-core to classic lirc interface bridge +/* ir-lirc-codec.c - rc-core to classic lirc interface bridge * * Copyright (C) 2010 by Jarod Wilson <jarod@redhat.com> * @@ -47,6 +47,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) /* Carrier reports */ if (ev.carrier_report) { sample = LIRC_FREQUENCY(ev.carrier); + IR_dprintk(2, "carrier report (freq: %d)\n", sample); /* Packet end */ } else if (ev.timeout) { @@ -62,6 +63,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) return 0; sample = LIRC_TIMEOUT(ev.duration / 1000); + IR_dprintk(2, "timeout report (duration: %d)\n", sample); /* Normal sample */ } else { @@ -85,6 +87,8 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) : LIRC_SPACE(ev.duration / 1000); + IR_dprintk(2, "delivering %uus %s to lirc_dev\n", + TO_US(ev.duration), TO_STR(ev.pulse)); } lirc_buffer_write(dev->raw->lirc.drv->rbuf, diff --git a/drivers/media/rc/keymaps/rc-rc6-mce.c b/drivers/media/rc/keymaps/rc-rc6-mce.c index 3bf3337875d1..2f5dc0622b94 100644 --- a/drivers/media/rc/keymaps/rc-rc6-mce.c +++ b/drivers/media/rc/keymaps/rc-rc6-mce.c @@ -3,6 +3,9 @@ * * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com> * + * See http://mediacenterguides.com/book/export/html/31 for details on + * key mappings. + * * 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 @@ -60,6 +63,9 @@ static struct rc_map_table rc6_mce[] = { { 0x800f0426, KEY_EPG }, /* Guide */ { 0x800f0427, KEY_ZOOM }, /* Aspect */ + { 0x800f0432, KEY_MODE }, /* Visualization */ + { 0x800f0433, KEY_PRESENTATION }, /* Slide Show */ + { 0x800f0434, KEY_EJECTCD }, { 0x800f043a, KEY_BRIGHTNESSUP }, { 0x800f0446, KEY_TV }, diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 079353e5d558..6df0a4980645 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -816,7 +816,7 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index) switch (ir->buf_in[index]) { /* 2-byte return value commands */ case MCE_CMD_S_TIMEOUT: - ir->rc->timeout = MS_TO_NS((hi << 8 | lo) / 2); + ir->rc->timeout = US_TO_NS((hi << 8 | lo) / 2); break; /* 1-byte return value commands */ @@ -855,9 +855,10 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) break; case PARSE_IRDATA: ir->rem--; + init_ir_raw_event(&rawir); rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0); rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK) - * MS_TO_US(MCE_TIME_UNIT); + * US_TO_NS(MCE_TIME_UNIT); dev_dbg(ir->dev, "Storing %s with duration %d\n", rawir.pulse ? "pulse" : "space", @@ -883,6 +884,8 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) i, ir->rem + 1, false); if (ir->rem) ir->parser_state = PARSE_IRDATA; + else + ir_raw_event_reset(ir->rc); break; } @@ -1060,7 +1063,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) rc->priv = ir; rc->driver_type = RC_DRIVER_IR_RAW; rc->allowed_protos = RC_TYPE_ALL; - rc->timeout = MS_TO_NS(1000); + rc->timeout = US_TO_NS(1000); if (!ir->flags.no_tx) { rc->s_tx_mask = mceusb_set_tx_mask; rc->s_tx_carrier = mceusb_set_tx_carrier; diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index dd4caf8ef80b..273d9d674792 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -460,7 +460,7 @@ static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt) return 0; } - carrier = (count * 1000000) / duration; + carrier = MS_TO_NS(count) / duration; if ((carrier > MAX_CARRIER) || (carrier < MIN_CARRIER)) nvt_dbg("WTF? Carrier frequency out of range!"); @@ -612,8 +612,8 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt) sample = nvt->buf[i]; rawir.pulse = ((sample & BUF_PULSE_BIT) != 0); - rawir.duration = (sample & BUF_LEN_MASK) - * SAMPLE_PERIOD * 1000; + rawir.duration = US_TO_NS((sample & BUF_LEN_MASK) + * SAMPLE_PERIOD); if ((sample & BUF_LEN_MASK) == BUF_LEN_MASK) { if (nvt->rawir.pulse == rawir.pulse) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 72be8a02118c..512a2f4ada0e 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -458,21 +458,27 @@ static int ir_getkeycode(struct input_dev *idev, index = ir_lookup_by_scancode(rc_map, scancode); } - if (index >= rc_map->len) { - if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) - IR_dprintk(1, "unknown key for scancode 0x%04x\n", - scancode); + if (index < rc_map->len) { + entry = &rc_map->scan[index]; + + ke->index = index; + ke->keycode = entry->keycode; + ke->len = sizeof(entry->scancode); + memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode)); + + } else if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) { + /* + * We do not really know the valid range of scancodes + * so let's respond with KEY_RESERVED to anything we + * do not have mapping for [yet]. + */ + ke->index = index; + ke->keycode = KEY_RESERVED; + } else { retval = -EINVAL; goto out; } - entry = &rc_map->scan[index]; - - ke->index = index; - ke->keycode = entry->keycode; - ke->len = sizeof(entry->scancode); - memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode)); - retval = 0; out: diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index 6e2911c2abfb..e435d94c0776 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c @@ -164,7 +164,7 @@ static void sz_push_full_pulse(struct streamzap_ir *sz, sz->signal_start.tv_usec - sz->signal_last.tv_usec); rawir.duration -= sz->sum; - rawir.duration *= 1000; + rawir.duration = US_TO_NS(rawir.duration); rawir.duration &= IR_MAX_DURATION; } sz_push(sz, rawir); @@ -177,7 +177,7 @@ static void sz_push_full_pulse(struct streamzap_ir *sz, rawir.duration = ((int) value) * SZ_RESOLUTION; rawir.duration += SZ_RESOLUTION / 2; sz->sum += rawir.duration; - rawir.duration *= 1000; + rawir.duration = US_TO_NS(rawir.duration); rawir.duration &= IR_MAX_DURATION; sz_push(sz, rawir); } @@ -197,7 +197,7 @@ static void sz_push_full_space(struct streamzap_ir *sz, rawir.duration = ((int) value) * SZ_RESOLUTION; rawir.duration += SZ_RESOLUTION / 2; sz->sum += rawir.duration; - rawir.duration *= 1000; + rawir.duration = US_TO_NS(rawir.duration); sz_push(sz, rawir); } @@ -273,6 +273,7 @@ static void streamzap_callback(struct urb *urb) if (sz->timeout_enabled) sz_push(sz, rawir); ir_raw_event_handle(sz->rdev); + ir_raw_event_reset(sz->rdev); } else { sz_push_full_space(sz, sz->buf_in[i]); } @@ -290,6 +291,7 @@ static void streamzap_callback(struct urb *urb) } } + ir_raw_event_handle(sz->rdev); usb_submit_urb(urb, GFP_ATOMIC); return; @@ -430,13 +432,13 @@ static int __devinit streamzap_probe(struct usb_interface *intf, sz->decoder_state = PulseSpace; /* FIXME: don't yet have a way to set this */ sz->timeout_enabled = true; - sz->rdev->timeout = (((SZ_TIMEOUT * SZ_RESOLUTION * 1000) & + sz->rdev->timeout = ((US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION) & IR_MAX_DURATION) | 0x03000000); #if 0 /* not yet supported, depends on patches from maxim */ /* see also: LIRC_GET_REC_RESOLUTION and LIRC_SET_REC_TIMEOUT */ - sz->min_timeout = SZ_TIMEOUT * SZ_RESOLUTION * 1000; - sz->max_timeout = SZ_TIMEOUT * SZ_RESOLUTION * 1000; + sz->min_timeout = US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION); + sz->max_timeout = US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION); #endif do_gettimeofday(&sz->signal_start); diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index 865216e9362c..47236a58bf33 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -5793,7 +5793,7 @@ static void usb_exchange(struct gspca_dev *gspca_dev, break; default: /* case 0xdd: * delay */ - msleep(action->val / 64 + 10); + msleep(action->idx); break; } action++; @@ -5830,7 +5830,7 @@ static void setmatrix(struct gspca_dev *gspca_dev) [SENSOR_GC0305] = gc0305_matrix, [SENSOR_HDCS2020b] = NULL, [SENSOR_HV7131B] = NULL, - [SENSOR_HV7131R] = NULL, + [SENSOR_HV7131R] = po2030_matrix, [SENSOR_ICM105A] = po2030_matrix, [SENSOR_MC501CB] = NULL, [SENSOR_MT9V111_1] = gc0305_matrix, @@ -5936,6 +5936,7 @@ static void setquality(struct gspca_dev *gspca_dev) case SENSOR_ADCM2700: case SENSOR_GC0305: case SENSOR_HV7131B: + case SENSOR_HV7131R: case SENSOR_OV7620: case SENSOR_PAS202B: case SENSOR_PO2030: @@ -6108,11 +6109,13 @@ static void send_unknown(struct gspca_dev *gspca_dev, int sensor) reg_w(gspca_dev, 0x02, 0x003b); reg_w(gspca_dev, 0x00, 0x0038); break; + case SENSOR_HV7131R: case SENSOR_PAS202B: reg_w(gspca_dev, 0x03, 0x003b); reg_w(gspca_dev, 0x0c, 0x003a); reg_w(gspca_dev, 0x0b, 0x0039); - reg_w(gspca_dev, 0x0b, 0x0038); + if (sensor == SENSOR_PAS202B) + reg_w(gspca_dev, 0x0b, 0x0038); break; } } @@ -6704,10 +6707,13 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x02, 0x003b); reg_w(gspca_dev, 0x00, 0x0038); break; + case SENSOR_HV7131R: case SENSOR_PAS202B: reg_w(gspca_dev, 0x03, 0x003b); reg_w(gspca_dev, 0x0c, 0x003a); reg_w(gspca_dev, 0x0b, 0x0039); + if (sd->sensor == SENSOR_HV7131R) + reg_w(gspca_dev, 0x50, ZC3XX_R11D_GLOBALGAIN); break; } @@ -6720,6 +6726,7 @@ static int sd_start(struct gspca_dev *gspca_dev) break; case SENSOR_PAS202B: case SENSOR_GC0305: + case SENSOR_HV7131R: case SENSOR_TAS5130C: reg_r(gspca_dev, 0x0008); /* fall thru */ @@ -6760,6 +6767,12 @@ static int sd_start(struct gspca_dev *gspca_dev) /* ms-win + */ reg_w(gspca_dev, 0x40, 0x0117); break; + case SENSOR_HV7131R: + i2c_write(gspca_dev, 0x25, 0x04, 0x00); /* exposure */ + i2c_write(gspca_dev, 0x26, 0x93, 0x00); + i2c_write(gspca_dev, 0x27, 0xe0, 0x00); + reg_w(gspca_dev, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN); + break; case SENSOR_GC0305: case SENSOR_TAS5130C: reg_w(gspca_dev, 0x09, 0x01ad); /* (from win traces) */ @@ -6808,9 +6821,17 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; - if (data[0] == 0xff && data[1] == 0xd8) { /* start of frame */ + /* check the JPEG end of frame */ + if (len >= 3 + && data[len - 3] == 0xff && data[len - 2] == 0xd9) { +/*fixme: what does the last byte mean?*/ gspca_frame_add(gspca_dev, LAST_PACKET, - NULL, 0); + data, len - 1); + return; + } + + /* check the JPEG start of a frame */ + if (data[0] == 0xff && data[1] == 0xd8) { /* put the JPEG header in the new frame */ gspca_frame_add(gspca_dev, FIRST_PACKET, sd->jpeg_hdr, JPEG_HDR_SZ); diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c index a6572e5ae369..a27d93b503a5 100644 --- a/drivers/media/video/hdpvr/hdpvr-core.c +++ b/drivers/media/video/hdpvr/hdpvr-core.c @@ -283,6 +283,7 @@ static int hdpvr_probe(struct usb_interface *interface, struct hdpvr_device *dev; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; + struct i2c_client *client; size_t buffer_size; int i; int retval = -ENOMEM; @@ -381,13 +382,21 @@ static int hdpvr_probe(struct usb_interface *interface, #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) retval = hdpvr_register_i2c_adapter(dev); if (retval < 0) { - v4l2_err(&dev->v4l2_dev, "registering i2c adapter failed\n"); + v4l2_err(&dev->v4l2_dev, "i2c adapter register failed\n"); goto error; } - retval = hdpvr_register_i2c_ir(dev); - if (retval < 0) - v4l2_err(&dev->v4l2_dev, "registering i2c IR devices failed\n"); + client = hdpvr_register_ir_rx_i2c(dev); + if (!client) { + v4l2_err(&dev->v4l2_dev, "i2c IR RX device register failed\n"); + goto reg_fail; + } + + client = hdpvr_register_ir_tx_i2c(dev); + if (!client) { + v4l2_err(&dev->v4l2_dev, "i2c IR TX device register failed\n"); + goto reg_fail; + } #endif /* let the user know what node this device is now attached to */ @@ -395,6 +404,10 @@ static int hdpvr_probe(struct usb_interface *interface, video_device_node_name(dev->video_dev)); return 0; +reg_fail: +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_adapter(&dev->i2c_adapter); +#endif error: if (dev) { /* Destroy single thread */ @@ -424,6 +437,9 @@ static void hdpvr_disconnect(struct usb_interface *interface) mutex_lock(&dev->io_mutex); hdpvr_cancel_queue(dev); mutex_unlock(&dev->io_mutex); +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_adapter(&dev->i2c_adapter); +#endif video_unregister_device(dev->video_dev); atomic_dec(&dev_nr); } diff --git a/drivers/media/video/hdpvr/hdpvr-i2c.c b/drivers/media/video/hdpvr/hdpvr-i2c.c index 89b71faeaac2..e53fa55d56a1 100644 --- a/drivers/media/video/hdpvr/hdpvr-i2c.c +++ b/drivers/media/video/hdpvr/hdpvr-i2c.c @@ -31,26 +31,34 @@ #define Z8F0811_IR_RX_I2C_ADDR 0x71 -static struct i2c_board_info hdpvr_i2c_board_info = { - I2C_BOARD_INFO("ir_tx_z8f0811_hdpvr", Z8F0811_IR_TX_I2C_ADDR), - I2C_BOARD_INFO("ir_rx_z8f0811_hdpvr", Z8F0811_IR_RX_I2C_ADDR), -}; +struct i2c_client *hdpvr_register_ir_tx_i2c(struct hdpvr_device *dev) +{ + struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data; + struct i2c_board_info hdpvr_ir_tx_i2c_board_info = { + I2C_BOARD_INFO("ir_tx_z8f0811_hdpvr", Z8F0811_IR_TX_I2C_ADDR), + }; + + init_data->name = "HD-PVR"; + hdpvr_ir_tx_i2c_board_info.platform_data = init_data; -int hdpvr_register_i2c_ir(struct hdpvr_device *dev) + return i2c_new_device(&dev->i2c_adapter, &hdpvr_ir_tx_i2c_board_info); +} + +struct i2c_client *hdpvr_register_ir_rx_i2c(struct hdpvr_device *dev) { - struct i2c_client *c; struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data; + struct i2c_board_info hdpvr_ir_rx_i2c_board_info = { + I2C_BOARD_INFO("ir_rx_z8f0811_hdpvr", Z8F0811_IR_RX_I2C_ADDR), + }; /* Our default information for ir-kbd-i2c.c to use */ init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; init_data->type = RC_TYPE_RC5; - init_data->name = "HD PVR"; - hdpvr_i2c_board_info.platform_data = init_data; - - c = i2c_new_device(&dev->i2c_adapter, &hdpvr_i2c_board_info); + init_data->name = "HD-PVR"; + hdpvr_ir_rx_i2c_board_info.platform_data = init_data; - return (c == NULL) ? -ENODEV : 0; + return i2c_new_device(&dev->i2c_adapter, &hdpvr_ir_rx_i2c_board_info); } static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus, diff --git a/drivers/media/video/hdpvr/hdpvr.h b/drivers/media/video/hdpvr/hdpvr.h index ee74e3be9a6a..072f23c570f3 100644 --- a/drivers/media/video/hdpvr/hdpvr.h +++ b/drivers/media/video/hdpvr/hdpvr.h @@ -313,7 +313,8 @@ int hdpvr_cancel_queue(struct hdpvr_device *dev); /* i2c adapter registration */ int hdpvr_register_i2c_adapter(struct hdpvr_device *dev); -int hdpvr_register_i2c_ir(struct hdpvr_device *dev); +struct i2c_client *hdpvr_register_ir_rx_i2c(struct hdpvr_device *dev); +struct i2c_client *hdpvr_register_ir_tx_i2c(struct hdpvr_device *dev); /*========================================================================*/ /* buffer management */ diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index d2b20ad383a3..a221ad68b330 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -128,6 +128,19 @@ static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) static int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { + int ret; + unsigned char buf[1] = { 0 }; + + /* + * This is the same apparent "are you ready?" poll command observed + * watching Windows driver traffic and implemented in lirc_zilog. With + * this added, we get far saner remote behavior with z8 chips on usb + * connected devices, even with the default polling interval of 100ms. + */ + ret = i2c_master_send(ir->c, buf, 1); + if (ret != 1) + return (ret < 0) ? ret : -EINVAL; + return get_key_haup_common (ir, ir_key, ir_raw, 6, 3); } diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index ccc884948f34..451ecd485f97 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -597,7 +597,6 @@ static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw) init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; init_data->type = RC_TYPE_RC5; init_data->name = hdw->hdw_desc->description; - init_data->polling_interval = 260; /* ms From lirc_zilog */ /* IR Receiver */ info.addr = 0x71; info.platform_data = init_data; diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index f35459d1f42f..0db90922ee93 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -1565,7 +1565,7 @@ static int saa711x_probe(struct i2c_client *client, chip_id = name[5]; /* Check whether this chip is part of the saa711x series */ - if (memcmp(name, "1f711", 5)) { + if (memcmp(name + 1, "f711", 4)) { v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n", client->addr << 1, name); return -ENODEV; diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c index e9a3eab7b0cf..8c1d85e27be4 100644 --- a/drivers/memstick/core/memstick.c +++ b/drivers/memstick/core/memstick.c @@ -621,7 +621,7 @@ static int __init memstick_init(void) { int rc; - workqueue = create_freezeable_workqueue("kmemstick"); + workqueue = create_freezable_workqueue("kmemstick"); if (!workqueue) return -ENOMEM; diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index f71f22948477..1735c84ff757 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -76,8 +76,8 @@ #define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.04.17" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.17" +#define MPT_LINUX_VERSION_COMMON "3.04.18" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.18" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index a3856ed90aef..e8deb8ed0499 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -597,6 +597,13 @@ mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) } static int +mptctl_release(struct inode *inode, struct file *filep) +{ + fasync_helper(-1, filep, 0, &async_queue); + return 0; +} + +static int mptctl_fasync(int fd, struct file *filep, int mode) { MPT_ADAPTER *ioc; @@ -2815,6 +2822,7 @@ static const struct file_operations mptctl_fops = { .llseek = no_llseek, .fasync = mptctl_fasync, .unlocked_ioctl = mptctl_ioctl, + .release = mptctl_release, #ifdef CONFIG_COMPAT .compat_ioctl = compat_mpctl_ioctl, #endif diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 59b8f53d1ece..0d9b82a44540 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -1873,8 +1873,9 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) } out: - printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n", - ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), SCpnt); + printk(MYIOC_s_INFO_FMT "task abort: %s (rv=%04x) (sc=%p) (sn=%ld)\n", + ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), retval, + SCpnt, SCpnt->serial_number); return retval; } @@ -1911,7 +1912,7 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt) vdevice = SCpnt->device->hostdata; if (!vdevice || !vdevice->vtarget) { - retval = SUCCESS; + retval = 0; goto out; } diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c index 5f6852dff40b..44d4475a09dd 100644 --- a/drivers/misc/tifm_core.c +++ b/drivers/misc/tifm_core.c @@ -329,7 +329,7 @@ static int __init tifm_init(void) { int rc; - workqueue = create_freezeable_workqueue("tifm"); + workqueue = create_freezable_workqueue("tifm"); if (!workqueue) return -ENOMEM; diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 4d2ea8e80140..6df5a55da110 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -785,7 +785,7 @@ static int __init vmballoon_init(void) if (x86_hyper != &x86_hyper_vmware) return -ENODEV; - vmballoon_wq = create_freezeable_workqueue("vmmemctl"); + vmballoon_wq = create_freezable_workqueue("vmmemctl"); if (!vmballoon_wq) { pr_err("failed to create workqueue\n"); return -ENOMEM; diff --git a/drivers/mmc/host/bfin_sdh.c b/drivers/mmc/host/bfin_sdh.c index bac7d62866b7..0371bf502249 100644 --- a/drivers/mmc/host/bfin_sdh.c +++ b/drivers/mmc/host/bfin_sdh.c @@ -462,7 +462,7 @@ static int __devinit sdh_probe(struct platform_device *pdev) goto out; } - mmc = mmc_alloc_host(sizeof(*mmc), &pdev->dev); + mmc = mmc_alloc_host(sizeof(struct sdh_host), &pdev->dev); if (!mmc) { ret = -ENOMEM; goto out; diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index b3a0ab0e4c2b..74218ad677e4 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -14,6 +14,7 @@ */ #include <linux/mmc/host.h> +#include <linux/err.h> #include <linux/io.h> #include <linux/irq.h> #include <linux/interrupt.h> @@ -827,8 +828,8 @@ static int __devinit jz4740_mmc_probe(struct platform_device* pdev) } host->clk = clk_get(&pdev->dev, "mmc"); - if (!host->clk) { - ret = -ENOENT; + if (IS_ERR(host->clk)) { + ret = PTR_ERR(host->clk); dev_err(&pdev->dev, "Failed to get mmc clock\n"); goto err_free_host; } diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 563022825667..2d6de3e03e2d 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -14,6 +14,7 @@ #include <linux/ioport.h> #include <linux/device.h> #include <linux/interrupt.h> +#include <linux/kernel.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/highmem.h> @@ -46,10 +47,6 @@ static unsigned int fmax = 515633; * is asserted (likewise for RX) * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY * is asserted (likewise for RX) - * @broken_blockend: the MCI_DATABLOCKEND is broken on the hardware - * and will not work at all. - * @broken_blockend_dma: the MCI_DATABLOCKEND is broken on the hardware when - * using DMA. * @sdio: variant supports SDIO * @st_clkdiv: true if using a ST-specific clock divider algorithm */ @@ -59,8 +56,6 @@ struct variant_data { unsigned int datalength_bits; unsigned int fifosize; unsigned int fifohalfsize; - bool broken_blockend; - bool broken_blockend_dma; bool sdio; bool st_clkdiv; }; @@ -76,7 +71,6 @@ static struct variant_data variant_u300 = { .fifohalfsize = 8 * 4, .clkreg_enable = 1 << 13, /* HWFCEN */ .datalength_bits = 16, - .broken_blockend_dma = true, .sdio = true, }; @@ -86,7 +80,6 @@ static struct variant_data variant_ux500 = { .clkreg = MCI_CLK_ENABLE, .clkreg_enable = 1 << 14, /* HWFCEN */ .datalength_bits = 24, - .broken_blockend = true, .sdio = true, .st_clkdiv = true, }; @@ -210,8 +203,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) host->data = data; host->size = data->blksz * data->blocks; host->data_xfered = 0; - host->blockend = false; - host->dataend = false; mmci_init_sg(host, data); @@ -288,21 +279,26 @@ static void mmci_data_irq(struct mmci_host *host, struct mmc_data *data, unsigned int status) { - struct variant_data *variant = host->variant; - /* First check for errors */ if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { + u32 remain, success; + + /* Calculate how far we are into the transfer */ + remain = readl(host->base + MMCIDATACNT); + success = data->blksz * data->blocks - remain; + dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status); - if (status & MCI_DATACRCFAIL) + if (status & MCI_DATACRCFAIL) { + /* Last block was not successful */ + host->data_xfered = round_down(success - 1, data->blksz); data->error = -EILSEQ; - else if (status & MCI_DATATIMEOUT) + } else if (status & MCI_DATATIMEOUT) { + host->data_xfered = round_down(success, data->blksz); data->error = -ETIMEDOUT; - else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) + } else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) { + host->data_xfered = round_down(success, data->blksz); data->error = -EIO; - - /* Force-complete the transaction */ - host->blockend = true; - host->dataend = true; + } /* * We hit an error condition. Ensure that any data @@ -321,61 +317,14 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, } } - /* - * On ARM variants in PIO mode, MCI_DATABLOCKEND - * is always sent first, and we increase the - * transfered number of bytes for that IRQ. Then - * MCI_DATAEND follows and we conclude the transaction. - * - * On the Ux500 single-IRQ variant MCI_DATABLOCKEND - * doesn't seem to immediately clear from the status, - * so we can't use it keep count when only one irq is - * used because the irq will hit for other reasons, and - * then the flag is still up. So we use the MCI_DATAEND - * IRQ at the end of the entire transfer because - * MCI_DATABLOCKEND is broken. - * - * In the U300, the IRQs can arrive out-of-order, - * e.g. MCI_DATABLOCKEND sometimes arrives after MCI_DATAEND, - * so for this case we use the flags "blockend" and - * "dataend" to make sure both IRQs have arrived before - * concluding the transaction. (This does not apply - * to the Ux500 which doesn't fire MCI_DATABLOCKEND - * at all.) In DMA mode it suffers from the same problem - * as the Ux500. - */ - if (status & MCI_DATABLOCKEND) { - /* - * Just being a little over-cautious, we do not - * use this progressive update if the hardware blockend - * flag is unreliable: since it can stay high between - * IRQs it will corrupt the transfer counter. - */ - if (!variant->broken_blockend) - host->data_xfered += data->blksz; - host->blockend = true; - } - - if (status & MCI_DATAEND) - host->dataend = true; + if (status & MCI_DATABLOCKEND) + dev_err(mmc_dev(host->mmc), "stray MCI_DATABLOCKEND interrupt\n"); - /* - * On variants with broken blockend we shall only wait for dataend, - * on others we must sync with the blockend signal since they can - * appear out-of-order. - */ - if (host->dataend && (host->blockend || variant->broken_blockend)) { + if (status & MCI_DATAEND || data->error) { mmci_stop_data(host); - /* Reset these flags */ - host->blockend = false; - host->dataend = false; - - /* - * Variants with broken blockend flags need to handle the - * end of the entire transfer here. - */ - if (variant->broken_blockend && !data->error) + if (!data->error) + /* The error clause is handled above, success! */ host->data_xfered += data->blksz * data->blocks; if (!data->stop) { @@ -394,15 +343,15 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, host->cmd = NULL; - cmd->resp[0] = readl(base + MMCIRESPONSE0); - cmd->resp[1] = readl(base + MMCIRESPONSE1); - cmd->resp[2] = readl(base + MMCIRESPONSE2); - cmd->resp[3] = readl(base + MMCIRESPONSE3); - if (status & MCI_CMDTIMEOUT) { cmd->error = -ETIMEDOUT; } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { cmd->error = -EILSEQ; + } else { + cmd->resp[0] = readl(base + MMCIRESPONSE0); + cmd->resp[1] = readl(base + MMCIRESPONSE1); + cmd->resp[2] = readl(base + MMCIRESPONSE2); + cmd->resp[3] = readl(base + MMCIRESPONSE3); } if (!cmd->data || cmd->error) { @@ -770,7 +719,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) struct variant_data *variant = id->data; struct mmci_host *host; struct mmc_host *mmc; - unsigned int mask; int ret; /* must have platform data */ @@ -951,12 +899,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) goto irq0_free; } - mask = MCI_IRQENABLE; - /* Don't use the datablockend flag if it's broken */ - if (variant->broken_blockend) - mask &= ~MCI_DATABLOCKEND; - - writel(mask, host->base + MMCIMASK0); + writel(MCI_IRQENABLE, host->base + MMCIMASK0); amba_set_drvdata(dev, mmc); diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index df06f01aac89..c1df7b82d36c 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -137,7 +137,7 @@ #define MCI_IRQENABLE \ (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \ MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ - MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK) + MCI_CMDRESPENDMASK|MCI_CMDSENTMASK) /* These interrupts are directed to IRQ1 when two IRQ lines are available */ #define MCI_IRQ1MASK \ @@ -177,9 +177,6 @@ struct mmci_host { struct timer_list timer; unsigned int oldstat; - bool blockend; - bool dataend; - /* pio stuff */ struct sg_mapping_iter sg_miter; unsigned int size; diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 5decfd0bd61d..153ab977a013 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -383,14 +383,30 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) host->curr.user_pages = 0; box = &nc->cmd[0]; - for (i = 0; i < host->dma.num_ents; i++) { - box->cmd = CMD_MODE_BOX; - /* Initialize sg dma address */ - sg->dma_address = page_to_dma(mmc_dev(host->mmc), sg_page(sg)) - + sg->offset; + /* location of command block must be 64 bit aligned */ + BUG_ON(host->dma.cmd_busaddr & 0x07); - if (i == (host->dma.num_ents - 1)) + nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP; + host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST | + DMOV_CMD_ADDR(host->dma.cmdptr_busaddr); + host->dma.hdr.complete_func = msmsdcc_dma_complete_func; + + n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, + host->dma.num_ents, host->dma.dir); + if (n == 0) { + printk(KERN_ERR "%s: Unable to map in all sg elements\n", + mmc_hostname(host->mmc)); + host->dma.sg = NULL; + host->dma.num_ents = 0; + return -ENOMEM; + } + + for_each_sg(host->dma.sg, sg, n, i) { + + box->cmd = CMD_MODE_BOX; + + if (i == n - 1) box->cmd |= CMD_LC; rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ? (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 : @@ -418,27 +434,6 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) box->cmd |= CMD_DST_CRCI(crci); } box++; - sg++; - } - - /* location of command block must be 64 bit aligned */ - BUG_ON(host->dma.cmd_busaddr & 0x07); - - nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP; - host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST | - DMOV_CMD_ADDR(host->dma.cmdptr_busaddr); - host->dma.hdr.complete_func = msmsdcc_dma_complete_func; - - n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, - host->dma.num_ents, host->dma.dir); -/* dsb inside dma_map_sg will write nc out to mem as well */ - - if (n != host->dma.num_ents) { - printk(KERN_ERR "%s: Unable to map in all sg elements\n", - mmc_hostname(host->mmc)); - host->dma.sg = NULL; - host->dma.num_ents = 0; - return -ENOMEM; } return 0; @@ -1331,9 +1326,6 @@ msmsdcc_probe(struct platform_device *pdev) if (host->timer.function) pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc)); -#if BUSCLK_PWRSAVE - msmsdcc_disable_clocks(host, 1); -#endif return 0; cmd_irq_free: free_irq(cmd_irqres->start, host); diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 17203586305c..5309ab95aada 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -277,10 +277,43 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) host->clock = clock; } +/** + * sdhci_s3c_platform_8bit_width - support 8bit buswidth + * @host: The SDHCI host being queried + * @width: MMC_BUS_WIDTH_ macro for the bus width being requested + * + * We have 8-bit width support but is not a v3 controller. + * So we add platform_8bit_width() and support 8bit width. + */ +static int sdhci_s3c_platform_8bit_width(struct sdhci_host *host, int width) +{ + u8 ctrl; + + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); + + switch (width) { + case MMC_BUS_WIDTH_8: + ctrl |= SDHCI_CTRL_8BITBUS; + ctrl &= ~SDHCI_CTRL_4BITBUS; + break; + case MMC_BUS_WIDTH_4: + ctrl |= SDHCI_CTRL_4BITBUS; + ctrl &= ~SDHCI_CTRL_8BITBUS; + break; + default: + break; + } + + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); + + return 0; +} + static struct sdhci_ops sdhci_s3c_ops = { .get_max_clock = sdhci_s3c_get_max_clk, .set_clock = sdhci_s3c_set_clock, .get_min_clock = sdhci_s3c_get_min_clock, + .platform_8bit_width = sdhci_s3c_platform_8bit_width, }; static void sdhci_s3c_notify_change(struct platform_device *dev, int state) @@ -473,6 +506,9 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) if (pdata->cd_type == S3C_SDHCI_CD_PERMANENT) host->mmc->caps = MMC_CAP_NONREMOVABLE; + if (pdata->host_caps) + host->mmc->caps |= pdata->host_caps; + host->quirks |= (SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_32BIT_DMA_SIZE); diff --git a/drivers/mmc/host/ushc.c b/drivers/mmc/host/ushc.c index f8f65df9b017..f08f944ac53c 100644 --- a/drivers/mmc/host/ushc.c +++ b/drivers/mmc/host/ushc.c @@ -19,7 +19,6 @@ #include <linux/module.h> #include <linux/usb.h> #include <linux/kernel.h> -#include <linux/usb.h> #include <linux/slab.h> #include <linux/dma-mapping.h> #include <linux/mmc/host.h> diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index d9d7efbc77cc..6322d1fb5d62 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -930,7 +930,7 @@ int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) init_completion(&dev->dma_done); - dev->card_workqueue = create_freezeable_workqueue(DRV_NAME); + dev->card_workqueue = create_freezable_workqueue(DRV_NAME); if (!dev->card_workqueue) goto error9; diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index 67822cf6c025..ac0d6a8613b5 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -1258,7 +1258,7 @@ static struct mtd_blktrans_ops sm_ftl_ops = { static __init int sm_module_init(void) { int error = 0; - cache_flush_workqueue = create_freezeable_workqueue("smflush"); + cache_flush_workqueue = create_freezable_workqueue("smflush"); if (IS_ERR(cache_flush_workqueue)) return PTR_ERR(cache_flush_workqueue); diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index f49e49dc5928..5ebe280225d6 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -672,33 +672,7 @@ static int io_init(struct ubi_device *ubi) ubi->nor_flash = 1; } - /* - * Set UBI min. I/O size (@ubi->min_io_size). We use @mtd->writebufsize - * for these purposes, not @mtd->writesize. At the moment this does not - * matter for NAND, because currently @mtd->writebufsize is equivalent to - * @mtd->writesize for all NANDs. However, some CFI NOR flashes may - * have @mtd->writebufsize which is multiple of @mtd->writesize. - * - * The reason we use @mtd->writebufsize for @ubi->min_io_size is that - * UBI and UBIFS recovery algorithms rely on the fact that if there was - * an unclean power cut, then we can find offset of the last corrupted - * node, align the offset to @ubi->min_io_size, read the rest of the - * eraseblock starting from this offset, and check whether there are - * only 0xFF bytes. If yes, then we are probably dealing with a - * corruption caused by a power cut, if not, then this is probably some - * severe corruption. - * - * Thus, we have to use the maximum write unit size of the flash, which - * is @mtd->writebufsize, because @mtd->writesize is the minimum write - * size, not the maximum. - */ - if (ubi->mtd->type == MTD_NANDFLASH) - ubi_assert(ubi->mtd->writebufsize == ubi->mtd->writesize); - else if (ubi->mtd->type == MTD_NORFLASH) - ubi_assert(ubi->mtd->writebufsize % ubi->mtd->writesize == 0); - - ubi->min_io_size = ubi->mtd->writebufsize; - + ubi->min_io_size = ubi->mtd->writesize; ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft; /* diff --git a/drivers/net/atl1c/atl1c_hw.c b/drivers/net/atl1c/atl1c_hw.c index 1bf672009948..23f2ab0f2fa8 100644 --- a/drivers/net/atl1c/atl1c_hw.c +++ b/drivers/net/atl1c/atl1c_hw.c @@ -345,7 +345,7 @@ int atl1c_write_phy_reg(struct atl1c_hw *hw, u32 reg_addr, u16 phy_data) */ static int atl1c_phy_setup_adv(struct atl1c_hw *hw) { - u16 mii_adv_data = ADVERTISE_DEFAULT_CAP & ~ADVERTISE_SPEED_MASK; + u16 mii_adv_data = ADVERTISE_DEFAULT_CAP & ~ADVERTISE_ALL; u16 mii_giga_ctrl_data = GIGA_CR_1000T_DEFAULT_CAP & ~GIGA_CR_1000T_SPEED_MASK; @@ -373,7 +373,7 @@ static int atl1c_phy_setup_adv(struct atl1c_hw *hw) } if (atl1c_write_phy_reg(hw, MII_ADVERTISE, mii_adv_data) != 0 || - atl1c_write_phy_reg(hw, MII_GIGA_CR, mii_giga_ctrl_data) != 0) + atl1c_write_phy_reg(hw, MII_CTRL1000, mii_giga_ctrl_data) != 0) return -1; return 0; } @@ -517,19 +517,18 @@ int atl1c_phy_init(struct atl1c_hw *hw) "Error Setting up Auto-Negotiation\n"); return ret_val; } - mii_bmcr_data |= BMCR_AUTO_NEG_EN | BMCR_RESTART_AUTO_NEG; + mii_bmcr_data |= BMCR_ANENABLE | BMCR_ANRESTART; break; case MEDIA_TYPE_100M_FULL: - mii_bmcr_data |= BMCR_SPEED_100 | BMCR_FULL_DUPLEX; + mii_bmcr_data |= BMCR_SPEED100 | BMCR_FULLDPLX; break; case MEDIA_TYPE_100M_HALF: - mii_bmcr_data |= BMCR_SPEED_100; + mii_bmcr_data |= BMCR_SPEED100; break; case MEDIA_TYPE_10M_FULL: - mii_bmcr_data |= BMCR_SPEED_10 | BMCR_FULL_DUPLEX; + mii_bmcr_data |= BMCR_FULLDPLX; break; case MEDIA_TYPE_10M_HALF: - mii_bmcr_data |= BMCR_SPEED_10; break; default: if (netif_msg_link(adapter)) @@ -657,7 +656,7 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw) err = atl1c_phy_setup_adv(hw); if (err) return err; - mii_bmcr_data |= BMCR_AUTO_NEG_EN | BMCR_RESTART_AUTO_NEG; + mii_bmcr_data |= BMCR_ANENABLE | BMCR_ANRESTART; return atl1c_write_phy_reg(hw, MII_BMCR, mii_bmcr_data); } diff --git a/drivers/net/atl1c/atl1c_hw.h b/drivers/net/atl1c/atl1c_hw.h index 3dd675979aa1..655fc6c4a8a4 100644 --- a/drivers/net/atl1c/atl1c_hw.h +++ b/drivers/net/atl1c/atl1c_hw.h @@ -736,55 +736,16 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); #define REG_DEBUG_DATA0 0x1900 #define REG_DEBUG_DATA1 0x1904 -/* PHY Control Register */ -#define MII_BMCR 0x00 -#define BMCR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ -#define BMCR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ -#define BMCR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ -#define BMCR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ -#define BMCR_ISOLATE 0x0400 /* Isolate PHY from MII */ -#define BMCR_POWER_DOWN 0x0800 /* Power down */ -#define BMCR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ -#define BMCR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */ -#define BMCR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ -#define BMCR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ -#define BMCR_SPEED_MASK 0x2040 -#define BMCR_SPEED_1000 0x0040 -#define BMCR_SPEED_100 0x2000 -#define BMCR_SPEED_10 0x0000 - -/* PHY Status Register */ -#define MII_BMSR 0x01 -#define BMMSR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ -#define BMSR_JABBER_DETECT 0x0002 /* Jabber Detected */ -#define BMSR_LINK_STATUS 0x0004 /* Link Status 1 = link */ -#define BMSR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ -#define BMSR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ -#define BMSR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ -#define BMSR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ -#define BMSR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ -#define BMSR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ -#define BMSR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ -#define BMSR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ -#define BMSR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ -#define BMSR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ -#define BMMII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ -#define BMMII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ - -#define MII_PHYSID1 0x02 -#define MII_PHYSID2 0x03 #define L1D_MPW_PHYID1 0xD01C /* V7 */ #define L1D_MPW_PHYID2 0xD01D /* V1-V6 */ #define L1D_MPW_PHYID3 0xD01E /* V8 */ /* Autoneg Advertisement Register */ -#define MII_ADVERTISE 0x04 -#define ADVERTISE_SPEED_MASK 0x01E0 -#define ADVERTISE_DEFAULT_CAP 0x0DE0 +#define ADVERTISE_DEFAULT_CAP \ + (ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM) /* 1000BASE-T Control Register */ -#define MII_GIGA_CR 0x09 #define GIGA_CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port 0=DTE device */ #define GIGA_CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master 0=Configure PHY as Slave */ diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index 3824382faecc..e60595f0247c 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -2718,7 +2718,6 @@ static int __devinit atl1c_probe(struct pci_dev *pdev, goto err_reset; } - device_init_wakeup(&pdev->dev, 1); /* reset the controller to * put the device in a known good starting state */ err = atl1c_phy_init(&adapter->hw); diff --git a/drivers/net/atl1e/atl1e_ethtool.c b/drivers/net/atl1e/atl1e_ethtool.c index 6943a6c3b948..1209297433b8 100644 --- a/drivers/net/atl1e/atl1e_ethtool.c +++ b/drivers/net/atl1e/atl1e_ethtool.c @@ -95,18 +95,18 @@ static int atl1e_set_settings(struct net_device *netdev, ecmd->advertising = hw->autoneg_advertised | ADVERTISED_TP | ADVERTISED_Autoneg; - adv4 = hw->mii_autoneg_adv_reg & ~MII_AR_SPEED_MASK; + adv4 = hw->mii_autoneg_adv_reg & ~ADVERTISE_ALL; adv9 = hw->mii_1000t_ctrl_reg & ~MII_AT001_CR_1000T_SPEED_MASK; if (hw->autoneg_advertised & ADVERTISE_10_HALF) - adv4 |= MII_AR_10T_HD_CAPS; + adv4 |= ADVERTISE_10HALF; if (hw->autoneg_advertised & ADVERTISE_10_FULL) - adv4 |= MII_AR_10T_FD_CAPS; + adv4 |= ADVERTISE_10FULL; if (hw->autoneg_advertised & ADVERTISE_100_HALF) - adv4 |= MII_AR_100TX_HD_CAPS; + adv4 |= ADVERTISE_100HALF; if (hw->autoneg_advertised & ADVERTISE_100_FULL) - adv4 |= MII_AR_100TX_FD_CAPS; + adv4 |= ADVERTISE_100FULL; if (hw->autoneg_advertised & ADVERTISE_1000_FULL) - adv9 |= MII_AT001_CR_1000T_FD_CAPS; + adv9 |= ADVERTISE_1000FULL; if (adv4 != hw->mii_autoneg_adv_reg || adv9 != hw->mii_1000t_ctrl_reg) { diff --git a/drivers/net/atl1e/atl1e_hw.c b/drivers/net/atl1e/atl1e_hw.c index 76cc043def8c..923063d2e5bb 100644 --- a/drivers/net/atl1e/atl1e_hw.c +++ b/drivers/net/atl1e/atl1e_hw.c @@ -318,7 +318,7 @@ static int atl1e_phy_setup_autoneg_adv(struct atl1e_hw *hw) * Advertisement Register (Address 4) and the 1000 mb speed bits in * the 1000Base-T control Register (Address 9). */ - mii_autoneg_adv_reg &= ~MII_AR_SPEED_MASK; + mii_autoneg_adv_reg &= ~ADVERTISE_ALL; mii_1000t_ctrl_reg &= ~MII_AT001_CR_1000T_SPEED_MASK; /* @@ -327,44 +327,37 @@ static int atl1e_phy_setup_autoneg_adv(struct atl1e_hw *hw) */ switch (hw->media_type) { case MEDIA_TYPE_AUTO_SENSOR: - mii_autoneg_adv_reg |= (MII_AR_10T_HD_CAPS | - MII_AR_10T_FD_CAPS | - MII_AR_100TX_HD_CAPS | - MII_AR_100TX_FD_CAPS); - hw->autoneg_advertised = ADVERTISE_10_HALF | - ADVERTISE_10_FULL | - ADVERTISE_100_HALF | - ADVERTISE_100_FULL; + mii_autoneg_adv_reg |= ADVERTISE_ALL; + hw->autoneg_advertised = ADVERTISE_ALL; if (hw->nic_type == athr_l1e) { - mii_1000t_ctrl_reg |= - MII_AT001_CR_1000T_FD_CAPS; + mii_1000t_ctrl_reg |= ADVERTISE_1000FULL; hw->autoneg_advertised |= ADVERTISE_1000_FULL; } break; case MEDIA_TYPE_100M_FULL: - mii_autoneg_adv_reg |= MII_AR_100TX_FD_CAPS; + mii_autoneg_adv_reg |= ADVERTISE_100FULL; hw->autoneg_advertised = ADVERTISE_100_FULL; break; case MEDIA_TYPE_100M_HALF: - mii_autoneg_adv_reg |= MII_AR_100TX_HD_CAPS; + mii_autoneg_adv_reg |= ADVERTISE_100_HALF; hw->autoneg_advertised = ADVERTISE_100_HALF; break; case MEDIA_TYPE_10M_FULL: - mii_autoneg_adv_reg |= MII_AR_10T_FD_CAPS; + mii_autoneg_adv_reg |= ADVERTISE_10_FULL; hw->autoneg_advertised = ADVERTISE_10_FULL; break; default: - mii_autoneg_adv_reg |= MII_AR_10T_HD_CAPS; + mii_autoneg_adv_reg |= ADVERTISE_10_HALF; hw->autoneg_advertised = ADVERTISE_10_HALF; break; } /* flow control fixed to enable all */ - mii_autoneg_adv_reg |= (MII_AR_ASM_DIR | MII_AR_PAUSE); + mii_autoneg_adv_reg |= (ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP); hw->mii_autoneg_adv_reg = mii_autoneg_adv_reg; hw->mii_1000t_ctrl_reg = mii_1000t_ctrl_reg; @@ -374,7 +367,7 @@ static int atl1e_phy_setup_autoneg_adv(struct atl1e_hw *hw) return ret_val; if (hw->nic_type == athr_l1e || hw->nic_type == athr_l2e_revA) { - ret_val = atl1e_write_phy_reg(hw, MII_AT001_CR, + ret_val = atl1e_write_phy_reg(hw, MII_CTRL1000, mii_1000t_ctrl_reg); if (ret_val) return ret_val; @@ -397,7 +390,7 @@ int atl1e_phy_commit(struct atl1e_hw *hw) int ret_val; u16 phy_data; - phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG; + phy_data = BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART; ret_val = atl1e_write_phy_reg(hw, MII_BMCR, phy_data); if (ret_val) { @@ -645,15 +638,14 @@ int atl1e_restart_autoneg(struct atl1e_hw *hw) return err; if (hw->nic_type == athr_l1e || hw->nic_type == athr_l2e_revA) { - err = atl1e_write_phy_reg(hw, MII_AT001_CR, + err = atl1e_write_phy_reg(hw, MII_CTRL1000, hw->mii_1000t_ctrl_reg); if (err) return err; } err = atl1e_write_phy_reg(hw, MII_BMCR, - MII_CR_RESET | MII_CR_AUTO_NEG_EN | - MII_CR_RESTART_AUTO_NEG); + BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART); return err; } diff --git a/drivers/net/atl1e/atl1e_hw.h b/drivers/net/atl1e/atl1e_hw.h index 5ea2f4d86cfa..74df16aef793 100644 --- a/drivers/net/atl1e/atl1e_hw.h +++ b/drivers/net/atl1e/atl1e_hw.h @@ -629,127 +629,24 @@ s32 atl1e_restart_autoneg(struct atl1e_hw *hw); /***************************** MII definition ***************************************/ /* PHY Common Register */ -#define MII_BMCR 0x00 -#define MII_BMSR 0x01 -#define MII_PHYSID1 0x02 -#define MII_PHYSID2 0x03 -#define MII_ADVERTISE 0x04 -#define MII_LPA 0x05 -#define MII_EXPANSION 0x06 -#define MII_AT001_CR 0x09 -#define MII_AT001_SR 0x0A -#define MII_AT001_ESR 0x0F #define MII_AT001_PSCR 0x10 #define MII_AT001_PSSR 0x11 #define MII_INT_CTRL 0x12 #define MII_INT_STATUS 0x13 #define MII_SMARTSPEED 0x14 -#define MII_RERRCOUNTER 0x15 -#define MII_SREVISION 0x16 -#define MII_RESV1 0x17 #define MII_LBRERROR 0x18 -#define MII_PHYADDR 0x19 #define MII_RESV2 0x1a -#define MII_TPISTATUS 0x1b -#define MII_NCONFIG 0x1c #define MII_DBG_ADDR 0x1D #define MII_DBG_DATA 0x1E - -/* PHY Control Register */ -#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ -#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ -#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ -#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ -#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */ -#define MII_CR_POWER_DOWN 0x0800 /* Power down */ -#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ -#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */ -#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ -#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ -#define MII_CR_SPEED_MASK 0x2040 -#define MII_CR_SPEED_1000 0x0040 -#define MII_CR_SPEED_100 0x2000 -#define MII_CR_SPEED_10 0x0000 - - -/* PHY Status Register */ -#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ -#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */ -#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ -#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ -#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ -#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ -#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ -#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ -#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ -#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ -#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ -#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ -#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ -#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ -#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ - -/* Link partner ability register. */ -#define MII_LPA_SLCT 0x001f /* Same as advertise selector */ -#define MII_LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */ -#define MII_LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */ -#define MII_LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */ -#define MII_LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */ -#define MII_LPA_100BASE4 0x0200 /* 100BASE-T4 */ -#define MII_LPA_PAUSE 0x0400 /* PAUSE */ -#define MII_LPA_ASYPAUSE 0x0800 /* Asymmetrical PAUSE */ -#define MII_LPA_RFAULT 0x2000 /* Link partner faulted */ -#define MII_LPA_LPACK 0x4000 /* Link partner acked us */ -#define MII_LPA_NPAGE 0x8000 /* Next page bit */ - /* Autoneg Advertisement Register */ -#define MII_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */ -#define MII_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ -#define MII_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ -#define MII_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ -#define MII_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ -#define MII_AR_100T4_CAPS 0x0200 /* 100T4 Capable */ -#define MII_AR_PAUSE 0x0400 /* Pause operation desired */ -#define MII_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ -#define MII_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */ -#define MII_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */ -#define MII_AR_SPEED_MASK 0x01E0 -#define MII_AR_DEFAULT_CAP_MASK 0x0DE0 +#define MII_AR_DEFAULT_CAP_MASK 0 /* 1000BASE-T Control Register */ -#define MII_AT001_CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ -#define MII_AT001_CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ -#define MII_AT001_CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */ -/* 0=DTE device */ -#define MII_AT001_CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */ -/* 0=Configure PHY as Slave */ -#define MII_AT001_CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */ -/* 0=Automatic Master/Slave config */ -#define MII_AT001_CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */ -#define MII_AT001_CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */ -#define MII_AT001_CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */ -#define MII_AT001_CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */ -#define MII_AT001_CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */ -#define MII_AT001_CR_1000T_SPEED_MASK 0x0300 -#define MII_AT001_CR_1000T_DEFAULT_CAP_MASK 0x0300 - -/* 1000BASE-T Status Register */ -#define MII_AT001_SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */ -#define MII_AT001_SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */ -#define MII_AT001_SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ -#define MII_AT001_SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ -#define MII_AT001_SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */ -#define MII_AT001_SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */ -#define MII_AT001_SR_1000T_REMOTE_RX_STATUS_SHIFT 12 -#define MII_AT001_SR_1000T_LOCAL_RX_STATUS_SHIFT 13 - -/* Extended Status Register */ -#define MII_AT001_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */ -#define MII_AT001_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */ -#define MII_AT001_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */ -#define MII_AT001_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */ +#define MII_AT001_CR_1000T_SPEED_MASK \ + (ADVERTISE_1000FULL | ADVERTISE_1000HALF) +#define MII_AT001_CR_1000T_DEFAULT_CAP_MASK MII_AT001_CR_1000T_SPEED_MASK /* AT001 PHY Specific Control Register */ #define MII_AT001_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */ diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index e28f8baf394e..bf7500ccd73f 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -2051,9 +2051,9 @@ static int atl1e_suspend(struct pci_dev *pdev, pm_message_t state) atl1e_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data); atl1e_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data); - mii_advertise_data = MII_AR_10T_HD_CAPS; + mii_advertise_data = ADVERTISE_10HALF; - if ((atl1e_write_phy_reg(hw, MII_AT001_CR, 0) != 0) || + if ((atl1e_write_phy_reg(hw, MII_CTRL1000, 0) != 0) || (atl1e_write_phy_reg(hw, MII_ADVERTISE, mii_advertise_data) != 0) || (atl1e_phy_commit(hw)) != 0) { diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 3b527687c28f..67f40b9c16ed 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -950,6 +950,7 @@ static int __devinit atl1_sw_init(struct atl1_adapter *adapter) hw->min_frame_size = ETH_ZLEN + ETH_FCS_LEN; adapter->wol = 0; + device_set_wakeup_enable(&adapter->pdev->dev, false); adapter->rx_buffer_len = (hw->max_frame_size + 7) & ~7; adapter->ict = 50000; /* 100ms */ adapter->link_speed = SPEED_0; /* hardware init */ @@ -2735,15 +2736,15 @@ static int atl1_close(struct net_device *netdev) } #ifdef CONFIG_PM -static int atl1_suspend(struct pci_dev *pdev, pm_message_t state) +static int atl1_suspend(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); struct atl1_adapter *adapter = netdev_priv(netdev); struct atl1_hw *hw = &adapter->hw; u32 ctrl = 0; u32 wufc = adapter->wol; u32 val; - int retval; u16 speed; u16 duplex; @@ -2751,17 +2752,15 @@ static int atl1_suspend(struct pci_dev *pdev, pm_message_t state) if (netif_running(netdev)) atl1_down(adapter); - retval = pci_save_state(pdev); - if (retval) - return retval; - atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl); atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl); val = ctrl & BMSR_LSTATUS; if (val) wufc &= ~ATLX_WUFC_LNKC; + if (!wufc) + goto disable_wol; - if (val && wufc) { + if (val) { val = atl1_get_speed_and_duplex(hw, &speed, &duplex); if (val) { if (netif_msg_ifdown(adapter)) @@ -2798,23 +2797,18 @@ static int atl1_suspend(struct pci_dev *pdev, pm_message_t state) ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; iowrite32(ctrl, hw->hw_addr + REG_PCIE_PHYMISC); ioread32(hw->hw_addr + REG_PCIE_PHYMISC); - - pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); - goto exit; - } - - if (!val && wufc) { + } else { ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN); iowrite32(ctrl, hw->hw_addr + REG_WOL_CTRL); ioread32(hw->hw_addr + REG_WOL_CTRL); iowrite32(0, hw->hw_addr + REG_MAC_CTRL); ioread32(hw->hw_addr + REG_MAC_CTRL); hw->phy_configured = false; - pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); - goto exit; } -disable_wol: + return 0; + + disable_wol: iowrite32(0, hw->hw_addr + REG_WOL_CTRL); ioread32(hw->hw_addr + REG_WOL_CTRL); ctrl = ioread32(hw->hw_addr + REG_PCIE_PHYMISC); @@ -2822,37 +2816,17 @@ disable_wol: iowrite32(ctrl, hw->hw_addr + REG_PCIE_PHYMISC); ioread32(hw->hw_addr + REG_PCIE_PHYMISC); hw->phy_configured = false; - pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); -exit: - if (netif_running(netdev)) - pci_disable_msi(adapter->pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; } -static int atl1_resume(struct pci_dev *pdev) +static int atl1_resume(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); struct atl1_adapter *adapter = netdev_priv(netdev); - u32 err; - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - err = pci_enable_device(pdev); - if (err) { - if (netif_msg_ifup(adapter)) - dev_printk(KERN_DEBUG, &pdev->dev, - "error enabling pci device\n"); - return err; - } - - pci_set_master(pdev); iowrite32(0, adapter->hw.hw_addr + REG_WOL_CTRL); - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); atl1_reset_hw(&adapter->hw); @@ -2864,16 +2838,25 @@ static int atl1_resume(struct pci_dev *pdev) return 0; } + +static SIMPLE_DEV_PM_OPS(atl1_pm_ops, atl1_suspend, atl1_resume); +#define ATL1_PM_OPS (&atl1_pm_ops) + #else -#define atl1_suspend NULL -#define atl1_resume NULL + +static int atl1_suspend(struct device *dev) { return 0; } + +#define ATL1_PM_OPS NULL #endif static void atl1_shutdown(struct pci_dev *pdev) { -#ifdef CONFIG_PM - atl1_suspend(pdev, PMSG_SUSPEND); -#endif + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl1_adapter *adapter = netdev_priv(netdev); + + atl1_suspend(&pdev->dev); + pci_wake_from_d3(pdev, adapter->wol); + pci_set_power_state(pdev, PCI_D3hot); } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -3117,9 +3100,8 @@ static struct pci_driver atl1_driver = { .id_table = atl1_pci_tbl, .probe = atl1_probe, .remove = __devexit_p(atl1_remove), - .suspend = atl1_suspend, - .resume = atl1_resume, - .shutdown = atl1_shutdown + .shutdown = atl1_shutdown, + .driver.pm = ATL1_PM_OPS, }; /* @@ -3409,6 +3391,9 @@ static int atl1_set_wol(struct net_device *netdev, adapter->wol = 0; if (wol->wolopts & WAKE_MAGIC) adapter->wol |= ATLX_WUFC_MAG; + + device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol); + return 0; } diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index add0b93350dd..3a800e2bc94b 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -450,9 +450,8 @@ static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac) mac[5] = (u8)(addr & 0xFF); mac[4] = (u8)((addr >> 8) & 0xFF); mac[3] = (u8)((addr >> 16) & 0xFF); - mac[2] = 0xC9; - mac[1] = 0x00; - mac[0] = 0x00; + /* Use the OUI from the current MAC address */ + memcpy(mac, adapter->netdev->dev_addr, 3); } extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index a179cc6d79f2..619ebc24602e 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -23,6 +23,12 @@ static void be_mcc_notify(struct be_adapter *adapter) struct be_queue_info *mccq = &adapter->mcc_obj.q; u32 val = 0; + if (adapter->eeh_err) { + dev_info(&adapter->pdev->dev, + "Error in Card Detected! Cannot issue commands\n"); + return; + } + val |= mccq->id & DB_MCCQ_RING_ID_MASK; val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT; @@ -102,6 +108,7 @@ static void be_async_grp5_cos_priority_process(struct be_adapter *adapter, { if (evt->valid) { adapter->vlan_prio_bmap = evt->available_priority_bmap; + adapter->recommended_prio &= ~VLAN_PRIO_MASK; adapter->recommended_prio = evt->reco_default_priority << VLAN_PRIO_SHIFT; } @@ -216,6 +223,9 @@ static int be_mcc_wait_compl(struct be_adapter *adapter) int i, num, status = 0; struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; + if (adapter->eeh_err) + return -EIO; + for (i = 0; i < mcc_timeout; i++) { num = be_process_mcc(adapter, &status); if (num) @@ -245,6 +255,12 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) int msecs = 0; u32 ready; + if (adapter->eeh_err) { + dev_err(&adapter->pdev->dev, + "Error detected in card.Cannot issue commands\n"); + return -EIO; + } + do { ready = ioread32(db); if (ready == 0xffffffff) { @@ -598,7 +614,7 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, /* Uses synchronous MCCQ */ int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, - u32 if_id, u32 *pmac_id) + u32 if_id, u32 *pmac_id, u32 domain) { struct be_mcc_wrb *wrb; struct be_cmd_req_pmac_add *req; @@ -619,6 +635,7 @@ int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_NTWK_PMAC_ADD, sizeof(*req)); + req->hdr.domain = domain; req->if_id = cpu_to_le32(if_id); memcpy(req->mac_address, mac_addr, ETH_ALEN); @@ -634,7 +651,7 @@ err: } /* Uses synchronous MCCQ */ -int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id) +int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id, u32 dom) { struct be_mcc_wrb *wrb; struct be_cmd_req_pmac_del *req; @@ -655,6 +672,7 @@ int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id) be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_NTWK_PMAC_DEL, sizeof(*req)); + req->hdr.domain = dom; req->if_id = cpu_to_le32(if_id); req->pmac_id = cpu_to_le32(pmac_id); @@ -995,7 +1013,7 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags, } /* Uses mbox */ -int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id) +int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id, u32 domain) { struct be_mcc_wrb *wrb; struct be_cmd_req_if_destroy *req; @@ -1016,6 +1034,7 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id) be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_NTWK_INTERFACE_DESTROY, sizeof(*req)); + req->hdr.domain = domain; req->interface_id = cpu_to_le32(interface_id); status = be_mbox_notify_wait(adapter); @@ -1868,8 +1887,8 @@ int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain) OPCODE_COMMON_SET_QOS, sizeof(*req)); req->hdr.domain = domain; - req->valid_bits = BE_QOS_BITS_NIC; - req->max_bps_nic = bps; + req->valid_bits = cpu_to_le32(BE_QOS_BITS_NIC); + req->max_bps_nic = cpu_to_le32(bps); status = be_mcc_notify_wait(adapter); diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 83d15c8a9fa3..91c5d2b09aa1 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -999,12 +999,14 @@ extern int be_cmd_POST(struct be_adapter *adapter); extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, u8 type, bool permanent, u32 if_handle); extern int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, - u32 if_id, u32 *pmac_id); -extern int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id); + u32 if_id, u32 *pmac_id, u32 domain); +extern int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, + u32 pmac_id, u32 domain); extern int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags, u8 *mac, bool pmac_invalid, u32 *if_handle, u32 *pmac_id, u32 domain); -extern int be_cmd_if_destroy(struct be_adapter *adapter, u32 if_handle); +extern int be_cmd_if_destroy(struct be_adapter *adapter, u32 if_handle, + u32 domain); extern int be_cmd_eq_create(struct be_adapter *adapter, struct be_queue_info *eq, int eq_delay); extern int be_cmd_cq_create(struct be_adapter *adapter, diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index b4be0271efe0..07b4ab902b17 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -376,8 +376,9 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) } phy_cmd.size = sizeof(struct be_cmd_req_get_phy_info); - phy_cmd.va = pci_alloc_consistent(adapter->pdev, phy_cmd.size, - &phy_cmd.dma); + phy_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, + phy_cmd.size, &phy_cmd.dma, + GFP_KERNEL); if (!phy_cmd.va) { dev_err(&adapter->pdev->dev, "Memory alloc failure\n"); return -ENOMEM; @@ -416,8 +417,8 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) adapter->port_type = ecmd->port; adapter->transceiver = ecmd->transceiver; adapter->autoneg = ecmd->autoneg; - pci_free_consistent(adapter->pdev, phy_cmd.size, - phy_cmd.va, phy_cmd.dma); + dma_free_coherent(&adapter->pdev->dev, phy_cmd.size, phy_cmd.va, + phy_cmd.dma); } else { ecmd->speed = adapter->link_speed; ecmd->port = adapter->port_type; @@ -515,12 +516,23 @@ be_phys_id(struct net_device *netdev, u32 data) return status; } +static bool +be_is_wol_supported(struct be_adapter *adapter) +{ + if (!be_physfn(adapter)) + return false; + else + return true; +} + static void be_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { struct be_adapter *adapter = netdev_priv(netdev); - wol->supported = WAKE_MAGIC; + if (be_is_wol_supported(adapter)) + wol->supported = WAKE_MAGIC; + if (adapter->wol) wol->wolopts = WAKE_MAGIC; else @@ -536,7 +548,7 @@ be_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) if (wol->wolopts & ~WAKE_MAGIC) return -EINVAL; - if (wol->wolopts & WAKE_MAGIC) + if ((wol->wolopts & WAKE_MAGIC) && be_is_wol_supported(adapter)) adapter->wol = true; else adapter->wol = false; @@ -554,8 +566,8 @@ be_test_ddr_dma(struct be_adapter *adapter) }; ddrdma_cmd.size = sizeof(struct be_cmd_req_ddrdma_test); - ddrdma_cmd.va = pci_alloc_consistent(adapter->pdev, ddrdma_cmd.size, - &ddrdma_cmd.dma); + ddrdma_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, ddrdma_cmd.size, + &ddrdma_cmd.dma, GFP_KERNEL); if (!ddrdma_cmd.va) { dev_err(&adapter->pdev->dev, "Memory allocation failure\n"); return -ENOMEM; @@ -569,8 +581,8 @@ be_test_ddr_dma(struct be_adapter *adapter) } err: - pci_free_consistent(adapter->pdev, ddrdma_cmd.size, - ddrdma_cmd.va, ddrdma_cmd.dma); + dma_free_coherent(&adapter->pdev->dev, ddrdma_cmd.size, ddrdma_cmd.va, + ddrdma_cmd.dma); return ret; } @@ -662,8 +674,8 @@ be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, memset(&eeprom_cmd, 0, sizeof(struct be_dma_mem)); eeprom_cmd.size = sizeof(struct be_cmd_req_seeprom_read); - eeprom_cmd.va = pci_alloc_consistent(adapter->pdev, eeprom_cmd.size, - &eeprom_cmd.dma); + eeprom_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, eeprom_cmd.size, + &eeprom_cmd.dma, GFP_KERNEL); if (!eeprom_cmd.va) { dev_err(&adapter->pdev->dev, @@ -677,8 +689,8 @@ be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, resp = (struct be_cmd_resp_seeprom_read *) eeprom_cmd.va; memcpy(data, resp->seeprom_data + eeprom->offset, eeprom->len); } - pci_free_consistent(adapter->pdev, eeprom_cmd.size, eeprom_cmd.va, - eeprom_cmd.dma); + dma_free_coherent(&adapter->pdev->dev, eeprom_cmd.size, eeprom_cmd.va, + eeprom_cmd.dma); return status; } diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 28a32a6c8bf1..aad7ea37d589 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -125,8 +125,8 @@ static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q) { struct be_dma_mem *mem = &q->dma_mem; if (mem->va) - pci_free_consistent(adapter->pdev, mem->size, - mem->va, mem->dma); + dma_free_coherent(&adapter->pdev->dev, mem->size, mem->va, + mem->dma); } static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q, @@ -138,7 +138,8 @@ static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q, q->len = len; q->entry_size = entry_size; mem->size = len * entry_size; - mem->va = pci_alloc_consistent(adapter->pdev, mem->size, &mem->dma); + mem->va = dma_alloc_coherent(&adapter->pdev->dev, mem->size, &mem->dma, + GFP_KERNEL); if (!mem->va) return -1; memset(mem->va, 0, mem->size); @@ -235,12 +236,13 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) if (!be_physfn(adapter)) goto netdev_addr; - status = be_cmd_pmac_del(adapter, adapter->if_handle, adapter->pmac_id); + status = be_cmd_pmac_del(adapter, adapter->if_handle, + adapter->pmac_id, 0); if (status) return status; status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data, - adapter->if_handle, &adapter->pmac_id); + adapter->if_handle, &adapter->pmac_id, 0); netdev_addr: if (!status) memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); @@ -484,7 +486,7 @@ static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, AMAP_SET_BITS(struct amap_eth_hdr_wrb, len, hdr, len); } -static void unmap_tx_frag(struct pci_dev *pdev, struct be_eth_wrb *wrb, +static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb, bool unmap_single) { dma_addr_t dma; @@ -494,11 +496,10 @@ static void unmap_tx_frag(struct pci_dev *pdev, struct be_eth_wrb *wrb, dma = (u64)wrb->frag_pa_hi << 32 | (u64)wrb->frag_pa_lo; if (wrb->frag_len) { if (unmap_single) - pci_unmap_single(pdev, dma, wrb->frag_len, - PCI_DMA_TODEVICE); + dma_unmap_single(dev, dma, wrb->frag_len, + DMA_TO_DEVICE); else - pci_unmap_page(pdev, dma, wrb->frag_len, - PCI_DMA_TODEVICE); + dma_unmap_page(dev, dma, wrb->frag_len, DMA_TO_DEVICE); } } @@ -507,7 +508,7 @@ static int make_tx_wrbs(struct be_adapter *adapter, { dma_addr_t busaddr; int i, copied = 0; - struct pci_dev *pdev = adapter->pdev; + struct device *dev = &adapter->pdev->dev; struct sk_buff *first_skb = skb; struct be_queue_info *txq = &adapter->tx_obj.q; struct be_eth_wrb *wrb; @@ -521,9 +522,8 @@ static int make_tx_wrbs(struct be_adapter *adapter, if (skb->len > skb->data_len) { int len = skb_headlen(skb); - busaddr = pci_map_single(pdev, skb->data, len, - PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(pdev, busaddr)) + busaddr = dma_map_single(dev, skb->data, len, DMA_TO_DEVICE); + if (dma_mapping_error(dev, busaddr)) goto dma_err; map_single = true; wrb = queue_head_node(txq); @@ -536,10 +536,9 @@ static int make_tx_wrbs(struct be_adapter *adapter, for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; - busaddr = pci_map_page(pdev, frag->page, - frag->page_offset, - frag->size, PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(pdev, busaddr)) + busaddr = dma_map_page(dev, frag->page, frag->page_offset, + frag->size, DMA_TO_DEVICE); + if (dma_mapping_error(dev, busaddr)) goto dma_err; wrb = queue_head_node(txq); wrb_fill(wrb, busaddr, frag->size); @@ -563,7 +562,7 @@ dma_err: txq->head = map_head; while (copied) { wrb = queue_head_node(txq); - unmap_tx_frag(pdev, wrb, map_single); + unmap_tx_frag(dev, wrb, map_single); map_single = false; copied -= wrb->frag_len; queue_head_inc(txq); @@ -743,11 +742,11 @@ static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID) status = be_cmd_pmac_del(adapter, adapter->vf_cfg[vf].vf_if_handle, - adapter->vf_cfg[vf].vf_pmac_id); + adapter->vf_cfg[vf].vf_pmac_id, vf + 1); status = be_cmd_pmac_add(adapter, mac, adapter->vf_cfg[vf].vf_if_handle, - &adapter->vf_cfg[vf].vf_pmac_id); + &adapter->vf_cfg[vf].vf_pmac_id, vf + 1); if (status) dev_err(&adapter->pdev->dev, "MAC %pM set on VF %d Failed\n", @@ -822,7 +821,7 @@ static int be_set_vf_tx_rate(struct net_device *netdev, rate = 10000; adapter->vf_cfg[vf].vf_tx_rate = rate; - status = be_cmd_set_qos(adapter, rate / 10, vf); + status = be_cmd_set_qos(adapter, rate / 10, vf + 1); if (status) dev_info(&adapter->pdev->dev, @@ -888,8 +887,9 @@ get_rx_page_info(struct be_adapter *adapter, BUG_ON(!rx_page_info->page); if (rx_page_info->last_page_user) { - pci_unmap_page(adapter->pdev, dma_unmap_addr(rx_page_info, bus), - adapter->big_page_size, PCI_DMA_FROMDEVICE); + dma_unmap_page(&adapter->pdev->dev, + dma_unmap_addr(rx_page_info, bus), + adapter->big_page_size, DMA_FROM_DEVICE); rx_page_info->last_page_user = false; } @@ -1195,9 +1195,9 @@ static void be_post_rx_frags(struct be_rx_obj *rxo) rxo->stats.rx_post_fail++; break; } - page_dmaaddr = pci_map_page(adapter->pdev, pagep, 0, - adapter->big_page_size, - PCI_DMA_FROMDEVICE); + page_dmaaddr = dma_map_page(&adapter->pdev->dev, pagep, + 0, adapter->big_page_size, + DMA_FROM_DEVICE); page_info->page_offset = 0; } else { get_page(pagep); @@ -1270,8 +1270,8 @@ static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index) do { cur_index = txq->tail; wrb = queue_tail_node(txq); - unmap_tx_frag(adapter->pdev, wrb, (unmap_skb_hdr && - skb_headlen(sent_skb))); + unmap_tx_frag(&adapter->pdev->dev, wrb, + (unmap_skb_hdr && skb_headlen(sent_skb))); unmap_skb_hdr = false; num_wrbs++; @@ -1827,6 +1827,7 @@ void be_detect_dump_ue(struct be_adapter *adapter) if (ue_status_lo || ue_status_hi) { adapter->ue_detected = true; + adapter->eeh_err = true; dev_err(&adapter->pdev->dev, "UE Detected!!\n"); } @@ -1865,6 +1866,10 @@ static void be_worker(struct work_struct *work) struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; be_cq_notify(adapter, mcc_obj->cq.id, false, mcc_compl); } + + if (!adapter->ue_detected && !lancer_chip(adapter)) + be_detect_dump_ue(adapter); + goto reschedule; } @@ -2179,7 +2184,8 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable) memset(mac, 0, ETH_ALEN); cmd.size = sizeof(struct be_cmd_req_acpi_wol_magic_config); - cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size, &cmd.dma); + cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, + GFP_KERNEL); if (cmd.va == NULL) return -1; memset(cmd.va, 0, cmd.size); @@ -2190,8 +2196,8 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable) if (status) { dev_err(&adapter->pdev->dev, "Could not enable Wake-on-lan\n"); - pci_free_consistent(adapter->pdev, cmd.size, cmd.va, - cmd.dma); + dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, + cmd.dma); return status; } status = be_cmd_enable_magic_wol(adapter, @@ -2204,7 +2210,7 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable) pci_enable_wake(adapter->pdev, PCI_D3cold, 0); } - pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma); + dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, cmd.dma); return status; } @@ -2225,7 +2231,8 @@ static inline int be_vf_eth_addr_config(struct be_adapter *adapter) for (vf = 0; vf < num_vfs; vf++) { status = be_cmd_pmac_add(adapter, mac, adapter->vf_cfg[vf].vf_if_handle, - &adapter->vf_cfg[vf].vf_pmac_id); + &adapter->vf_cfg[vf].vf_pmac_id, + vf + 1); if (status) dev_err(&adapter->pdev->dev, "Mac address add failed for VF %d\n", vf); @@ -2245,7 +2252,7 @@ static inline void be_vf_eth_addr_rem(struct be_adapter *adapter) if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID) be_cmd_pmac_del(adapter, adapter->vf_cfg[vf].vf_if_handle, - adapter->vf_cfg[vf].vf_pmac_id); + adapter->vf_cfg[vf].vf_pmac_id, vf + 1); } } @@ -2277,22 +2284,26 @@ static int be_setup(struct be_adapter *adapter) goto do_none; if (be_physfn(adapter)) { - while (vf < num_vfs) { - cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED - | BE_IF_FLAGS_BROADCAST; - status = be_cmd_if_create(adapter, cap_flags, en_flags, - mac, true, + if (adapter->sriov_enabled) { + while (vf < num_vfs) { + cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | + BE_IF_FLAGS_BROADCAST; + status = be_cmd_if_create(adapter, cap_flags, + en_flags, mac, true, &adapter->vf_cfg[vf].vf_if_handle, NULL, vf+1); - if (status) { - dev_err(&adapter->pdev->dev, - "Interface Create failed for VF %d\n", vf); - goto if_destroy; + if (status) { + dev_err(&adapter->pdev->dev, + "Interface Create failed for VF %d\n", + vf); + goto if_destroy; + } + adapter->vf_cfg[vf].vf_pmac_id = + BE_INVALID_PMAC_ID; + vf++; } - adapter->vf_cfg[vf].vf_pmac_id = BE_INVALID_PMAC_ID; - vf++; } - } else if (!be_physfn(adapter)) { + } else { status = be_cmd_mac_addr_query(adapter, mac, MAC_ADDRESS_TYPE_NETWORK, false, adapter->if_handle); if (!status) { @@ -2313,44 +2324,46 @@ static int be_setup(struct be_adapter *adapter) if (status != 0) goto rx_qs_destroy; - if (be_physfn(adapter)) { - status = be_vf_eth_addr_config(adapter); - if (status) - goto mcc_q_destroy; - } - adapter->link_speed = -1; return 0; -mcc_q_destroy: - if (be_physfn(adapter)) - be_vf_eth_addr_rem(adapter); be_mcc_queues_destroy(adapter); rx_qs_destroy: be_rx_queues_destroy(adapter); tx_qs_destroy: be_tx_queues_destroy(adapter); if_destroy: - for (vf = 0; vf < num_vfs; vf++) - if (adapter->vf_cfg[vf].vf_if_handle) - be_cmd_if_destroy(adapter, - adapter->vf_cfg[vf].vf_if_handle); - be_cmd_if_destroy(adapter, adapter->if_handle); + if (be_physfn(adapter) && adapter->sriov_enabled) + for (vf = 0; vf < num_vfs; vf++) + if (adapter->vf_cfg[vf].vf_if_handle) + be_cmd_if_destroy(adapter, + adapter->vf_cfg[vf].vf_if_handle, + vf + 1); + be_cmd_if_destroy(adapter, adapter->if_handle, 0); do_none: return status; } static int be_clear(struct be_adapter *adapter) { - if (be_physfn(adapter)) + int vf; + + if (be_physfn(adapter) && adapter->sriov_enabled) be_vf_eth_addr_rem(adapter); be_mcc_queues_destroy(adapter); be_rx_queues_destroy(adapter); be_tx_queues_destroy(adapter); - be_cmd_if_destroy(adapter, adapter->if_handle); + if (be_physfn(adapter) && adapter->sriov_enabled) + for (vf = 0; vf < num_vfs; vf++) + if (adapter->vf_cfg[vf].vf_if_handle) + be_cmd_if_destroy(adapter, + adapter->vf_cfg[vf].vf_if_handle, + vf + 1); + + be_cmd_if_destroy(adapter, adapter->if_handle, 0); /* tell fw we're done with firing cmds */ be_cmd_fw_clean(adapter); @@ -2453,8 +2466,8 @@ static int be_flash_data(struct be_adapter *adapter, continue; if ((pflashcomp[i].optype == IMG_TYPE_REDBOOT) && (!be_flash_redboot(adapter, fw->data, - pflashcomp[i].offset, pflashcomp[i].size, - filehdr_size))) + pflashcomp[i].offset, pflashcomp[i].size, filehdr_size + + (num_of_images * sizeof(struct image_hdr))))) continue; p = fw->data; p += filehdr_size + pflashcomp[i].offset @@ -2528,8 +2541,8 @@ int be_load_fw(struct be_adapter *adapter, u8 *func) dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file); flash_cmd.size = sizeof(struct be_cmd_write_flashrom) + 32*1024; - flash_cmd.va = pci_alloc_consistent(adapter->pdev, flash_cmd.size, - &flash_cmd.dma); + flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size, + &flash_cmd.dma, GFP_KERNEL); if (!flash_cmd.va) { status = -ENOMEM; dev_err(&adapter->pdev->dev, @@ -2558,8 +2571,8 @@ int be_load_fw(struct be_adapter *adapter, u8 *func) status = -1; } - pci_free_consistent(adapter->pdev, flash_cmd.size, flash_cmd.va, - flash_cmd.dma); + dma_free_coherent(&adapter->pdev->dev, flash_cmd.size, flash_cmd.va, + flash_cmd.dma); if (status) { dev_err(&adapter->pdev->dev, "Firmware load error\n"); goto fw_exit; @@ -2700,13 +2713,13 @@ static void be_ctrl_cleanup(struct be_adapter *adapter) be_unmap_pci_bars(adapter); if (mem->va) - pci_free_consistent(adapter->pdev, mem->size, - mem->va, mem->dma); + dma_free_coherent(&adapter->pdev->dev, mem->size, mem->va, + mem->dma); mem = &adapter->mc_cmd_mem; if (mem->va) - pci_free_consistent(adapter->pdev, mem->size, - mem->va, mem->dma); + dma_free_coherent(&adapter->pdev->dev, mem->size, mem->va, + mem->dma); } static int be_ctrl_init(struct be_adapter *adapter) @@ -2721,8 +2734,10 @@ static int be_ctrl_init(struct be_adapter *adapter) goto done; mbox_mem_alloc->size = sizeof(struct be_mcc_mailbox) + 16; - mbox_mem_alloc->va = pci_alloc_consistent(adapter->pdev, - mbox_mem_alloc->size, &mbox_mem_alloc->dma); + mbox_mem_alloc->va = dma_alloc_coherent(&adapter->pdev->dev, + mbox_mem_alloc->size, + &mbox_mem_alloc->dma, + GFP_KERNEL); if (!mbox_mem_alloc->va) { status = -ENOMEM; goto unmap_pci_bars; @@ -2734,8 +2749,9 @@ static int be_ctrl_init(struct be_adapter *adapter) memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox)); mc_cmd_mem->size = sizeof(struct be_cmd_req_mcast_mac_config); - mc_cmd_mem->va = pci_alloc_consistent(adapter->pdev, mc_cmd_mem->size, - &mc_cmd_mem->dma); + mc_cmd_mem->va = dma_alloc_coherent(&adapter->pdev->dev, + mc_cmd_mem->size, &mc_cmd_mem->dma, + GFP_KERNEL); if (mc_cmd_mem->va == NULL) { status = -ENOMEM; goto free_mbox; @@ -2751,8 +2767,8 @@ static int be_ctrl_init(struct be_adapter *adapter) return 0; free_mbox: - pci_free_consistent(adapter->pdev, mbox_mem_alloc->size, - mbox_mem_alloc->va, mbox_mem_alloc->dma); + dma_free_coherent(&adapter->pdev->dev, mbox_mem_alloc->size, + mbox_mem_alloc->va, mbox_mem_alloc->dma); unmap_pci_bars: be_unmap_pci_bars(adapter); @@ -2766,8 +2782,8 @@ static void be_stats_cleanup(struct be_adapter *adapter) struct be_dma_mem *cmd = &adapter->stats_cmd; if (cmd->va) - pci_free_consistent(adapter->pdev, cmd->size, - cmd->va, cmd->dma); + dma_free_coherent(&adapter->pdev->dev, cmd->size, + cmd->va, cmd->dma); } static int be_stats_init(struct be_adapter *adapter) @@ -2775,7 +2791,8 @@ static int be_stats_init(struct be_adapter *adapter) struct be_dma_mem *cmd = &adapter->stats_cmd; cmd->size = sizeof(struct be_cmd_req_get_stats); - cmd->va = pci_alloc_consistent(adapter->pdev, cmd->size, &cmd->dma); + cmd->va = dma_alloc_coherent(&adapter->pdev->dev, cmd->size, &cmd->dma, + GFP_KERNEL); if (cmd->va == NULL) return -1; memset(cmd->va, 0, cmd->size); @@ -2918,11 +2935,11 @@ static int __devinit be_probe(struct pci_dev *pdev, adapter->netdev = netdev; SET_NETDEV_DEV(netdev, &pdev->dev); - status = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + status = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); if (!status) { netdev->features |= NETIF_F_HIGHDMA; } else { - status = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + status = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (status) { dev_err(&pdev->dev, "Could not set PCI DMA Mask\n"); goto free_netdev; @@ -2947,11 +2964,9 @@ static int __devinit be_probe(struct pci_dev *pdev, if (status) goto ctrl_clean; - if (be_physfn(adapter)) { - status = be_cmd_reset_function(adapter); - if (status) - goto ctrl_clean; - } + status = be_cmd_reset_function(adapter); + if (status) + goto ctrl_clean; status = be_stats_init(adapter); if (status) @@ -2975,10 +2990,18 @@ static int __devinit be_probe(struct pci_dev *pdev, goto unsetup; netif_carrier_off(netdev); + if (be_physfn(adapter) && adapter->sriov_enabled) { + status = be_vf_eth_addr_config(adapter); + if (status) + goto unreg_netdev; + } + dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num); schedule_delayed_work(&adapter->work, msecs_to_jiffies(100)); return 0; +unreg_netdev: + unregister_netdev(netdev); unsetup: be_clear(adapter); msix_disable: @@ -3005,6 +3028,7 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state) struct be_adapter *adapter = pci_get_drvdata(pdev); struct net_device *netdev = adapter->netdev; + cancel_delayed_work_sync(&adapter->work); if (adapter->wol) be_setup_wol(adapter, true); @@ -3017,6 +3041,7 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state) be_cmd_get_flow_control(adapter, &adapter->tx_fc, &adapter->rx_fc); be_clear(adapter); + be_msix_disable(adapter); pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); @@ -3038,6 +3063,7 @@ static int be_resume(struct pci_dev *pdev) pci_set_power_state(pdev, 0); pci_restore_state(pdev); + be_msix_enable(adapter); /* tell fw we're ready to fire cmds */ status = be_cmd_fw_init(adapter); if (status) @@ -3053,6 +3079,8 @@ static int be_resume(struct pci_dev *pdev) if (adapter->wol) be_setup_wol(adapter, false); + + schedule_delayed_work(&adapter->work, msecs_to_jiffies(100)); return 0; } @@ -3064,6 +3092,9 @@ static void be_shutdown(struct pci_dev *pdev) struct be_adapter *adapter = pci_get_drvdata(pdev); struct net_device *netdev = adapter->netdev; + if (netif_running(netdev)) + cancel_delayed_work_sync(&adapter->work); + netif_device_detach(netdev); be_cmd_reset_function(adapter); diff --git a/drivers/net/bna/bnad.c b/drivers/net/bna/bnad.c index fad912656fe4..9f356d5d0f33 100644 --- a/drivers/net/bna/bnad.c +++ b/drivers/net/bna/bnad.c @@ -126,22 +126,22 @@ bnad_free_all_txbufs(struct bnad *bnad, } unmap_array[unmap_cons].skb = NULL; - pci_unmap_single(bnad->pcidev, - pci_unmap_addr(&unmap_array[unmap_cons], + dma_unmap_single(&bnad->pcidev->dev, + dma_unmap_addr(&unmap_array[unmap_cons], dma_addr), skb_headlen(skb), - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); - pci_unmap_addr_set(&unmap_array[unmap_cons], dma_addr, 0); + dma_unmap_addr_set(&unmap_array[unmap_cons], dma_addr, 0); if (++unmap_cons >= unmap_q->q_depth) break; for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - pci_unmap_page(bnad->pcidev, - pci_unmap_addr(&unmap_array[unmap_cons], + dma_unmap_page(&bnad->pcidev->dev, + dma_unmap_addr(&unmap_array[unmap_cons], dma_addr), skb_shinfo(skb)->frags[i].size, - PCI_DMA_TODEVICE); - pci_unmap_addr_set(&unmap_array[unmap_cons], dma_addr, + DMA_TO_DEVICE); + dma_unmap_addr_set(&unmap_array[unmap_cons], dma_addr, 0); if (++unmap_cons >= unmap_q->q_depth) break; @@ -199,23 +199,23 @@ bnad_free_txbufs(struct bnad *bnad, sent_bytes += skb->len; wis -= BNA_TXQ_WI_NEEDED(1 + skb_shinfo(skb)->nr_frags); - pci_unmap_single(bnad->pcidev, - pci_unmap_addr(&unmap_array[unmap_cons], + dma_unmap_single(&bnad->pcidev->dev, + dma_unmap_addr(&unmap_array[unmap_cons], dma_addr), skb_headlen(skb), - PCI_DMA_TODEVICE); - pci_unmap_addr_set(&unmap_array[unmap_cons], dma_addr, 0); + DMA_TO_DEVICE); + dma_unmap_addr_set(&unmap_array[unmap_cons], dma_addr, 0); BNA_QE_INDX_ADD(unmap_cons, 1, unmap_q->q_depth); prefetch(&unmap_array[unmap_cons + 1]); for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { prefetch(&unmap_array[unmap_cons + 1]); - pci_unmap_page(bnad->pcidev, - pci_unmap_addr(&unmap_array[unmap_cons], + dma_unmap_page(&bnad->pcidev->dev, + dma_unmap_addr(&unmap_array[unmap_cons], dma_addr), skb_shinfo(skb)->frags[i].size, - PCI_DMA_TODEVICE); - pci_unmap_addr_set(&unmap_array[unmap_cons], dma_addr, + DMA_TO_DEVICE); + dma_unmap_addr_set(&unmap_array[unmap_cons], dma_addr, 0); BNA_QE_INDX_ADD(unmap_cons, 1, unmap_q->q_depth); } @@ -340,19 +340,22 @@ static void bnad_free_all_rxbufs(struct bnad *bnad, struct bna_rcb *rcb) { struct bnad_unmap_q *unmap_q; + struct bnad_skb_unmap *unmap_array; struct sk_buff *skb; int unmap_cons; unmap_q = rcb->unmap_q; + unmap_array = unmap_q->unmap_array; for (unmap_cons = 0; unmap_cons < unmap_q->q_depth; unmap_cons++) { - skb = unmap_q->unmap_array[unmap_cons].skb; + skb = unmap_array[unmap_cons].skb; if (!skb) continue; - unmap_q->unmap_array[unmap_cons].skb = NULL; - pci_unmap_single(bnad->pcidev, pci_unmap_addr(&unmap_q-> - unmap_array[unmap_cons], - dma_addr), rcb->rxq->buffer_size, - PCI_DMA_FROMDEVICE); + unmap_array[unmap_cons].skb = NULL; + dma_unmap_single(&bnad->pcidev->dev, + dma_unmap_addr(&unmap_array[unmap_cons], + dma_addr), + rcb->rxq->buffer_size, + DMA_FROM_DEVICE); dev_kfree_skb(skb); } bnad_reset_rcb(bnad, rcb); @@ -391,9 +394,10 @@ bnad_alloc_n_post_rxbufs(struct bnad *bnad, struct bna_rcb *rcb) skb->dev = bnad->netdev; skb_reserve(skb, NET_IP_ALIGN); unmap_array[unmap_prod].skb = skb; - dma_addr = pci_map_single(bnad->pcidev, skb->data, - rcb->rxq->buffer_size, PCI_DMA_FROMDEVICE); - pci_unmap_addr_set(&unmap_array[unmap_prod], dma_addr, + dma_addr = dma_map_single(&bnad->pcidev->dev, skb->data, + rcb->rxq->buffer_size, + DMA_FROM_DEVICE); + dma_unmap_addr_set(&unmap_array[unmap_prod], dma_addr, dma_addr); BNA_SET_DMA_ADDR(dma_addr, &rxent->host_addr); BNA_QE_INDX_ADD(unmap_prod, 1, unmap_q->q_depth); @@ -434,8 +438,9 @@ bnad_poll_cq(struct bnad *bnad, struct bna_ccb *ccb, int budget) struct bna_rcb *rcb = NULL; unsigned int wi_range, packets = 0, wis = 0; struct bnad_unmap_q *unmap_q; + struct bnad_skb_unmap *unmap_array; struct sk_buff *skb; - u32 flags; + u32 flags, unmap_cons; u32 qid0 = ccb->rcb[0]->rxq->rxq_id; struct bna_pkt_rate *pkt_rt = &ccb->pkt_rate; @@ -456,17 +461,17 @@ bnad_poll_cq(struct bnad *bnad, struct bna_ccb *ccb, int budget) rcb = ccb->rcb[1]; unmap_q = rcb->unmap_q; + unmap_array = unmap_q->unmap_array; + unmap_cons = unmap_q->consumer_index; - skb = unmap_q->unmap_array[unmap_q->consumer_index].skb; + skb = unmap_array[unmap_cons].skb; BUG_ON(!(skb)); - unmap_q->unmap_array[unmap_q->consumer_index].skb = NULL; - pci_unmap_single(bnad->pcidev, - pci_unmap_addr(&unmap_q-> - unmap_array[unmap_q-> - consumer_index], + unmap_array[unmap_cons].skb = NULL; + dma_unmap_single(&bnad->pcidev->dev, + dma_unmap_addr(&unmap_array[unmap_cons], dma_addr), - rcb->rxq->buffer_size, - PCI_DMA_FROMDEVICE); + rcb->rxq->buffer_size, + DMA_FROM_DEVICE); BNA_QE_INDX_ADD(unmap_q->consumer_index, 1, unmap_q->q_depth); /* Should be more efficient ? Performance ? */ @@ -1015,9 +1020,9 @@ bnad_mem_free(struct bnad *bnad, if (mem_info->mem_type == BNA_MEM_T_DMA) { BNA_GET_DMA_ADDR(&(mem_info->mdl[i].dma), dma_pa); - pci_free_consistent(bnad->pcidev, - mem_info->mdl[i].len, - mem_info->mdl[i].kva, dma_pa); + dma_free_coherent(&bnad->pcidev->dev, + mem_info->mdl[i].len, + mem_info->mdl[i].kva, dma_pa); } else kfree(mem_info->mdl[i].kva); } @@ -1047,8 +1052,9 @@ bnad_mem_alloc(struct bnad *bnad, for (i = 0; i < mem_info->num; i++) { mem_info->mdl[i].len = mem_info->len; mem_info->mdl[i].kva = - pci_alloc_consistent(bnad->pcidev, - mem_info->len, &dma_pa); + dma_alloc_coherent(&bnad->pcidev->dev, + mem_info->len, &dma_pa, + GFP_KERNEL); if (mem_info->mdl[i].kva == NULL) goto err_return; @@ -2600,9 +2606,9 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev) unmap_q->unmap_array[unmap_prod].skb = skb; BUG_ON(!(skb_headlen(skb) <= BFI_TX_MAX_DATA_PER_VECTOR)); txqent->vector[vect_id].length = htons(skb_headlen(skb)); - dma_addr = pci_map_single(bnad->pcidev, skb->data, skb_headlen(skb), - PCI_DMA_TODEVICE); - pci_unmap_addr_set(&unmap_q->unmap_array[unmap_prod], dma_addr, + dma_addr = dma_map_single(&bnad->pcidev->dev, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); + dma_unmap_addr_set(&unmap_q->unmap_array[unmap_prod], dma_addr, dma_addr); BNA_SET_DMA_ADDR(dma_addr, &txqent->vector[vect_id].host_addr); @@ -2630,11 +2636,9 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev) BUG_ON(!(size <= BFI_TX_MAX_DATA_PER_VECTOR)); txqent->vector[vect_id].length = htons(size); - dma_addr = - pci_map_page(bnad->pcidev, frag->page, - frag->page_offset, size, - PCI_DMA_TODEVICE); - pci_unmap_addr_set(&unmap_q->unmap_array[unmap_prod], dma_addr, + dma_addr = dma_map_page(&bnad->pcidev->dev, frag->page, + frag->page_offset, size, DMA_TO_DEVICE); + dma_unmap_addr_set(&unmap_q->unmap_array[unmap_prod], dma_addr, dma_addr); BNA_SET_DMA_ADDR(dma_addr, &txqent->vector[vect_id].host_addr); BNA_QE_INDX_ADD(unmap_prod, 1, unmap_q->q_depth); @@ -3022,14 +3026,14 @@ bnad_pci_init(struct bnad *bnad, err = pci_request_regions(pdev, BNAD_NAME); if (err) goto disable_device; - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && - !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { + if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) && + !dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) { *using_dac = 1; } else { - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (err) { - err = pci_set_consistent_dma_mask(pdev, - DMA_BIT_MASK(32)); + err = dma_set_coherent_mask(&pdev->dev, + DMA_BIT_MASK(32)); if (err) goto release_regions; } diff --git a/drivers/net/bna/bnad.h b/drivers/net/bna/bnad.h index 8b1d51557def..a89117fa4970 100644 --- a/drivers/net/bna/bnad.h +++ b/drivers/net/bna/bnad.h @@ -181,7 +181,7 @@ struct bnad_rx_info { /* Unmap queues for Tx / Rx cleanup */ struct bnad_skb_unmap { struct sk_buff *skb; - DECLARE_PCI_UNMAP_ADDR(dma_addr) + DEFINE_DMA_UNMAP_ADDR(dma_addr); }; struct bnad_unmap_q { diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 0ba59d5aeb7f..2a961b7f7e17 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -435,7 +435,8 @@ bnx2_cnic_stop(struct bnx2 *bp) struct cnic_ctl_info info; mutex_lock(&bp->cnic_lock); - c_ops = bp->cnic_ops; + c_ops = rcu_dereference_protected(bp->cnic_ops, + lockdep_is_held(&bp->cnic_lock)); if (c_ops) { info.cmd = CNIC_CTL_STOP_CMD; c_ops->cnic_ctl(bp->cnic_data, &info); @@ -450,7 +451,8 @@ bnx2_cnic_start(struct bnx2 *bp) struct cnic_ctl_info info; mutex_lock(&bp->cnic_lock); - c_ops = bp->cnic_ops; + c_ops = rcu_dereference_protected(bp->cnic_ops, + lockdep_is_held(&bp->cnic_lock)); if (c_ops) { if (!(bp->flags & BNX2_FLAG_USING_MSIX)) { struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; @@ -8315,7 +8317,7 @@ static const struct net_device_ops bnx2_netdev_ops = { #endif }; -static void inline vlan_features_add(struct net_device *dev, unsigned long flags) +static void inline vlan_features_add(struct net_device *dev, u32 flags) { dev->vlan_features |= flags; } diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index f459fb2f9add..7a5e88f831f6 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6207,6 +6207,8 @@ struct l2_fhdr { #define BNX2_CP_SCRATCH 0x001a0000 +#define BNX2_FW_MAX_ISCSI_CONN 0x001a0080 + /* * mcp_reg definition @@ -6759,7 +6761,7 @@ struct bnx2 { u32 tx_wake_thresh; #ifdef BCM_CNIC - struct cnic_ops *cnic_ops; + struct cnic_ops __rcu *cnic_ops; void *cnic_data; #endif diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h index 653c62475cb6..c0dd30d870ae 100644 --- a/drivers/net/bnx2x/bnx2x.h +++ b/drivers/net/bnx2x/bnx2x.h @@ -22,8 +22,8 @@ * (you will need to reboot afterwards) */ /* #define BNX2X_STOP_ON_ERROR */ -#define DRV_MODULE_VERSION "1.62.00-5" -#define DRV_MODULE_RELDATE "2011/01/30" +#define DRV_MODULE_VERSION "1.62.11-0" +#define DRV_MODULE_RELDATE "2011/01/31" #define BNX2X_BC_VER 0x040200 #define BNX2X_MULTI_QUEUE @@ -129,6 +129,7 @@ void bnx2x_panic_dump(struct bnx2x *bp); #endif #define bnx2x_mc_addr(ha) ((ha)->addr) +#define bnx2x_uc_addr(ha) ((ha)->addr) #define U64_LO(x) (u32)(((u64)(x)) & 0xffffffff) #define U64_HI(x) (u32)(((u64)(x)) >> 32) @@ -341,6 +342,8 @@ struct bnx2x_fastpath { /* chip independed shortcut into rx_prods_offset memory */ u32 ustorm_rx_prods_offset; + u32 rx_buf_size; + dma_addr_t status_blk_mapping; struct sw_tx_bd *tx_buf_ring; @@ -428,6 +431,10 @@ struct bnx2x_fastpath { }; #define bnx2x_fp(bp, nr, var) (bp->fp[nr].var) + +/* Use 2500 as a mini-jumbo MTU for FCoE */ +#define BNX2X_FCOE_MINI_JUMBO_MTU 2500 + #ifdef BCM_CNIC /* FCoE L2 `fastpath' is right after the eth entries */ #define FCOE_IDX BNX2X_NUM_ETH_QUEUES(bp) @@ -810,6 +817,7 @@ struct bnx2x_slowpath { struct eth_stats_query fw_stats; struct mac_configuration_cmd mac_config; struct mac_configuration_cmd mcast_config; + struct mac_configuration_cmd uc_mac_config; struct client_init_ramrod_data client_init_data; /* used by dmae command executer */ @@ -911,7 +919,6 @@ struct bnx2x { int tx_ring_size; u32 rx_csum; - u32 rx_buf_size; /* L2 header size + 2*VLANs (8 bytes) + LLC SNAP (8 bytes) */ #define ETH_OVREHEAD (ETH_HLEN + 8 + 8) #define ETH_MIN_PACKET_SIZE 60 @@ -939,7 +946,7 @@ struct bnx2x { struct eth_spe *spq_prod_bd; struct eth_spe *spq_last_bd; __le16 *dsb_sp_prod; - atomic_t spq_left; /* serialize spq */ + atomic_t cq_spq_left; /* ETH_XXX ramrods credit */ /* used to synchronize spq accesses */ spinlock_t spq_lock; @@ -949,6 +956,7 @@ struct bnx2x { u16 eq_prod; u16 eq_cons; __le16 *eq_cons_sb; + atomic_t eq_spq_left; /* COMMON_XXX ramrods credit */ /* Flags for marking that there is a STAT_QUERY or SET_MAC ramrod pending */ @@ -976,8 +984,12 @@ struct bnx2x { #define MF_FUNC_DIS 0x1000 #define FCOE_MACS_SET 0x2000 #define NO_FCOE_FLAG 0x4000 +#define NO_ISCSI_OOO_FLAG 0x8000 +#define NO_ISCSI_FLAG 0x10000 #define NO_FCOE(bp) ((bp)->flags & NO_FCOE_FLAG) +#define NO_ISCSI(bp) ((bp)->flags & NO_ISCSI_FLAG) +#define NO_ISCSI_OOO(bp) ((bp)->flags & NO_ISCSI_OOO_FLAG) int pf_num; /* absolute PF number */ int pfid; /* per-path PF number */ @@ -1064,6 +1076,7 @@ struct bnx2x { int num_queues; int disable_tpa; int int_mode; + u32 *rx_indir_table; struct tstorm_eth_mac_filter_config mac_filters; #define BNX2X_ACCEPT_NONE 0x0000 @@ -1110,7 +1123,7 @@ struct bnx2x { #define BNX2X_CNIC_FLAG_MAC_SET 1 void *t2; dma_addr_t t2_mapping; - struct cnic_ops *cnic_ops; + struct cnic_ops __rcu *cnic_ops; void *cnic_data; u32 cnic_tag; struct cnic_eth_dev cnic_eth_dev; @@ -1125,13 +1138,12 @@ struct bnx2x { u16 cnic_kwq_pending; u16 cnic_spq_pending; struct mutex cnic_mutex; - u8 iscsi_mac[ETH_ALEN]; u8 fip_mac[ETH_ALEN]; #endif int dmae_ready; /* used to synchronize dmae accesses */ - struct mutex dmae_mutex; + spinlock_t dmae_lock; /* used to protect the FW mail box */ struct mutex fw_mb_mutex; @@ -1447,6 +1459,12 @@ u32 bnx2x_fw_command(struct bnx2x *bp, u32 command, u32 param); void bnx2x_calc_fc_adv(struct bnx2x *bp); int bnx2x_sp_post(struct bnx2x *bp, int command, int cid, u32 data_hi, u32 data_lo, int common); + +/* Clears multicast and unicast list configuration in the chip. */ +void bnx2x_invalidate_e1_mc_list(struct bnx2x *bp); +void bnx2x_invalidate_e1h_mc_list(struct bnx2x *bp); +void bnx2x_invalidate_uc_list(struct bnx2x *bp); + void bnx2x_update_coalesce(struct bnx2x *bp); int bnx2x_get_link_cfg_idx(struct bnx2x *bp); @@ -1782,5 +1800,6 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, BNX2X_EXTERN int load_count[2][3]; /* per path: 0-common, 1-port0, 2-port1 */ extern void bnx2x_set_ethtool_ops(struct net_device *netdev); +void bnx2x_push_indir_table(struct bnx2x *bp); #endif /* bnx2x.h */ diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c index 710ce5d04c53..6fac8e183c59 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.c +++ b/drivers/net/bnx2x/bnx2x_cmn.c @@ -232,7 +232,7 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue, /* move empty skb from pool to prod and map it */ prod_rx_buf->skb = fp->tpa_pool[queue].skb; mapping = dma_map_single(&bp->pdev->dev, fp->tpa_pool[queue].skb->data, - bp->rx_buf_size, DMA_FROM_DEVICE); + fp->rx_buf_size, DMA_FROM_DEVICE); dma_unmap_addr_set(prod_rx_buf, mapping, mapping); /* move partial skb from cons to pool (don't unmap yet) */ @@ -333,13 +333,13 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp, struct sw_rx_bd *rx_buf = &fp->tpa_pool[queue]; struct sk_buff *skb = rx_buf->skb; /* alloc new skb */ - struct sk_buff *new_skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size); + struct sk_buff *new_skb = netdev_alloc_skb(bp->dev, fp->rx_buf_size); /* Unmap skb in the pool anyway, as we are going to change pool entry status to BNX2X_TPA_STOP even if new skb allocation fails. */ dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(rx_buf, mapping), - bp->rx_buf_size, DMA_FROM_DEVICE); + fp->rx_buf_size, DMA_FROM_DEVICE); if (likely(new_skb)) { /* fix ip xsum and give it to the stack */ @@ -349,10 +349,10 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp, prefetch(((char *)(skb)) + L1_CACHE_BYTES); #ifdef BNX2X_STOP_ON_ERROR - if (pad + len > bp->rx_buf_size) { + if (pad + len > fp->rx_buf_size) { BNX2X_ERR("skb_put is about to fail... " "pad %d len %d rx_buf_size %d\n", - pad, len, bp->rx_buf_size); + pad, len, fp->rx_buf_size); bnx2x_panic(); return; } @@ -582,7 +582,7 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) if (likely(bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0)) { dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(rx_buf, mapping), - bp->rx_buf_size, + fp->rx_buf_size, DMA_FROM_DEVICE); skb_reserve(skb, pad); skb_put(skb, len); @@ -821,19 +821,16 @@ void bnx2x_init_rx_rings(struct bnx2x *bp) u16 ring_prod; int i, j; - bp->rx_buf_size = bp->dev->mtu + ETH_OVREHEAD + BNX2X_RX_ALIGN + - IP_HEADER_ALIGNMENT_PADDING; - - DP(NETIF_MSG_IFUP, - "mtu %d rx_buf_size %d\n", bp->dev->mtu, bp->rx_buf_size); - for_each_rx_queue(bp, j) { struct bnx2x_fastpath *fp = &bp->fp[j]; + DP(NETIF_MSG_IFUP, + "mtu %d rx_buf_size %d\n", bp->dev->mtu, fp->rx_buf_size); + if (!fp->disable_tpa) { for (i = 0; i < max_agg_queues; i++) { fp->tpa_pool[i].skb = - netdev_alloc_skb(bp->dev, bp->rx_buf_size); + netdev_alloc_skb(bp->dev, fp->rx_buf_size); if (!fp->tpa_pool[i].skb) { BNX2X_ERR("Failed to allocate TPA " "skb pool for queue[%d] - " @@ -941,7 +938,7 @@ static void bnx2x_free_rx_skbs(struct bnx2x *bp) dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(rx_buf, mapping), - bp->rx_buf_size, DMA_FROM_DEVICE); + fp->rx_buf_size, DMA_FROM_DEVICE); rx_buf->skb = NULL; dev_kfree_skb(skb); @@ -1249,6 +1246,31 @@ static inline int bnx2x_set_real_num_queues(struct bnx2x *bp) return rc; } +static inline void bnx2x_set_rx_buf_size(struct bnx2x *bp) +{ + int i; + + for_each_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + + /* Always use a mini-jumbo MTU for the FCoE L2 ring */ + if (IS_FCOE_IDX(i)) + /* + * Although there are no IP frames expected to arrive to + * this ring we still want to add an + * IP_HEADER_ALIGNMENT_PADDING to prevent a buffer + * overrun attack. + */ + fp->rx_buf_size = + BNX2X_FCOE_MINI_JUMBO_MTU + ETH_OVREHEAD + + BNX2X_RX_ALIGN + IP_HEADER_ALIGNMENT_PADDING; + else + fp->rx_buf_size = + bp->dev->mtu + ETH_OVREHEAD + BNX2X_RX_ALIGN + + IP_HEADER_ALIGNMENT_PADDING; + } +} + /* must be called with rtnl_lock */ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) { @@ -1272,6 +1294,9 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) /* must be called before memory allocation and HW init */ bnx2x_ilt_set_info(bp); + /* Set the receive queues buffer size */ + bnx2x_set_rx_buf_size(bp); + if (bnx2x_alloc_mem(bp)) return -ENOMEM; @@ -1427,28 +1452,35 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) bnx2x_set_eth_mac(bp, 1); + /* Clear MC configuration */ + if (CHIP_IS_E1(bp)) + bnx2x_invalidate_e1_mc_list(bp); + else + bnx2x_invalidate_e1h_mc_list(bp); + + /* Clear UC lists configuration */ + bnx2x_invalidate_uc_list(bp); + if (bp->port.pmf) bnx2x_initial_phy_init(bp, load_mode); + /* Initialize Rx filtering */ + bnx2x_set_rx_mode(bp->dev); + /* Start fast path */ switch (load_mode) { case LOAD_NORMAL: /* Tx queue should be only reenabled */ netif_tx_wake_all_queues(bp->dev); /* Initialize the receive filter. */ - bnx2x_set_rx_mode(bp->dev); break; case LOAD_OPEN: netif_tx_start_all_queues(bp->dev); smp_mb__after_clear_bit(); - /* Initialize the receive filter. */ - bnx2x_set_rx_mode(bp->dev); break; case LOAD_DIAG: - /* Initialize the receive filter. */ - bnx2x_set_rx_mode(bp->dev); bp->state = BNX2X_STATE_DIAG; break; diff --git a/drivers/net/bnx2x/bnx2x_cmn.h b/drivers/net/bnx2x/bnx2x_cmn.h index 03eb4d68e6bb..f062d5d20fa9 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.h +++ b/drivers/net/bnx2x/bnx2x_cmn.h @@ -822,11 +822,11 @@ static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp, struct eth_rx_bd *rx_bd = &fp->rx_desc_ring[index]; dma_addr_t mapping; - skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size); + skb = netdev_alloc_skb(bp->dev, fp->rx_buf_size); if (unlikely(skb == NULL)) return -ENOMEM; - mapping = dma_map_single(&bp->pdev->dev, skb->data, bp->rx_buf_size, + mapping = dma_map_single(&bp->pdev->dev, skb->data, fp->rx_buf_size, DMA_FROM_DEVICE); if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) { dev_kfree_skb(skb); @@ -892,7 +892,7 @@ static inline void bnx2x_free_tpa_pool(struct bnx2x *bp, if (fp->tpa_state[i] == BNX2X_TPA_START) dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(rx_buf, mapping), - bp->rx_buf_size, DMA_FROM_DEVICE); + fp->rx_buf_size, DMA_FROM_DEVICE); dev_kfree_skb(skb); rx_buf->skb = NULL; diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c index 5b44a8b48509..8d19d127f796 100644 --- a/drivers/net/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/bnx2x/bnx2x_ethtool.c @@ -1618,7 +1618,7 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up) /* prepare the loopback packet */ pkt_size = (((bp->dev->mtu < ETH_MAX_PACKET_SIZE) ? bp->dev->mtu : ETH_MAX_PACKET_SIZE) + ETH_HLEN); - skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size); + skb = netdev_alloc_skb(bp->dev, fp_rx->rx_buf_size); if (!skb) { rc = -ENOMEM; goto test_loopback_exit; @@ -2134,6 +2134,59 @@ static int bnx2x_phys_id(struct net_device *dev, u32 data) return 0; } +static int bnx2x_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, + void *rules __always_unused) +{ + struct bnx2x *bp = netdev_priv(dev); + + switch (info->cmd) { + case ETHTOOL_GRXRINGS: + info->data = BNX2X_NUM_ETH_QUEUES(bp); + return 0; + + default: + return -EOPNOTSUPP; + } +} + +static int bnx2x_get_rxfh_indir(struct net_device *dev, + struct ethtool_rxfh_indir *indir) +{ + struct bnx2x *bp = netdev_priv(dev); + size_t copy_size = + min_t(size_t, indir->size, TSTORM_INDIRECTION_TABLE_SIZE); + + if (bp->multi_mode == ETH_RSS_MODE_DISABLED) + return -EOPNOTSUPP; + + indir->size = TSTORM_INDIRECTION_TABLE_SIZE; + memcpy(indir->ring_index, bp->rx_indir_table, + copy_size * sizeof(bp->rx_indir_table[0])); + return 0; +} + +static int bnx2x_set_rxfh_indir(struct net_device *dev, + const struct ethtool_rxfh_indir *indir) +{ + struct bnx2x *bp = netdev_priv(dev); + size_t i; + + if (bp->multi_mode == ETH_RSS_MODE_DISABLED) + return -EOPNOTSUPP; + + /* Validate size and indices */ + if (indir->size != TSTORM_INDIRECTION_TABLE_SIZE) + return -EINVAL; + for (i = 0; i < TSTORM_INDIRECTION_TABLE_SIZE; i++) + if (indir->ring_index[i] >= BNX2X_NUM_ETH_QUEUES(bp)) + return -EINVAL; + + memcpy(bp->rx_indir_table, indir->ring_index, + indir->size * sizeof(bp->rx_indir_table[0])); + bnx2x_push_indir_table(bp); + return 0; +} + static const struct ethtool_ops bnx2x_ethtool_ops = { .get_settings = bnx2x_get_settings, .set_settings = bnx2x_set_settings, @@ -2170,6 +2223,9 @@ static const struct ethtool_ops bnx2x_ethtool_ops = { .get_strings = bnx2x_get_strings, .phys_id = bnx2x_phys_id, .get_ethtool_stats = bnx2x_get_ethtool_stats, + .get_rxnfc = bnx2x_get_rxnfc, + .get_rxfh_indir = bnx2x_get_rxfh_indir, + .set_rxfh_indir = bnx2x_set_rxfh_indir, }; void bnx2x_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/bnx2x/bnx2x_hsi.h b/drivers/net/bnx2x/bnx2x_hsi.h index 548f5631c0dc..be503cc0a50b 100644 --- a/drivers/net/bnx2x/bnx2x_hsi.h +++ b/drivers/net/bnx2x/bnx2x_hsi.h @@ -11,20 +11,27 @@ #include "bnx2x_fw_defs.h" +#define FW_ENCODE_32BIT_PATTERN 0x1e1e1e1e + struct license_key { u32 reserved[6]; -#if defined(__BIG_ENDIAN) - u16 max_iscsi_init_conn; - u16 max_iscsi_trgt_conn; -#elif defined(__LITTLE_ENDIAN) - u16 max_iscsi_trgt_conn; - u16 max_iscsi_init_conn; -#endif + u32 max_iscsi_conn; +#define BNX2X_MAX_ISCSI_TRGT_CONN_MASK 0xFFFF +#define BNX2X_MAX_ISCSI_TRGT_CONN_SHIFT 0 +#define BNX2X_MAX_ISCSI_INIT_CONN_MASK 0xFFFF0000 +#define BNX2X_MAX_ISCSI_INIT_CONN_SHIFT 16 - u32 reserved_a[6]; -}; + u32 reserved_a; + + u32 max_fcoe_conn; +#define BNX2X_MAX_FCOE_TRGT_CONN_MASK 0xFFFF +#define BNX2X_MAX_FCOE_TRGT_CONN_SHIFT 0 +#define BNX2X_MAX_FCOE_INIT_CONN_MASK 0xFFFF0000 +#define BNX2X_MAX_FCOE_INIT_CONN_SHIFT 16 + u32 reserved_b[4]; +}; #define PORT_0 0 #define PORT_1 1 @@ -237,8 +244,26 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */ #define PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_SHIFT 16 - u32 Reserved0[16]; /* 0x158 */ - + u32 Reserved0[3]; /* 0x158 */ + /* Controls the TX laser of the SFP+ module */ + u32 sfp_ctrl; /* 0x164 */ +#define PORT_HW_CFG_TX_LASER_MASK 0x000000FF +#define PORT_HW_CFG_TX_LASER_SHIFT 0 +#define PORT_HW_CFG_TX_LASER_MDIO 0x00000000 +#define PORT_HW_CFG_TX_LASER_GPIO0 0x00000001 +#define PORT_HW_CFG_TX_LASER_GPIO1 0x00000002 +#define PORT_HW_CFG_TX_LASER_GPIO2 0x00000003 +#define PORT_HW_CFG_TX_LASER_GPIO3 0x00000004 + + /* Controls the fault module LED of the SFP+ */ +#define PORT_HW_CFG_FAULT_MODULE_LED_MASK 0x0000FF00 +#define PORT_HW_CFG_FAULT_MODULE_LED_SHIFT 8 +#define PORT_HW_CFG_FAULT_MODULE_LED_GPIO0 0x00000000 +#define PORT_HW_CFG_FAULT_MODULE_LED_GPIO1 0x00000100 +#define PORT_HW_CFG_FAULT_MODULE_LED_GPIO2 0x00000200 +#define PORT_HW_CFG_FAULT_MODULE_LED_GPIO3 0x00000300 +#define PORT_HW_CFG_FAULT_MODULE_LED_DISABLED 0x00000400 + u32 Reserved01[12]; /* 0x158 */ /* for external PHY, or forced mode or during AN */ u16 xgxs_config_rx[4]; /* 0x198 */ @@ -246,12 +271,78 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */ u32 Reserved1[56]; /* 0x1A8 */ u32 default_cfg; /* 0x288 */ +#define PORT_HW_CFG_GPIO0_CONFIG_MASK 0x00000003 +#define PORT_HW_CFG_GPIO0_CONFIG_SHIFT 0 +#define PORT_HW_CFG_GPIO0_CONFIG_NA 0x00000000 +#define PORT_HW_CFG_GPIO0_CONFIG_LOW 0x00000001 +#define PORT_HW_CFG_GPIO0_CONFIG_HIGH 0x00000002 +#define PORT_HW_CFG_GPIO0_CONFIG_INPUT 0x00000003 + +#define PORT_HW_CFG_GPIO1_CONFIG_MASK 0x0000000C +#define PORT_HW_CFG_GPIO1_CONFIG_SHIFT 2 +#define PORT_HW_CFG_GPIO1_CONFIG_NA 0x00000000 +#define PORT_HW_CFG_GPIO1_CONFIG_LOW 0x00000004 +#define PORT_HW_CFG_GPIO1_CONFIG_HIGH 0x00000008 +#define PORT_HW_CFG_GPIO1_CONFIG_INPUT 0x0000000c + +#define PORT_HW_CFG_GPIO2_CONFIG_MASK 0x00000030 +#define PORT_HW_CFG_GPIO2_CONFIG_SHIFT 4 +#define PORT_HW_CFG_GPIO2_CONFIG_NA 0x00000000 +#define PORT_HW_CFG_GPIO2_CONFIG_LOW 0x00000010 +#define PORT_HW_CFG_GPIO2_CONFIG_HIGH 0x00000020 +#define PORT_HW_CFG_GPIO2_CONFIG_INPUT 0x00000030 + +#define PORT_HW_CFG_GPIO3_CONFIG_MASK 0x000000C0 +#define PORT_HW_CFG_GPIO3_CONFIG_SHIFT 6 +#define PORT_HW_CFG_GPIO3_CONFIG_NA 0x00000000 +#define PORT_HW_CFG_GPIO3_CONFIG_LOW 0x00000040 +#define PORT_HW_CFG_GPIO3_CONFIG_HIGH 0x00000080 +#define PORT_HW_CFG_GPIO3_CONFIG_INPUT 0x000000c0 + + /* + * When KR link is required to be set to force which is not + * KR-compliant, this parameter determine what is the trigger for it. + * When GPIO is selected, low input will force the speed. Currently + * default speed is 1G. In the future, it may be widen to select the + * forced speed in with another parameter. Note when force-1G is + * enabled, it override option 56: Link Speed option. + */ +#define PORT_HW_CFG_FORCE_KR_ENABLER_MASK 0x00000F00 +#define PORT_HW_CFG_FORCE_KR_ENABLER_SHIFT 8 +#define PORT_HW_CFG_FORCE_KR_ENABLER_NOT_FORCED 0x00000000 +#define PORT_HW_CFG_FORCE_KR_ENABLER_GPIO0_P0 0x00000100 +#define PORT_HW_CFG_FORCE_KR_ENABLER_GPIO1_P0 0x00000200 +#define PORT_HW_CFG_FORCE_KR_ENABLER_GPIO2_P0 0x00000300 +#define PORT_HW_CFG_FORCE_KR_ENABLER_GPIO3_P0 0x00000400 +#define PORT_HW_CFG_FORCE_KR_ENABLER_GPIO0_P1 0x00000500 +#define PORT_HW_CFG_FORCE_KR_ENABLER_GPIO1_P1 0x00000600 +#define PORT_HW_CFG_FORCE_KR_ENABLER_GPIO2_P1 0x00000700 +#define PORT_HW_CFG_FORCE_KR_ENABLER_GPIO3_P1 0x00000800 +#define PORT_HW_CFG_FORCE_KR_ENABLER_FORCED 0x00000900 + /* Enable to determine with which GPIO to reset the external phy */ +#define PORT_HW_CFG_EXT_PHY_GPIO_RST_MASK 0x000F0000 +#define PORT_HW_CFG_EXT_PHY_GPIO_RST_SHIFT 16 +#define PORT_HW_CFG_EXT_PHY_GPIO_RST_PHY_TYPE 0x00000000 +#define PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO0_P0 0x00010000 +#define PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO1_P0 0x00020000 +#define PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO2_P0 0x00030000 +#define PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO3_P0 0x00040000 +#define PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO0_P1 0x00050000 +#define PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO1_P1 0x00060000 +#define PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO2_P1 0x00070000 +#define PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO3_P1 0x00080000 /* Enable BAM on KR */ #define PORT_HW_CFG_ENABLE_BAM_ON_KR_MASK 0x00100000 #define PORT_HW_CFG_ENABLE_BAM_ON_KR_SHIFT 20 #define PORT_HW_CFG_ENABLE_BAM_ON_KR_DISABLED 0x00000000 #define PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED 0x00100000 + /* Enable Common Mode Sense */ +#define PORT_HW_CFG_ENABLE_CMS_MASK 0x00200000 +#define PORT_HW_CFG_ENABLE_CMS_SHIFT 21 +#define PORT_HW_CFG_ENABLE_CMS_DISABLED 0x00000000 +#define PORT_HW_CFG_ENABLE_CMS_ENABLED 0x00200000 + u32 speed_capability_mask2; /* 0x28C */ #define PORT_HW_CFG_SPEED_CAPABILITY2_D3_MASK 0x0000FFFF #define PORT_HW_CFG_SPEED_CAPABILITY2_D3_SHIFT 0 @@ -381,6 +472,7 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */ #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727 0x00000900 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC 0x00000a00 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823 0x00000b00 +#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833 0x00000d00 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE 0x0000fd00 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN 0x0000ff00 diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c index dd1210fddfff..f2f367d4e74d 100644 --- a/drivers/net/bnx2x/bnx2x_link.c +++ b/drivers/net/bnx2x/bnx2x_link.c @@ -1,4 +1,4 @@ -/* Copyright 2008-2009 Broadcom Corporation +/* Copyright 2008-2011 Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -28,12 +28,13 @@ /********************************************************/ #define ETH_HLEN 14 -#define ETH_OVREHEAD (ETH_HLEN + 8 + 8)/* 16 for CRC + VLAN + LLC */ +/* L2 header size + 2*VLANs (8 bytes) + LLC SNAP (8 bytes) */ +#define ETH_OVREHEAD (ETH_HLEN + 8 + 8) #define ETH_MIN_PACKET_SIZE 60 #define ETH_MAX_PACKET_SIZE 1500 #define ETH_MAX_JUMBO_PACKET_SIZE 9600 #define MDIO_ACCESS_TIMEOUT 1000 -#define BMAC_CONTROL_RX_ENABLE 2 +#define BMAC_CONTROL_RX_ENABLE 2 /***********************************************************/ /* Shortcut definitions */ @@ -79,7 +80,7 @@ #define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37 #define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73 -#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM +#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM #define AUTONEG_PARALLEL \ SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION #define AUTONEG_SGMII_FIBER_AUTODET \ @@ -112,10 +113,10 @@ #define GP_STATUS_10G_KX4 \ MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4 -#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD -#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD +#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD +#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD #define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD -#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4 +#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4 #define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD #define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD #define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD @@ -123,18 +124,18 @@ #define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD #define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD #define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD -#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD -#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD -#define LINK_12GTFD LINK_STATUS_SPEED_AND_DUPLEX_12GTFD -#define LINK_12GXFD LINK_STATUS_SPEED_AND_DUPLEX_12GXFD +#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD +#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD +#define LINK_12GTFD LINK_STATUS_SPEED_AND_DUPLEX_12GTFD +#define LINK_12GXFD LINK_STATUS_SPEED_AND_DUPLEX_12GXFD #define LINK_12_5GTFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD #define LINK_12_5GXFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD -#define LINK_13GTFD LINK_STATUS_SPEED_AND_DUPLEX_13GTFD -#define LINK_13GXFD LINK_STATUS_SPEED_AND_DUPLEX_13GXFD -#define LINK_15GTFD LINK_STATUS_SPEED_AND_DUPLEX_15GTFD -#define LINK_15GXFD LINK_STATUS_SPEED_AND_DUPLEX_15GXFD -#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD -#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD +#define LINK_13GTFD LINK_STATUS_SPEED_AND_DUPLEX_13GTFD +#define LINK_13GXFD LINK_STATUS_SPEED_AND_DUPLEX_13GXFD +#define LINK_15GTFD LINK_STATUS_SPEED_AND_DUPLEX_15GTFD +#define LINK_15GXFD LINK_STATUS_SPEED_AND_DUPLEX_15GXFD +#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD +#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD #define PHY_XGXS_FLAG 0x1 #define PHY_SGMII_FLAG 0x2 @@ -142,7 +143,7 @@ /* */ #define SFP_EEPROM_CON_TYPE_ADDR 0x2 - #define SFP_EEPROM_CON_TYPE_VAL_LC 0x7 + #define SFP_EEPROM_CON_TYPE_VAL_LC 0x7 #define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21 @@ -153,15 +154,15 @@ #define SFP_EEPROM_FC_TX_TECH_ADDR 0x8 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4 - #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8 + #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8 -#define SFP_EEPROM_OPTIONS_ADDR 0x40 +#define SFP_EEPROM_OPTIONS_ADDR 0x40 #define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1 -#define SFP_EEPROM_OPTIONS_SIZE 2 +#define SFP_EEPROM_OPTIONS_SIZE 2 -#define EDC_MODE_LINEAR 0x0022 -#define EDC_MODE_LIMITING 0x0044 -#define EDC_MODE_PASSIVE_DAC 0x0055 +#define EDC_MODE_LINEAR 0x0022 +#define EDC_MODE_LIMITING 0x0044 +#define EDC_MODE_PASSIVE_DAC 0x0055 #define ETS_BW_LIMIT_CREDIT_UPPER_BOUND (0x5000) @@ -170,24 +171,18 @@ /* INTERFACE */ /**********************************************************/ -#define CL45_WR_OVER_CL22(_bp, _phy, _bank, _addr, _val) \ +#define CL22_WR_OVER_CL45(_bp, _phy, _bank, _addr, _val) \ bnx2x_cl45_write(_bp, _phy, \ (_phy)->def_md_devad, \ (_bank + (_addr & 0xf)), \ _val) -#define CL45_RD_OVER_CL22(_bp, _phy, _bank, _addr, _val) \ +#define CL22_RD_OVER_CL45(_bp, _phy, _bank, _addr, _val) \ bnx2x_cl45_read(_bp, _phy, \ (_phy)->def_md_devad, \ (_bank + (_addr & 0xf)), \ _val) -static u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy, - u8 devad, u16 reg, u16 *ret_val); - -static u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy, - u8 devad, u16 reg, u16 val); - static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits) { u32 val = REG_RD(bp, reg); @@ -216,7 +211,7 @@ void bnx2x_ets_disabled(struct link_params *params) DP(NETIF_MSG_LINK, "ETS disabled configuration\n"); - /** + /* * mapping between entry priority to client number (0,1,2 -debug and * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST) * 3bits client num. @@ -225,7 +220,7 @@ void bnx2x_ets_disabled(struct link_params *params) */ REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, 0x4688); - /** + /* * Bitmap of 5bits length. Each bit specifies whether the entry behaves * as strict. Bits 0,1,2 - debug and management entries, 3 - * COS0 entry, 4 - COS1 entry. @@ -237,12 +232,12 @@ void bnx2x_ets_disabled(struct link_params *params) REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7); /* defines which entries (clients) are subjected to WFQ arbitration */ REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0); - /** - * For strict priority entries defines the number of consecutive - * slots for the highest priority. - */ + /* + * For strict priority entries defines the number of consecutive + * slots for the highest priority. + */ REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100); - /** + /* * mapping between the CREDIT_WEIGHT registers and actual client * numbers */ @@ -255,7 +250,7 @@ void bnx2x_ets_disabled(struct link_params *params) REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, 0); /* ETS mode disable */ REG_WR(bp, PBF_REG_ETS_ENABLED, 0); - /** + /* * If ETS mode is enabled (there is no strict priority) defines a WFQ * weight for COS0/COS1. */ @@ -268,24 +263,24 @@ void bnx2x_ets_disabled(struct link_params *params) REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0); } -void bnx2x_ets_bw_limit_common(const struct link_params *params) +static void bnx2x_ets_bw_limit_common(const struct link_params *params) { /* ETS disabled configuration */ struct bnx2x *bp = params->bp; DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n"); - /** - * defines which entries (clients) are subjected to WFQ arbitration - * COS0 0x8 - * COS1 0x10 - */ + /* + * defines which entries (clients) are subjected to WFQ arbitration + * COS0 0x8 + * COS1 0x10 + */ REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0x18); - /** - * mapping between the ARB_CREDIT_WEIGHT registers and actual - * client numbers (WEIGHT_0 does not actually have to represent - * client 0) - * PRI4 | PRI3 | PRI2 | PRI1 | PRI0 - * cos1-001 cos0-000 dbg1-100 dbg0-011 MCP-010 - */ + /* + * mapping between the ARB_CREDIT_WEIGHT registers and actual + * client numbers (WEIGHT_0 does not actually have to represent + * client 0) + * PRI4 | PRI3 | PRI2 | PRI1 | PRI0 + * cos1-001 cos0-000 dbg1-100 dbg0-011 MCP-010 + */ REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0x111A); REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, @@ -298,14 +293,14 @@ void bnx2x_ets_bw_limit_common(const struct link_params *params) /* Defines the number of consecutive slots for the strict priority */ REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0); - /** - * Bitmap of 5bits length. Each bit specifies whether the entry behaves - * as strict. Bits 0,1,2 - debug and management entries, 3 - COS0 - * entry, 4 - COS1 entry. - * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT - * bit4 bit3 bit2 bit1 bit0 - * MCP and debug are strict - */ + /* + * Bitmap of 5bits length. Each bit specifies whether the entry behaves + * as strict. Bits 0,1,2 - debug and management entries, 3 - COS0 + * entry, 4 - COS1 entry. + * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT + * bit4 bit3 bit2 bit1 bit0 + * MCP and debug are strict + */ REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7); /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter.*/ @@ -329,8 +324,7 @@ void bnx2x_ets_bw_limit(const struct link_params *params, const u32 cos0_bw, if ((0 == total_bw) || (0 == cos0_bw) || (0 == cos1_bw)) { - DP(NETIF_MSG_LINK, - "bnx2x_ets_bw_limit: Total BW can't be zero\n"); + DP(NETIF_MSG_LINK, "Total BW can't be zero\n"); return; } @@ -355,7 +349,7 @@ u8 bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos) u32 val = 0; DP(NETIF_MSG_LINK, "ETS enabled strict configuration\n"); - /** + /* * Bitmap of 5bits length. Each bit specifies whether the entry behaves * as strict. Bits 0,1,2 - debug and management entries, * 3 - COS0 entry, 4 - COS1 entry. @@ -364,7 +358,7 @@ u8 bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos) * MCP and debug are strict */ REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x1F); - /** + /* * For strict priority entries defines the number of consecutive slots * for the highest priority. */ @@ -377,14 +371,14 @@ u8 bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos) /* Defines the number of consecutive slots for the strict priority */ REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, strict_cos); - /** - * mapping between entry priority to client number (0,1,2 -debug and - * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST) - * 3bits client num. - * PRI4 | PRI3 | PRI2 | PRI1 | PRI0 - * dbg0-010 dbg1-001 cos1-100 cos0-011 MCP-000 - * dbg0-010 dbg1-001 cos0-011 cos1-100 MCP-000 - */ + /* + * mapping between entry priority to client number (0,1,2 -debug and + * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST) + * 3bits client num. + * PRI4 | PRI3 | PRI2 | PRI1 | PRI0 + * dbg0-010 dbg1-001 cos1-100 cos0-011 MCP-000 + * dbg0-010 dbg1-001 cos0-011 cos1-100 MCP-000 + */ val = (0 == strict_cos) ? 0x2318 : 0x22E0; REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, val); @@ -471,7 +465,7 @@ void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars, /* MAC/PBF section */ /******************************************************************/ static void bnx2x_emac_init(struct link_params *params, - struct link_vars *vars) + struct link_vars *vars) { /* reset and unreset the emac core */ struct bnx2x *bp = params->bp; @@ -481,10 +475,10 @@ static void bnx2x_emac_init(struct link_params *params, u16 timeout; REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, - (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port)); + (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port)); udelay(5); REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, - (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port)); + (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port)); /* init emac - use read-modify-write */ /* self clear reset */ @@ -515,7 +509,7 @@ static void bnx2x_emac_init(struct link_params *params, } static u8 bnx2x_emac_enable(struct link_params *params, - struct link_vars *vars, u8 lb) + struct link_vars *vars, u8 lb) { struct bnx2x *bp = params->bp; u8 port = params->port; @@ -527,55 +521,33 @@ static u8 bnx2x_emac_enable(struct link_params *params, /* enable emac and not bmac */ REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1); - /* for paladium */ - if (CHIP_REV_IS_EMUL(bp)) { - /* Use lane 1 (of lanes 0-3) */ - REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1); - REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + - port*4, 1); - } - /* for fpga */ - else - - if (CHIP_REV_IS_FPGA(bp)) { - /* Use lane 1 (of lanes 0-3) */ - DP(NETIF_MSG_LINK, "bnx2x_emac_enable: Setting FPGA\n"); - - REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1); - REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, - 0); - } else /* ASIC */ if (vars->phy_flags & PHY_XGXS_FLAG) { u32 ser_lane = ((params->lane_config & - PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> - PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); DP(NETIF_MSG_LINK, "XGXS\n"); /* select the master lanes (out of 0-3) */ - REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + - port*4, ser_lane); + REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, ser_lane); /* select XGXS */ - REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + - port*4, 1); + REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1); } else { /* SerDes */ DP(NETIF_MSG_LINK, "SerDes\n"); /* select SerDes */ - REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + - port*4, 0); + REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0); } bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE, - EMAC_RX_MODE_RESET); + EMAC_RX_MODE_RESET); bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE, - EMAC_TX_MODE_RESET); + EMAC_TX_MODE_RESET); if (CHIP_REV_IS_SLOW(bp)) { /* config GMII mode */ val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE); - EMAC_WR(bp, EMAC_REG_EMAC_MODE, - (val | EMAC_MODE_PORT_GMII)); + EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_PORT_GMII)); } else { /* ASIC */ /* pause enable/disable */ bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE, @@ -605,14 +577,14 @@ static u8 bnx2x_emac_enable(struct link_params *params, val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE); val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS; - /** - * Setting this bit causes MAC control frames (except for pause - * frames) to be passed on for processing. This setting has no - * affect on the operation of the pause frames. This bit effects - * all packets regardless of RX Parser packet sorting logic. - * Turn the PFC off to make sure we are in Xon state before - * enabling it. - */ + /* + * Setting this bit causes MAC control frames (except for pause + * frames) to be passed on for processing. This setting has no + * affect on the operation of the pause frames. This bit effects + * all packets regardless of RX Parser packet sorting logic. + * Turn the PFC off to make sure we are in Xon state before + * enabling it. + */ EMAC_WR(bp, EMAC_REG_RX_PFC_MODE, 0); if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) { DP(NETIF_MSG_LINK, "PFC is enabled\n"); @@ -666,16 +638,7 @@ static u8 bnx2x_emac_enable(struct link_params *params, REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val); REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1); - if (CHIP_REV_IS_EMUL(bp)) { - /* take the BigMac out of reset */ - REG_WR(bp, - GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, - (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); - - /* enable access for bmac registers */ - REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1); - } else - REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0); + REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0); vars->mac_type = MAC_TYPE_EMAC; return 0; @@ -731,8 +694,7 @@ static void bnx2x_update_pfc_bmac2(struct link_params *params, val |= (1<<5); wb_data[0] = val; wb_data[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_CONTROL, - wb_data, 2); + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_CONTROL, wb_data, 2); udelay(30); /* Tx control */ @@ -768,12 +730,12 @@ static void bnx2x_update_pfc_bmac2(struct link_params *params, REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL, wb_data, 2); - /** - * Set Time (based unit is 512 bit time) between automatic - * re-sending of PP packets amd enable automatic re-send of - * Per-Priroity Packet as long as pp_gen is asserted and - * pp_disable is low. - */ + /* + * Set Time (based unit is 512 bit time) between automatic + * re-sending of PP packets amd enable automatic re-send of + * Per-Priroity Packet as long as pp_gen is asserted and + * pp_disable is low. + */ val = 0x8000; if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) val |= (1<<16); /* enable automatic re-send */ @@ -781,7 +743,7 @@ static void bnx2x_update_pfc_bmac2(struct link_params *params, wb_data[0] = val; wb_data[1] = 0; REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_PAUSE_CONTROL, - wb_data, 2); + wb_data, 2); /* mac control */ val = 0x3; /* Enable RX and TX */ @@ -795,8 +757,7 @@ static void bnx2x_update_pfc_bmac2(struct link_params *params, wb_data[0] = val; wb_data[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, - wb_data, 2); + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, wb_data, 2); } static void bnx2x_update_pfc_brb(struct link_params *params, @@ -825,17 +786,25 @@ static void bnx2x_update_pfc_brb(struct link_params *params, full_xon_th = PFC_BRB_MAC_FULL_XON_THRESHOLD_NON_PAUSEABLE; } - /* The number of free blocks below which the pause signal to class 0 - of MAC #n is asserted. n=0,1 */ + /* + * The number of free blocks below which the pause signal to class 0 + * of MAC #n is asserted. n=0,1 + */ REG_WR(bp, BRB1_REG_PAUSE_0_XOFF_THRESHOLD_0 , pause_xoff_th); - /* The number of free blocks above which the pause signal to class 0 - of MAC #n is de-asserted. n=0,1 */ + /* + * The number of free blocks above which the pause signal to class 0 + * of MAC #n is de-asserted. n=0,1 + */ REG_WR(bp, BRB1_REG_PAUSE_0_XON_THRESHOLD_0 , pause_xon_th); - /* The number of free blocks below which the full signal to class 0 - of MAC #n is asserted. n=0,1 */ + /* + * The number of free blocks below which the full signal to class 0 + * of MAC #n is asserted. n=0,1 + */ REG_WR(bp, BRB1_REG_FULL_0_XOFF_THRESHOLD_0 , full_xoff_th); - /* The number of free blocks above which the full signal to class 0 - of MAC #n is de-asserted. n=0,1 */ + /* + * The number of free blocks above which the full signal to class 0 + * of MAC #n is de-asserted. n=0,1 + */ REG_WR(bp, BRB1_REG_FULL_0_XON_THRESHOLD_0 , full_xon_th); if (set_pfc && pfc_params) { @@ -859,25 +828,25 @@ static void bnx2x_update_pfc_brb(struct link_params *params, full_xon_th = PFC_BRB_MAC_FULL_XON_THRESHOLD_NON_PAUSEABLE; } - /** + /* * The number of free blocks below which the pause signal to * class 1 of MAC #n is asserted. n=0,1 - **/ + */ REG_WR(bp, BRB1_REG_PAUSE_1_XOFF_THRESHOLD_0, pause_xoff_th); - /** + /* * The number of free blocks above which the pause signal to * class 1 of MAC #n is de-asserted. n=0,1 - **/ + */ REG_WR(bp, BRB1_REG_PAUSE_1_XON_THRESHOLD_0, pause_xon_th); - /** + /* * The number of free blocks below which the full signal to * class 1 of MAC #n is asserted. n=0,1 - **/ + */ REG_WR(bp, BRB1_REG_FULL_1_XOFF_THRESHOLD_0, full_xoff_th); - /** + /* * The number of free blocks above which the full signal to * class 1 of MAC #n is de-asserted. n=0,1 - **/ + */ REG_WR(bp, BRB1_REG_FULL_1_XON_THRESHOLD_0, full_xon_th); } } @@ -896,7 +865,7 @@ static void bnx2x_update_pfc_nig(struct link_params *params, FEATURE_CONFIG_PFC_ENABLED; DP(NETIF_MSG_LINK, "updating pfc nig parameters\n"); - /** + /* * When NIG_LLH0_XCM_MASK_REG_LLHX_XCM_MASK_BCN bit is set * MAC control frames (that are not pause packets) * will be forwarded to the XCM. @@ -904,7 +873,7 @@ static void bnx2x_update_pfc_nig(struct link_params *params, xcm_mask = REG_RD(bp, port ? NIG_REG_LLH1_XCM_MASK : NIG_REG_LLH0_XCM_MASK); - /** + /* * nig params will override non PFC params, since it's possible to * do transition from PFC to SAFC */ @@ -994,7 +963,7 @@ void bnx2x_update_pfc(struct link_params *params, struct link_vars *vars, struct bnx2x_nig_brb_pfc_port_params *pfc_params) { - /** + /* * The PFC and pause are orthogonal to one another, meaning when * PFC is enabled, the pause are disabled, and when PFC is * disabled, pause are set according to the pause result. @@ -1035,7 +1004,7 @@ void bnx2x_update_pfc(struct link_params *params, static u8 bnx2x_bmac1_enable(struct link_params *params, struct link_vars *vars, - u8 is_lb) + u8 is_lb) { struct bnx2x *bp = params->bp; u8 port = params->port; @@ -1049,9 +1018,8 @@ static u8 bnx2x_bmac1_enable(struct link_params *params, /* XGXS control */ wb_data[0] = 0x3c; wb_data[1] = 0; - REG_WR_DMAE(bp, bmac_addr + - BIGMAC_REGISTER_BMAC_XGXS_CONTROL, - wb_data, 2); + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_XGXS_CONTROL, + wb_data, 2); /* tx MAC SA */ wb_data[0] = ((params->mac_addr[2] << 24) | @@ -1060,8 +1028,7 @@ static u8 bnx2x_bmac1_enable(struct link_params *params, params->mac_addr[5]); wb_data[1] = ((params->mac_addr[0] << 8) | params->mac_addr[1]); - REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR, - wb_data, 2); + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR, wb_data, 2); /* mac control */ val = 0x3; @@ -1071,43 +1038,30 @@ static u8 bnx2x_bmac1_enable(struct link_params *params, } wb_data[0] = val; wb_data[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, - wb_data, 2); + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, wb_data, 2); /* set rx mtu */ wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; wb_data[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE, - wb_data, 2); + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE, wb_data, 2); bnx2x_update_pfc_bmac1(params, vars); /* set tx mtu */ wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; wb_data[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE, - wb_data, 2); + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE, wb_data, 2); /* set cnt max size */ wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; wb_data[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE, - wb_data, 2); + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE, wb_data, 2); /* configure safc */ wb_data[0] = 0x1000200; wb_data[1] = 0; REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS, wb_data, 2); - /* fix for emulation */ - if (CHIP_REV_IS_EMUL(bp)) { - wb_data[0] = 0xf000; - wb_data[1] = 0; - REG_WR_DMAE(bp, - bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD, - wb_data, 2); - } - return 0; } @@ -1126,16 +1080,14 @@ static u8 bnx2x_bmac2_enable(struct link_params *params, wb_data[0] = 0; wb_data[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, - wb_data, 2); + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, wb_data, 2); udelay(30); /* XGXS control: Reset phy HW, MDIO registers, PHY PLL and BMAC */ wb_data[0] = 0x3c; wb_data[1] = 0; - REG_WR_DMAE(bp, bmac_addr + - BIGMAC2_REGISTER_BMAC_XGXS_CONTROL, - wb_data, 2); + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_XGXS_CONTROL, + wb_data, 2); udelay(30); @@ -1147,7 +1099,7 @@ static u8 bnx2x_bmac2_enable(struct link_params *params, wb_data[1] = ((params->mac_addr[0] << 8) | params->mac_addr[1]); REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_SOURCE_ADDR, - wb_data, 2); + wb_data, 2); udelay(30); @@ -1155,27 +1107,24 @@ static u8 bnx2x_bmac2_enable(struct link_params *params, wb_data[0] = 0x1000200; wb_data[1] = 0; REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_LLFC_MSG_FLDS, - wb_data, 2); + wb_data, 2); udelay(30); /* set rx mtu */ wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; wb_data[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_MAX_SIZE, - wb_data, 2); + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_MAX_SIZE, wb_data, 2); udelay(30); /* set tx mtu */ wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; wb_data[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_MAX_SIZE, - wb_data, 2); + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_MAX_SIZE, wb_data, 2); udelay(30); /* set cnt max size */ wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD - 2; wb_data[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_CNT_MAX_SIZE, - wb_data, 2); + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_CNT_MAX_SIZE, wb_data, 2); udelay(30); bnx2x_update_pfc_bmac2(params, vars, is_lb); @@ -1191,11 +1140,11 @@ static u8 bnx2x_bmac_enable(struct link_params *params, u32 val; /* reset and unreset the BigMac */ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, - (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); msleep(1); REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, - (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); /* enable access for bmac registers */ REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1); @@ -1230,15 +1179,14 @@ static void bnx2x_update_mng(struct link_params *params, u32 link_status) struct bnx2x *bp = params->bp; REG_WR(bp, params->shmem_base + - offsetof(struct shmem_region, - port_mb[params->port].link_status), - link_status); + offsetof(struct shmem_region, + port_mb[params->port].link_status), link_status); } static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port) { u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM : - NIG_REG_INGRESS_BMAC0_MEM; + NIG_REG_INGRESS_BMAC0_MEM; u32 wb_data[2]; u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4); @@ -1250,12 +1198,12 @@ static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port) if (CHIP_IS_E2(bp)) { /* Clear Rx Enable bit in BMAC_CONTROL register */ REG_RD_DMAE(bp, bmac_addr + - BIGMAC2_REGISTER_BMAC_CONTROL, - wb_data, 2); + BIGMAC2_REGISTER_BMAC_CONTROL, + wb_data, 2); wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE; REG_WR_DMAE(bp, bmac_addr + - BIGMAC2_REGISTER_BMAC_CONTROL, - wb_data, 2); + BIGMAC2_REGISTER_BMAC_CONTROL, + wb_data, 2); } else { /* Clear Rx Enable bit in BMAC_CONTROL register */ REG_RD_DMAE(bp, bmac_addr + @@ -1271,7 +1219,7 @@ static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port) } static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl, - u32 line_speed) + u32 line_speed) { struct bnx2x *bp = params->bp; u8 port = params->port; @@ -1308,7 +1256,7 @@ static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl, /* update threshold */ REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0); /* update init credit */ - init_crd = 778; /* (800-18-4) */ + init_crd = 778; /* (800-18-4) */ } else { u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE + @@ -1353,6 +1301,23 @@ static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl, return 0; } +/* + * get_emac_base + * + * @param cb + * @param mdc_mdio_access + * @param port + * + * @return u32 + * + * This function selects the MDC/MDIO access (through emac0 or + * emac1) depend on the mdc_mdio_access, port, port swapped. Each + * phy has a default access mode, which could also be overridden + * by nvram configuration. This parameter, whether this is the + * default phy configuration, or the nvram overrun + * configuration, is passed here as mdc_mdio_access and selects + * the emac_base for the CL45 read/writes operations + */ static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 mdc_mdio_access, u8 port) { @@ -1385,13 +1350,16 @@ static u32 bnx2x_get_emac_base(struct bnx2x *bp, } -u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy, - u8 devad, u16 reg, u16 val) +/******************************************************************/ +/* CL45 access functions */ +/******************************************************************/ +static u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy, + u8 devad, u16 reg, u16 val) { u32 tmp, saved_mode; u8 i, rc = 0; - - /* set clause 45 mode, slow down the MDIO clock to 2.5MHz + /* + * Set clause 45 mode, slow down the MDIO clock to 2.5MHz * (a value of 49==0x31) and make sure that the AUTO poll is off */ @@ -1414,8 +1382,7 @@ u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy, for (i = 0; i < 50; i++) { udelay(10); - tmp = REG_RD(bp, phy->mdio_ctrl + - EMAC_REG_EMAC_MDIO_COMM); + tmp = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM); if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) { udelay(5); break; @@ -1423,6 +1390,7 @@ u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy, } if (tmp & EMAC_MDIO_COMM_START_BUSY) { DP(NETIF_MSG_LINK, "write phy register failed\n"); + netdev_err(bp->dev, "MDC/MDIO access timeout\n"); rc = -EFAULT; } else { /* data */ @@ -1435,7 +1403,7 @@ u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy, udelay(10); tmp = REG_RD(bp, phy->mdio_ctrl + - EMAC_REG_EMAC_MDIO_COMM); + EMAC_REG_EMAC_MDIO_COMM); if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) { udelay(5); break; @@ -1443,6 +1411,7 @@ u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy, } if (tmp & EMAC_MDIO_COMM_START_BUSY) { DP(NETIF_MSG_LINK, "write phy register failed\n"); + netdev_err(bp->dev, "MDC/MDIO access timeout\n"); rc = -EFAULT; } } @@ -1453,20 +1422,20 @@ u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy, return rc; } -u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy, - u8 devad, u16 reg, u16 *ret_val) +static u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy, + u8 devad, u16 reg, u16 *ret_val) { u32 val, saved_mode; u16 i; u8 rc = 0; - - /* set clause 45 mode, slow down the MDIO clock to 2.5MHz + /* + * Set clause 45 mode, slow down the MDIO clock to 2.5MHz * (a value of 49==0x31) and make sure that the AUTO poll is off */ saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); val = saved_mode & ~((EMAC_MDIO_MODE_AUTO_POLL | - EMAC_MDIO_MODE_CLOCK_CNT)); + EMAC_MDIO_MODE_CLOCK_CNT)); val |= (EMAC_MDIO_MODE_CLAUSE_45 | (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT)); REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val); @@ -1490,7 +1459,7 @@ u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy, } if (val & EMAC_MDIO_COMM_START_BUSY) { DP(NETIF_MSG_LINK, "read phy register failed\n"); - + netdev_err(bp->dev, "MDC/MDIO access timeout\n"); *ret_val = 0; rc = -EFAULT; @@ -1505,7 +1474,7 @@ u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy, udelay(10); val = REG_RD(bp, phy->mdio_ctrl + - EMAC_REG_EMAC_MDIO_COMM); + EMAC_REG_EMAC_MDIO_COMM); if (!(val & EMAC_MDIO_COMM_START_BUSY)) { *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA); break; @@ -1513,7 +1482,7 @@ u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy, } if (val & EMAC_MDIO_COMM_START_BUSY) { DP(NETIF_MSG_LINK, "read phy register failed\n"); - + netdev_err(bp->dev, "MDC/MDIO access timeout\n"); *ret_val = 0; rc = -EFAULT; } @@ -1529,7 +1498,7 @@ u8 bnx2x_phy_read(struct link_params *params, u8 phy_addr, u8 devad, u16 reg, u16 *ret_val) { u8 phy_index; - /** + /* * Probe for the phy according to the given phy_addr, and execute * the read request on it */ @@ -1547,7 +1516,7 @@ u8 bnx2x_phy_write(struct link_params *params, u8 phy_addr, u8 devad, u16 reg, u16 val) { u8 phy_index; - /** + /* * Probe for the phy according to the given phy_addr, and execute * the write request on it */ @@ -1576,16 +1545,15 @@ static void bnx2x_set_aer_mmd_xgxs(struct link_params *params, aer_val = 0x3800 + offset - 1; else aer_val = 0x3800 + offset; - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_AER_BLOCK, - MDIO_AER_BLOCK_AER_REG, aer_val); + CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK, + MDIO_AER_BLOCK_AER_REG, aer_val); } static void bnx2x_set_aer_mmd_serdes(struct bnx2x *bp, struct bnx2x_phy *phy) { - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_AER_BLOCK, - MDIO_AER_BLOCK_AER_REG, 0x3800); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_AER_BLOCK, + MDIO_AER_BLOCK_AER_REG, 0x3800); } /******************************************************************/ @@ -1621,9 +1589,8 @@ static void bnx2x_serdes_deassert(struct bnx2x *bp, u8 port) bnx2x_set_serdes_access(bp, port); - REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD + - port*0x10, - DEFAULT_PHY_DEV_ADDR); + REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD + port*0x10, + DEFAULT_PHY_DEV_ADDR); } static void bnx2x_xgxs_deassert(struct link_params *params) @@ -1641,23 +1608,22 @@ static void bnx2x_xgxs_deassert(struct link_params *params) udelay(500); REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val); - REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST + - port*0x18, 0); + REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST + port*0x18, 0); REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, - params->phy[INT_PHY].def_md_devad); + params->phy[INT_PHY].def_md_devad); } void bnx2x_link_status_update(struct link_params *params, - struct link_vars *vars) + struct link_vars *vars) { struct bnx2x *bp = params->bp; u8 link_10g; u8 port = params->port; vars->link_status = REG_RD(bp, params->shmem_base + - offsetof(struct shmem_region, - port_mb[port].link_status)); + offsetof(struct shmem_region, + port_mb[port].link_status)); vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP); @@ -1667,7 +1633,7 @@ void bnx2x_link_status_update(struct link_params *params, vars->phy_link_up = 1; vars->duplex = DUPLEX_FULL; switch (vars->link_status & - LINK_STATUS_SPEED_AND_DUPLEX_MASK) { + LINK_STATUS_SPEED_AND_DUPLEX_MASK) { case LINK_10THD: vars->duplex = DUPLEX_HALF; /* fall thru */ @@ -1779,20 +1745,20 @@ static void bnx2x_set_master_ln(struct link_params *params, { struct bnx2x *bp = params->bp; u16 new_master_ln, ser_lane; - ser_lane = ((params->lane_config & + ser_lane = ((params->lane_config & PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> - PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); /* set the master_ln for AN */ - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_XGXS_BLOCK2, - MDIO_XGXS_BLOCK2_TEST_MODE_LANE, - &new_master_ln); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_XGXS_BLOCK2, + MDIO_XGXS_BLOCK2_TEST_MODE_LANE, + &new_master_ln); - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_XGXS_BLOCK2 , - MDIO_XGXS_BLOCK2_TEST_MODE_LANE, - (new_master_ln | ser_lane)); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_XGXS_BLOCK2 , + MDIO_XGXS_BLOCK2_TEST_MODE_LANE, + (new_master_ln | ser_lane)); } static u8 bnx2x_reset_unicore(struct link_params *params, @@ -1802,17 +1768,16 @@ static u8 bnx2x_reset_unicore(struct link_params *params, struct bnx2x *bp = params->bp; u16 mii_control; u16 i; - - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control); /* reset the unicore */ - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_MII_CONTROL, - (mii_control | - MDIO_COMBO_IEEO_MII_CONTROL_RESET)); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + (mii_control | + MDIO_COMBO_IEEO_MII_CONTROL_RESET)); if (set_serdes) bnx2x_set_serdes_access(bp, params->port); @@ -1821,10 +1786,10 @@ static u8 bnx2x_reset_unicore(struct link_params *params, udelay(5); /* the reset erased the previous bank value */ - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_MII_CONTROL, - &mii_control); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + &mii_control); if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) { udelay(5); @@ -1832,6 +1797,9 @@ static u8 bnx2x_reset_unicore(struct link_params *params, } } + netdev_err(bp->dev, "Warning: PHY was not initialized," + " Port %d\n", + params->port); DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n"); return -EINVAL; @@ -1841,43 +1809,45 @@ static void bnx2x_set_swap_lanes(struct link_params *params, struct bnx2x_phy *phy) { struct bnx2x *bp = params->bp; - /* Each two bits represents a lane number: - No swap is 0123 => 0x1b no need to enable the swap */ + /* + * Each two bits represents a lane number: + * No swap is 0123 => 0x1b no need to enable the swap + */ u16 ser_lane, rx_lane_swap, tx_lane_swap; ser_lane = ((params->lane_config & - PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> - PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); rx_lane_swap = ((params->lane_config & - PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >> - PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT); + PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT); tx_lane_swap = ((params->lane_config & - PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >> - PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT); + PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT); if (rx_lane_swap != 0x1b) { - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_XGXS_BLOCK2, - MDIO_XGXS_BLOCK2_RX_LN_SWAP, - (rx_lane_swap | - MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE | - MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE)); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_XGXS_BLOCK2, + MDIO_XGXS_BLOCK2_RX_LN_SWAP, + (rx_lane_swap | + MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE | + MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE)); } else { - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_XGXS_BLOCK2, - MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_XGXS_BLOCK2, + MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0); } if (tx_lane_swap != 0x1b) { - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_XGXS_BLOCK2, - MDIO_XGXS_BLOCK2_TX_LN_SWAP, - (tx_lane_swap | - MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE)); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_XGXS_BLOCK2, + MDIO_XGXS_BLOCK2_TX_LN_SWAP, + (tx_lane_swap | + MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE)); } else { - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_XGXS_BLOCK2, - MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_XGXS_BLOCK2, + MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0); } } @@ -1886,66 +1856,66 @@ static void bnx2x_set_parallel_detection(struct bnx2x_phy *phy, { struct bnx2x *bp = params->bp; u16 control2; - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_SERDES_DIGITAL, - MDIO_SERDES_DIGITAL_A_1000X_CONTROL2, - &control2); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_CONTROL2, + &control2); if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN; else control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN; DP(NETIF_MSG_LINK, "phy->speed_cap_mask = 0x%x, control2 = 0x%x\n", phy->speed_cap_mask, control2); - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_SERDES_DIGITAL, - MDIO_SERDES_DIGITAL_A_1000X_CONTROL2, - control2); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_CONTROL2, + control2); if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) && (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) { DP(NETIF_MSG_LINK, "XGXS\n"); - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_10G_PARALLEL_DETECT, - MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK, - MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_10G_PARALLEL_DETECT, + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK, + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT); - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_10G_PARALLEL_DETECT, - MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL, - &control2); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_10G_PARALLEL_DETECT, + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL, + &control2); control2 |= MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN; - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_10G_PARALLEL_DETECT, - MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL, - control2); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_10G_PARALLEL_DETECT, + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL, + control2); /* Disable parallel detection of HiG */ - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_XGXS_BLOCK2, - MDIO_XGXS_BLOCK2_UNICORE_MODE_10G, - MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS | - MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_XGXS_BLOCK2, + MDIO_XGXS_BLOCK2_UNICORE_MODE_10G, + MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS | + MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS); } } static void bnx2x_set_autoneg(struct bnx2x_phy *phy, struct link_params *params, - struct link_vars *vars, - u8 enable_cl73) + struct link_vars *vars, + u8 enable_cl73) { struct bnx2x *bp = params->bp; u16 reg_val; /* CL37 Autoneg */ - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_MII_CONTROL, ®_val); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, ®_val); /* CL37 Autoneg Enabled */ if (vars->line_speed == SPEED_AUTO_NEG) @@ -1954,15 +1924,15 @@ static void bnx2x_set_autoneg(struct bnx2x_phy *phy, reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN); - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_MII_CONTROL, reg_val); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, reg_val); /* Enable/Disable Autodetection */ - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_SERDES_DIGITAL, - MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, ®_val); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, ®_val); reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN | MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT); reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE; @@ -1971,14 +1941,14 @@ static void bnx2x_set_autoneg(struct bnx2x_phy *phy, else reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET; - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_SERDES_DIGITAL, - MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val); /* Enable TetonII and BAM autoneg */ - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_BAM_NEXT_PAGE, - MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL, + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_BAM_NEXT_PAGE, + MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL, ®_val); if (vars->line_speed == SPEED_AUTO_NEG) { /* Enable BAM aneg Mode and TetonII aneg Mode */ @@ -1989,20 +1959,20 @@ static void bnx2x_set_autoneg(struct bnx2x_phy *phy, reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE | MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN); } - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_BAM_NEXT_PAGE, - MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL, - reg_val); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_BAM_NEXT_PAGE, + MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL, + reg_val); if (enable_cl73) { /* Enable Cl73 FSM status bits */ - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_CL73_USERB0, - MDIO_CL73_USERB0_CL73_UCTRL, - 0xe); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_USERB0, + MDIO_CL73_USERB0_CL73_UCTRL, + 0xe); /* Enable BAM Station Manager*/ - CL45_WR_OVER_CL22(bp, phy, + CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_CL73_USERB0, MDIO_CL73_USERB0_CL73_BAM_CTRL1, MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN | @@ -2010,10 +1980,10 @@ static void bnx2x_set_autoneg(struct bnx2x_phy *phy, MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN); /* Advertise CL73 link speeds */ - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_CL73_IEEEB1, - MDIO_CL73_IEEEB1_AN_ADV2, - ®_val); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB1, + MDIO_CL73_IEEEB1_AN_ADV2, + ®_val); if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4; @@ -2021,10 +1991,10 @@ static void bnx2x_set_autoneg(struct bnx2x_phy *phy, PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX; - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_CL73_IEEEB1, - MDIO_CL73_IEEEB1_AN_ADV2, - reg_val); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB1, + MDIO_CL73_IEEEB1_AN_ADV2, + reg_val); /* CL73 Autoneg Enabled */ reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN; @@ -2032,37 +2002,39 @@ static void bnx2x_set_autoneg(struct bnx2x_phy *phy, } else /* CL73 Autoneg Disabled */ reg_val = 0; - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_CL73_IEEEB0, - MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val); } /* program SerDes, forced speed */ static void bnx2x_program_serdes(struct bnx2x_phy *phy, struct link_params *params, - struct link_vars *vars) + struct link_vars *vars) { struct bnx2x *bp = params->bp; u16 reg_val; /* program duplex, disable autoneg and sgmii*/ - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_MII_CONTROL, ®_val); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, ®_val); reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX | MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK); if (phy->req_duplex == DUPLEX_FULL) reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX; - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_MII_CONTROL, reg_val); - - /* program speed - - needed only if the speed is greater than 1G (2.5G or 10G) */ - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_SERDES_DIGITAL, - MDIO_SERDES_DIGITAL_MISC1, ®_val); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, reg_val); + + /* + * program speed + * - needed only if the speed is greater than 1G (2.5G or 10G) + */ + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_MISC1, ®_val); /* clearing the speed value before setting the right speed */ DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val); @@ -2083,9 +2055,9 @@ static void bnx2x_program_serdes(struct bnx2x_phy *phy, MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G; } - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_SERDES_DIGITAL, - MDIO_SERDES_DIGITAL_MISC1, reg_val); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_MISC1, reg_val); } @@ -2102,13 +2074,13 @@ static void bnx2x_set_brcm_cl37_advertisment(struct bnx2x_phy *phy, val |= MDIO_OVER_1G_UP1_2_5G; if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) val |= MDIO_OVER_1G_UP1_10G; - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_OVER_1G, - MDIO_OVER_1G_UP1, val); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_OVER_1G, + MDIO_OVER_1G_UP1, val); - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_OVER_1G, - MDIO_OVER_1G_UP3, 0x400); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_OVER_1G, + MDIO_OVER_1G_UP3, 0x400); } static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy, @@ -2116,22 +2088,21 @@ static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy, { struct bnx2x *bp = params->bp; *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX; - /* resolve pause mode and advertisement - * Please refer to Table 28B-3 of the 802.3ab-1999 spec */ + /* + * Resolve pause mode and advertisement. + * Please refer to Table 28B-3 of the 802.3ab-1999 spec + */ switch (phy->req_flow_ctrl) { case BNX2X_FLOW_CTRL_AUTO: - if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) { - *ieee_fc |= - MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; - } else { + if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) + *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; + else *ieee_fc |= - MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; - } + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; break; case BNX2X_FLOW_CTRL_TX: - *ieee_fc |= - MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; + *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; break; case BNX2X_FLOW_CTRL_RX: @@ -2149,23 +2120,23 @@ static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy, static void bnx2x_set_ieee_aneg_advertisment(struct bnx2x_phy *phy, struct link_params *params, - u16 ieee_fc) + u16 ieee_fc) { struct bnx2x *bp = params->bp; u16 val; /* for AN, we are always publishing full duplex */ - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc); - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_CL73_IEEEB1, - MDIO_CL73_IEEEB1_AN_ADV1, &val); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB1, + MDIO_CL73_IEEEB1_AN_ADV1, &val); val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH; val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK); - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_CL73_IEEEB1, - MDIO_CL73_IEEEB1_AN_ADV1, val); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB1, + MDIO_CL73_IEEEB1_AN_ADV1, val); } static void bnx2x_restart_autoneg(struct bnx2x_phy *phy, @@ -2179,67 +2150,67 @@ static void bnx2x_restart_autoneg(struct bnx2x_phy *phy, /* Enable and restart BAM/CL37 aneg */ if (enable_cl73) { - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_CL73_IEEEB0, - MDIO_CL73_IEEEB0_CL73_AN_CONTROL, - &mii_control); - - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_CL73_IEEEB0, - MDIO_CL73_IEEEB0_CL73_AN_CONTROL, - (mii_control | - MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN | - MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN)); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + &mii_control); + + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + (mii_control | + MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN | + MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN)); } else { - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_MII_CONTROL, - &mii_control); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + &mii_control); DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg mii_control before = 0x%x\n", mii_control); - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_MII_CONTROL, - (mii_control | - MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | - MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN)); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + (mii_control | + MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | + MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN)); } } static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy, struct link_params *params, - struct link_vars *vars) + struct link_vars *vars) { struct bnx2x *bp = params->bp; u16 control1; /* in SGMII mode, the unicore is always slave */ - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_SERDES_DIGITAL, - MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, - &control1); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, + &control1); control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT; /* set sgmii mode (and not fiber) */ control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE | MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET | MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE); - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_SERDES_DIGITAL, - MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, - control1); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, + control1); /* if forced speed */ if (!(vars->line_speed == SPEED_AUTO_NEG)) { /* set speed, disable autoneg */ u16 mii_control; - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_MII_CONTROL, - &mii_control); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + &mii_control); mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK| MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX); @@ -2267,10 +2238,10 @@ static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy, if (phy->req_duplex == DUPLEX_FULL) mii_control |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX; - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_MII_CONTROL, - mii_control); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + mii_control); } else { /* AN mode */ /* enable and restart AN */ @@ -2285,19 +2256,19 @@ static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy, static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result) { /* LD LP */ - switch (pause_result) { /* ASYM P ASYM P */ - case 0xb: /* 1 0 1 1 */ + switch (pause_result) { /* ASYM P ASYM P */ + case 0xb: /* 1 0 1 1 */ vars->flow_ctrl = BNX2X_FLOW_CTRL_TX; break; - case 0xe: /* 1 1 1 0 */ + case 0xe: /* 1 1 1 0 */ vars->flow_ctrl = BNX2X_FLOW_CTRL_RX; break; - case 0x5: /* 0 1 0 1 */ - case 0x7: /* 0 1 1 1 */ - case 0xd: /* 1 1 0 1 */ - case 0xf: /* 1 1 1 1 */ + case 0x5: /* 0 1 0 1 */ + case 0x7: /* 0 1 1 1 */ + case 0xd: /* 1 1 0 1 */ + case 0xf: /* 1 1 1 1 */ vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH; break; @@ -2317,24 +2288,24 @@ static u8 bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy, u16 pd_10g, status2_1000x; if (phy->req_line_speed != SPEED_AUTO_NEG) return 0; - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_SERDES_DIGITAL, - MDIO_SERDES_DIGITAL_A_1000X_STATUS2, - &status2_1000x); - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_SERDES_DIGITAL, - MDIO_SERDES_DIGITAL_A_1000X_STATUS2, - &status2_1000x); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_STATUS2, + &status2_1000x); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_STATUS2, + &status2_1000x); if (status2_1000x & MDIO_SERDES_DIGITAL_A_1000X_STATUS2_AN_DISABLED) { DP(NETIF_MSG_LINK, "1G parallel detect link on port %d\n", params->port); return 1; } - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_10G_PARALLEL_DETECT, - MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS, - &pd_10g); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_10G_PARALLEL_DETECT, + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS, + &pd_10g); if (pd_10g & MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS_PD_LINK) { DP(NETIF_MSG_LINK, "10G parallel detect link on port %d\n", @@ -2373,14 +2344,14 @@ static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy, (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) { - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_CL73_IEEEB1, - MDIO_CL73_IEEEB1_AN_ADV1, - &ld_pause); - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_CL73_IEEEB1, - MDIO_CL73_IEEEB1_AN_LP_ADV1, - &lp_pause); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB1, + MDIO_CL73_IEEEB1_AN_ADV1, + &ld_pause); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB1, + MDIO_CL73_IEEEB1_AN_LP_ADV1, + &lp_pause); pause_result = (ld_pause & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK) >> 8; @@ -2390,18 +2361,18 @@ static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy, DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n", pause_result); } else { - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_AUTO_NEG_ADV, - &ld_pause); - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1, - &lp_pause); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_AUTO_NEG_ADV, + &ld_pause); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1, + &lp_pause); pause_result = (ld_pause & MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5; pause_result |= (lp_pause & - MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7; + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7; DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n", pause_result); } @@ -2417,25 +2388,25 @@ static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy, u16 rx_status, ustat_val, cl37_fsm_recieved; DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n"); /* Step 1: Make sure signal is detected */ - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_RX0, - MDIO_RX0_RX_STATUS, - &rx_status); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_RX0, + MDIO_RX0_RX_STATUS, + &rx_status); if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) != (MDIO_RX0_RX_STATUS_SIGDET)) { DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73." "rx_status(0x80b0) = 0x%x\n", rx_status); - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_CL73_IEEEB0, - MDIO_CL73_IEEEB0_CL73_AN_CONTROL, - MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN); return; } /* Step 2: Check CL73 state machine */ - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_CL73_USERB0, - MDIO_CL73_USERB0_CL73_USTAT1, - &ustat_val); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_USERB0, + MDIO_CL73_USERB0_CL73_USTAT1, + &ustat_val); if ((ustat_val & (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK | MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) != @@ -2445,12 +2416,14 @@ static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy, "ustat_val(0x8371) = 0x%x\n", ustat_val); return; } - /* Step 3: Check CL37 Message Pages received to indicate LP - supports only CL37 */ - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_REMOTE_PHY, - MDIO_REMOTE_PHY_MISC_RX_STATUS, - &cl37_fsm_recieved); + /* + * Step 3: Check CL37 Message Pages received to indicate LP + * supports only CL37 + */ + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_REMOTE_PHY, + MDIO_REMOTE_PHY_MISC_RX_STATUS, + &cl37_fsm_recieved); if ((cl37_fsm_recieved & (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG | MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) != @@ -2461,14 +2434,18 @@ static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy, cl37_fsm_recieved); return; } - /* The combined cl37/cl73 fsm state information indicating that we are - connected to a device which does not support cl73, but does support - cl37 BAM. In this case we disable cl73 and restart cl37 auto-neg */ + /* + * The combined cl37/cl73 fsm state information indicating that + * we are connected to a device which does not support cl73, but + * does support cl37 BAM. In this case we disable cl73 and + * restart cl37 auto-neg + */ + /* Disable CL73 */ - CL45_WR_OVER_CL22(bp, phy, - MDIO_REG_BANK_CL73_IEEEB0, - MDIO_CL73_IEEEB0_CL73_AN_CONTROL, - 0); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + 0); /* Restart CL37 autoneg */ bnx2x_restart_autoneg(phy, params, 0); DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n"); @@ -2493,14 +2470,14 @@ static u8 bnx2x_link_settings_status(struct bnx2x_phy *phy, struct link_vars *vars) { struct bnx2x *bp = params->bp; - u16 new_line_speed , gp_status; + u16 new_line_speed, gp_status; u8 rc = 0; /* Read gp_status */ - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_GP_STATUS, - MDIO_GP_STATUS_TOP_AN_STATUS1, - &gp_status); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_GP_STATUS, + MDIO_GP_STATUS_TOP_AN_STATUS1, + &gp_status); if (phy->req_line_speed == SPEED_AUTO_NEG) vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED; @@ -2637,9 +2614,9 @@ static void bnx2x_set_gmii_tx_driver(struct link_params *params) u16 bank; /* read precomp */ - CL45_RD_OVER_CL22(bp, phy, - MDIO_REG_BANK_OVER_1G, - MDIO_OVER_1G_LP_UP2, &lp_up2); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_OVER_1G, + MDIO_OVER_1G_LP_UP2, &lp_up2); /* bits [10:7] at lp_up2, positioned at [15:12] */ lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >> @@ -2651,18 +2628,18 @@ static void bnx2x_set_gmii_tx_driver(struct link_params *params) for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3; bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) { - CL45_RD_OVER_CL22(bp, phy, - bank, - MDIO_TX0_TX_DRIVER, &tx_driver); + CL22_RD_OVER_CL45(bp, phy, + bank, + MDIO_TX0_TX_DRIVER, &tx_driver); /* replace tx_driver bits [15:12] */ if (lp_up2 != (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) { tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK; tx_driver |= lp_up2; - CL45_WR_OVER_CL22(bp, phy, - bank, - MDIO_TX0_TX_DRIVER, tx_driver); + CL22_WR_OVER_CL45(bp, phy, + bank, + MDIO_TX0_TX_DRIVER, tx_driver); } } } @@ -2676,10 +2653,10 @@ static u8 bnx2x_emac_program(struct link_params *params, DP(NETIF_MSG_LINK, "setting link speed & duplex\n"); bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 + - EMAC_REG_EMAC_MODE, - (EMAC_MODE_25G_MODE | - EMAC_MODE_PORT_MII_10M | - EMAC_MODE_HALF_DUPLEX)); + EMAC_REG_EMAC_MODE, + (EMAC_MODE_25G_MODE | + EMAC_MODE_PORT_MII_10M | + EMAC_MODE_HALF_DUPLEX)); switch (vars->line_speed) { case SPEED_10: mode |= EMAC_MODE_PORT_MII_10M; @@ -2707,8 +2684,8 @@ static u8 bnx2x_emac_program(struct link_params *params, if (vars->duplex == DUPLEX_HALF) mode |= EMAC_MODE_HALF_DUPLEX; bnx2x_bits_en(bp, - GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE, - mode); + GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE, + mode); bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed); return 0; @@ -2723,7 +2700,7 @@ static void bnx2x_set_preemphasis(struct bnx2x_phy *phy, for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3; bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) { - CL45_WR_OVER_CL22(bp, phy, + CL22_WR_OVER_CL45(bp, phy, bank, MDIO_RX0_RX_EQ_BOOST, phy->rx_preemphasis[i]); @@ -2731,7 +2708,7 @@ static void bnx2x_set_preemphasis(struct bnx2x_phy *phy, for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3; bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) { - CL45_WR_OVER_CL22(bp, phy, + CL22_WR_OVER_CL45(bp, phy, bank, MDIO_TX0_TX_DRIVER, phy->tx_preemphasis[i]); @@ -2754,7 +2731,7 @@ static void bnx2x_init_internal_phy(struct bnx2x_phy *phy, /* forced speed requested? */ if (vars->line_speed != SPEED_AUTO_NEG || (SINGLE_MEDIA_DIRECT(params) && - params->loopback_mode == LOOPBACK_EXT)) { + params->loopback_mode == LOOPBACK_EXT)) { DP(NETIF_MSG_LINK, "not SGMII, no AN\n"); /* disable autoneg */ @@ -2771,7 +2748,7 @@ static void bnx2x_init_internal_phy(struct bnx2x_phy *phy, /* program duplex & pause advertisement (for aneg) */ bnx2x_set_ieee_aneg_advertisment(phy, params, - vars->ieee_fc); + vars->ieee_fc); /* enable autoneg */ bnx2x_set_autoneg(phy, params, vars, enable_cl73); @@ -2842,7 +2819,8 @@ static u8 bnx2x_init_xgxs(struct bnx2x_phy *phy, } static u16 bnx2x_wait_reset_complete(struct bnx2x *bp, - struct bnx2x_phy *phy) + struct bnx2x_phy *phy, + struct link_params *params) { u16 cnt, ctrl; /* Wait for soft reset to get cleared upto 1 sec */ @@ -2853,6 +2831,11 @@ static u16 bnx2x_wait_reset_complete(struct bnx2x *bp, break; msleep(1); } + + if (cnt == 1000) + netdev_err(bp->dev, "Warning: PHY was not initialized," + " Port %d\n", + params->port); DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n", ctrl, cnt); return cnt; } @@ -2863,9 +2846,7 @@ static void bnx2x_link_int_enable(struct link_params *params) u32 mask; struct bnx2x *bp = params->bp; - /* setting the status to report on link up - for either XGXS or SerDes */ - + /* Setting the status to report on link up for either XGXS or SerDes */ if (params->switch_cfg == SWITCH_CFG_10G) { mask = (NIG_MASK_XGXS0_LINK10G | NIG_MASK_XGXS0_LINK_STATUS); @@ -2908,7 +2889,7 @@ static void bnx2x_rearm_latch_signal(struct bnx2x *bp, u8 port, { u32 latch_status = 0; - /** + /* * Disable the MI INT ( external phy int ) by writing 1 to the * status register. Link down indication is high-active-signal, * so in this case we need to write the status to clear the XOR @@ -2933,27 +2914,30 @@ static void bnx2x_rearm_latch_signal(struct bnx2x *bp, u8 port, /* For all latched-signal=up : Re-Arm Latch signals */ REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8, - (latch_status & 0xfffe) | (latch_status & 1)); + (latch_status & 0xfffe) | (latch_status & 1)); } /* For all latched-signal=up,Write original_signal to status */ } static void bnx2x_link_int_ack(struct link_params *params, - struct link_vars *vars, u8 is_10g) + struct link_vars *vars, u8 is_10g) { struct bnx2x *bp = params->bp; u8 port = params->port; - /* first reset all status - * we assume only one line will be change at a time */ + /* + * First reset all status we assume only one line will be + * change at a time + */ bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, - (NIG_STATUS_XGXS0_LINK10G | - NIG_STATUS_XGXS0_LINK_STATUS | - NIG_STATUS_SERDES0_LINK_STATUS)); + (NIG_STATUS_XGXS0_LINK10G | + NIG_STATUS_XGXS0_LINK_STATUS | + NIG_STATUS_SERDES0_LINK_STATUS)); if (vars->phy_link_up) { if (is_10g) { - /* Disable the 10G link interrupt - * by writing 1 to the status register + /* + * Disable the 10G link interrupt by writing 1 to the + * status register */ DP(NETIF_MSG_LINK, "10G XGXS phy link up\n"); bnx2x_bits_en(bp, @@ -2961,9 +2945,9 @@ static void bnx2x_link_int_ack(struct link_params *params, NIG_STATUS_XGXS0_LINK10G); } else if (params->switch_cfg == SWITCH_CFG_10G) { - /* Disable the link interrupt - * by writing 1 to the relevant lane - * in the status register + /* + * Disable the link interrupt by writing 1 to the + * relevant lane in the status register */ u32 ser_lane = ((params->lane_config & PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> @@ -2978,8 +2962,9 @@ static void bnx2x_link_int_ack(struct link_params *params, } else { /* SerDes */ DP(NETIF_MSG_LINK, "SerDes phy link up\n"); - /* Disable the link interrupt - * by writing 1 to the status register + /* + * Disable the link interrupt by writing 1 to the status + * register */ bnx2x_bits_en(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, @@ -3059,8 +3044,7 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, } if ((params->num_phys == MAX_PHYS) && (params->phy[EXT_PHY2].ver_addr != 0)) { - spirom_ver = REG_RD(bp, - params->phy[EXT_PHY2].ver_addr); + spirom_ver = REG_RD(bp, params->phy[EXT_PHY2].ver_addr); if (params->phy[EXT_PHY2].format_fw_ver) { *ver_p = '/'; ver_p++; @@ -3089,29 +3073,27 @@ static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy, /* change the uni_phy_addr in the nig */ md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD + - port*0x18)); + port*0x18)); REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5); bnx2x_cl45_write(bp, phy, - 5, - (MDIO_REG_BANK_AER_BLOCK + - (MDIO_AER_BLOCK_AER_REG & 0xf)), - 0x2800); + 5, + (MDIO_REG_BANK_AER_BLOCK + + (MDIO_AER_BLOCK_AER_REG & 0xf)), + 0x2800); bnx2x_cl45_write(bp, phy, - 5, - (MDIO_REG_BANK_CL73_IEEEB0 + - (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)), - 0x6041); + 5, + (MDIO_REG_BANK_CL73_IEEEB0 + + (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)), + 0x6041); msleep(200); /* set aer mmd back */ bnx2x_set_aer_mmd_xgxs(params, phy); /* and md_devad */ - REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, - md_devad); - + REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, md_devad); } else { u16 mii_ctrl; DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n"); @@ -3152,26 +3134,26 @@ u8 bnx2x_set_led(struct link_params *params, case LED_MODE_OFF: REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0); REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, - SHARED_HW_CFG_LED_MAC1); + SHARED_HW_CFG_LED_MAC1); tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED); EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE)); break; case LED_MODE_OPER: - /** + /* * For all other phys, OPER mode is same as ON, so in case * link is down, do nothing - **/ + */ if (!vars->link_up) break; case LED_MODE_ON: if (params->phy[EXT_PHY1].type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727 && CHIP_IS_E2(bp) && params->num_phys == 2) { - /** - * This is a work-around for E2+8727 Configurations - */ + /* + * This is a work-around for E2+8727 Configurations + */ if (mode == LED_MODE_ON || speed == SPEED_10000){ REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0); @@ -3183,41 +3165,40 @@ u8 bnx2x_set_led(struct link_params *params, return rc; } } else if (SINGLE_MEDIA_DIRECT(params)) { - /** - * This is a work-around for HW issue found when link - * is up in CL73 - */ + /* + * This is a work-around for HW issue found when link + * is up in CL73 + */ REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0); REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1); } else { - REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, - hw_led_mode); + REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode); } - REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + - port*4, 0); + REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4, 0); /* Set blinking rate to ~15.9Hz */ REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4, - LED_BLINK_RATE_VAL); + LED_BLINK_RATE_VAL); REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 + - port*4, 1); + port*4, 1); tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED); - EMAC_WR(bp, EMAC_REG_EMAC_LED, - (tmp & (~EMAC_LED_OVERRIDE))); + EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp & (~EMAC_LED_OVERRIDE))); if (CHIP_IS_E1(bp) && ((speed == SPEED_2500) || (speed == SPEED_1000) || (speed == SPEED_100) || (speed == SPEED_10))) { - /* On Everest 1 Ax chip versions for speeds less than - 10G LED scheme is different */ + /* + * On Everest 1 Ax chip versions for speeds less than + * 10G LED scheme is different + */ REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 - + port*4, 1); + + port*4, 1); REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + - port*4, 0); + port*4, 0); REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 + - port*4, 1); + port*4, 1); } break; @@ -3231,7 +3212,7 @@ u8 bnx2x_set_led(struct link_params *params, } -/** +/* * This function comes to reflect the actual link state read DIRECTLY from the * HW */ @@ -3243,10 +3224,10 @@ u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars, u8 ext_phy_link_up = 0, serdes_phy_type; struct link_vars temp_vars; - CL45_RD_OVER_CL22(bp, ¶ms->phy[INT_PHY], - MDIO_REG_BANK_GP_STATUS, - MDIO_GP_STATUS_TOP_AN_STATUS1, - &gp_status); + CL22_RD_OVER_CL45(bp, ¶ms->phy[INT_PHY], + MDIO_REG_BANK_GP_STATUS, + MDIO_GP_STATUS_TOP_AN_STATUS1, + &gp_status); /* link is up only if both local phy and external phy are up */ if (!(gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS)) return -ESRCH; @@ -3290,15 +3271,15 @@ static u8 bnx2x_link_initialize(struct link_params *params, u8 rc = 0; u8 phy_index, non_ext_phy; struct bnx2x *bp = params->bp; - /** - * In case of external phy existence, the line speed would be the - * line speed linked up by the external phy. In case it is direct - * only, then the line_speed during initialization will be - * equal to the req_line_speed - */ + /* + * In case of external phy existence, the line speed would be the + * line speed linked up by the external phy. In case it is direct + * only, then the line_speed during initialization will be + * equal to the req_line_speed + */ vars->line_speed = params->phy[INT_PHY].req_line_speed; - /** + /* * Initialize the internal phy in case this is a direct board * (no external phys), or this board has external phy which requires * to first. @@ -3326,17 +3307,16 @@ static u8 bnx2x_link_initialize(struct link_params *params, if (!non_ext_phy) for (phy_index = EXT_PHY1; phy_index < params->num_phys; phy_index++) { - /** + /* * No need to initialize second phy in case of first * phy only selection. In case of second phy, we do * need to initialize the first phy, since they are * connected. - **/ + */ if (phy_index == EXT_PHY2 && (bnx2x_phy_selection(params) == PORT_HW_CFG_PHY_SELECTION_FIRST_PHY)) { - DP(NETIF_MSG_LINK, "Not initializing" - "second phy\n"); + DP(NETIF_MSG_LINK, "Ignoring second phy\n"); continue; } params->phy[phy_index].config_init( @@ -3358,9 +3338,8 @@ static void bnx2x_int_link_reset(struct bnx2x_phy *phy, struct link_params *params) { /* reset the SerDes/XGXS */ - REG_WR(params->bp, GRCBASE_MISC + - MISC_REGISTERS_RESET_REG_3_CLEAR, - (0x1ff << (params->port*16))); + REG_WR(params->bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, + (0x1ff << (params->port*16))); } static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy, @@ -3374,11 +3353,11 @@ static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy, else gpio_port = params->port; bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_OUTPUT_LOW, - gpio_port); + MISC_REGISTERS_GPIO_OUTPUT_LOW, + gpio_port); bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, - MISC_REGISTERS_GPIO_OUTPUT_LOW, - gpio_port); + MISC_REGISTERS_GPIO_OUTPUT_LOW, + gpio_port); DP(NETIF_MSG_LINK, "reset external PHY\n"); } @@ -3409,9 +3388,8 @@ static u8 bnx2x_update_link_down(struct link_params *params, /* reset BigMac */ bnx2x_bmac_rx_disable(bp, params->port); - REG_WR(bp, GRCBASE_MISC + - MISC_REGISTERS_RESET_REG_2_CLEAR, - (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); return 0; } @@ -3462,7 +3440,7 @@ static u8 bnx2x_update_link_up(struct link_params *params, msleep(20); return rc; } -/** +/* * The bnx2x_link_update function should be called upon link * interrupt. * Link is considered up as follows: @@ -3501,12 +3479,11 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4)); is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + - port*0x18) > 0); + port*0x18) > 0); DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n", REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4), is_mi_int, - REG_RD(bp, - NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c)); + REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c)); DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n", REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68), @@ -3515,14 +3492,14 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) /* disable emac */ REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0); - /** - * Step 1: - * Check external link change only for external phys, and apply - * priority selection between them in case the link on both phys - * is up. Note that the instead of the common vars, a temporary - * vars argument is used since each phy may have different link/ - * speed/duplex result - */ + /* + * Step 1: + * Check external link change only for external phys, and apply + * priority selection between them in case the link on both phys + * is up. Note that the instead of the common vars, a temporary + * vars argument is used since each phy may have different link/ + * speed/duplex result + */ for (phy_index = EXT_PHY1; phy_index < params->num_phys; phy_index++) { struct bnx2x_phy *phy = ¶ms->phy[phy_index]; @@ -3547,22 +3524,22 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) switch (bnx2x_phy_selection(params)) { case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT: case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY: - /** + /* * In this option, the first PHY makes sure to pass the * traffic through itself only. * Its not clear how to reset the link on the second phy - **/ + */ active_external_phy = EXT_PHY1; break; case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY: - /** + /* * In this option, the first PHY makes sure to pass the * traffic through the second PHY. - **/ + */ active_external_phy = EXT_PHY2; break; default: - /** + /* * Link indication on both PHYs with the following cases * is invalid: * - FIRST_PHY means that second phy wasn't initialized, @@ -3570,7 +3547,7 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) * - SECOND_PHY means that first phy should not be able * to link up by itself (using configuration) * - DEFAULT should be overriden during initialiazation - **/ + */ DP(NETIF_MSG_LINK, "Invalid link indication" "mpc=0x%x. DISABLING LINK !!!\n", params->multi_phy_config); @@ -3580,18 +3557,18 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) } } prev_line_speed = vars->line_speed; - /** - * Step 2: - * Read the status of the internal phy. In case of - * DIRECT_SINGLE_MEDIA board, this link is the external link, - * otherwise this is the link between the 577xx and the first - * external phy - */ + /* + * Step 2: + * Read the status of the internal phy. In case of + * DIRECT_SINGLE_MEDIA board, this link is the external link, + * otherwise this is the link between the 577xx and the first + * external phy + */ if (params->phy[INT_PHY].read_status) params->phy[INT_PHY].read_status( ¶ms->phy[INT_PHY], params, vars); - /** + /* * The INT_PHY flow control reside in the vars. This include the * case where the speed or flow control are not set to AUTO. * Otherwise, the active external phy flow control result is set @@ -3601,13 +3578,13 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) */ if (active_external_phy > INT_PHY) { vars->flow_ctrl = phy_vars[active_external_phy].flow_ctrl; - /** + /* * Link speed is taken from the XGXS. AN and FC result from * the external phy. */ vars->link_status |= phy_vars[active_external_phy].link_status; - /** + /* * if active_external_phy is first PHY and link is up - disable * disable TX on second external PHY */ @@ -3643,7 +3620,7 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x," " ext_phy_line_speed = %d\n", vars->flow_ctrl, vars->link_status, ext_phy_line_speed); - /** + /* * Upon link speed change set the NIG into drain mode. Comes to * deals with possible FIFO glitch due to clk change when speed * is decreased without link down indicator @@ -3658,8 +3635,8 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) ext_phy_line_speed); vars->phy_link_up = 0; } else if (prev_line_speed != vars->line_speed) { - REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE - + params->port*4, 0); + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, + 0); msleep(1); } } @@ -3674,14 +3651,14 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) bnx2x_link_int_ack(params, vars, link_10g); - /** - * In case external phy link is up, and internal link is down - * (not initialized yet probably after link initialization, it - * needs to be initialized. - * Note that after link down-up as result of cable plug, the xgxs - * link would probably become up again without the need - * initialize it - */ + /* + * In case external phy link is up, and internal link is down + * (not initialized yet probably after link initialization, it + * needs to be initialized. + * Note that after link down-up as result of cable plug, the xgxs + * link would probably become up again without the need + * initialize it + */ if (!(SINGLE_MEDIA_DIRECT(params))) { DP(NETIF_MSG_LINK, "ext_phy_link_up = %d, int_link_up = %d," " init_preceding = %d\n", ext_phy_link_up, @@ -3701,9 +3678,9 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) vars); } } - /** - * Link is up only if both local phy and external phy (in case of - * non-direct board) are up + /* + * Link is up only if both local phy and external phy (in case of + * non-direct board) are up */ vars->link_up = (vars->phy_link_up && (ext_phy_link_up || @@ -3724,10 +3701,10 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port) { bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_OUTPUT_LOW, port); + MISC_REGISTERS_GPIO_OUTPUT_LOW, port); msleep(1); bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_OUTPUT_HIGH, port); + MISC_REGISTERS_GPIO_OUTPUT_HIGH, port); } static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port, @@ -3747,9 +3724,9 @@ static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp, u16 fw_ver1, fw_ver2; bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, - MDIO_PMA_REG_ROM_VER1, &fw_ver1); + MDIO_PMA_REG_ROM_VER1, &fw_ver1); bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, - MDIO_PMA_REG_ROM_VER2, &fw_ver2); + MDIO_PMA_REG_ROM_VER2, &fw_ver2); bnx2x_save_spirom_version(bp, port, (u32)(fw_ver1<<16 | fw_ver2), phy->ver_addr); } @@ -3770,7 +3747,7 @@ static void bnx2x_ext_phy_set_pause(struct link_params *params, if ((vars->ieee_fc & MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) == MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) { - val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC; + val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC; } if ((vars->ieee_fc & MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) == @@ -3801,11 +3778,11 @@ static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy, else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) { ret = 1; bnx2x_cl45_read(bp, phy, - MDIO_AN_DEVAD, - MDIO_AN_REG_ADV_PAUSE, &ld_pause); + MDIO_AN_DEVAD, + MDIO_AN_REG_ADV_PAUSE, &ld_pause); bnx2x_cl45_read(bp, phy, - MDIO_AN_DEVAD, - MDIO_AN_REG_LP_AUTO_NEG, &lp_pause); + MDIO_AN_DEVAD, + MDIO_AN_REG_LP_AUTO_NEG, &lp_pause); pause_result = (ld_pause & MDIO_AN_REG_ADV_PAUSE_MASK) >> 8; pause_result |= (lp_pause & @@ -3881,31 +3858,31 @@ static u8 bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp, /* Boot port from external ROM */ /* EDC grst */ bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_GEN_CTRL, - 0x0001); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_GEN_CTRL, + 0x0001); /* ucode reboot and rst */ bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_GEN_CTRL, - 0x008c); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_GEN_CTRL, + 0x008c); bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_MISC_CTRL1, 0x0001); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_MISC_CTRL1, 0x0001); /* Reset internal microprocessor */ bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_GEN_CTRL, - MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_GEN_CTRL, + MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET); /* Release srst bit */ bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_GEN_CTRL, - MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_GEN_CTRL, + MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP); /* Delay 100ms per the PHY specifications */ msleep(100); @@ -3936,8 +3913,8 @@ static u8 bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp, /* Clear ser_boot_ctl bit */ bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_MISC_CTRL1, 0x0000); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_MISC_CTRL1, 0x0000); bnx2x_save_bcm_spirom_ver(bp, phy, port); DP(NETIF_MSG_LINK, @@ -3958,8 +3935,8 @@ static u8 bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy) /* Read 8073 HW revision*/ bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_8073_CHIP_REV, &val); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8073_CHIP_REV, &val); if (val != 1) { /* No need to workaround in 8073 A1 */ @@ -3967,8 +3944,8 @@ static u8 bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy) } bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_ROM_VER2, &val); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, &val); /* SNR should be applied only for version 0x102 */ if (val != 0x102) @@ -3982,8 +3959,8 @@ static u8 bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy) u16 val, cnt, cnt1 ; bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_8073_CHIP_REV, &val); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8073_CHIP_REV, &val); if (val > 0) { /* No need to workaround in 8073 A1 */ @@ -3991,26 +3968,32 @@ static u8 bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy) } /* XAUI workaround in 8073 A0: */ - /* After loading the boot ROM and restarting Autoneg, - poll Dev1, Reg $C820: */ + /* + * After loading the boot ROM and restarting Autoneg, poll + * Dev1, Reg $C820: + */ for (cnt = 0; cnt < 1000; cnt++) { bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_8073_SPEED_LINK_STATUS, - &val); - /* If bit [14] = 0 or bit [13] = 0, continue on with - system initialization (XAUI work-around not required, - as these bits indicate 2.5G or 1G link up). */ + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8073_SPEED_LINK_STATUS, + &val); + /* + * If bit [14] = 0 or bit [13] = 0, continue on with + * system initialization (XAUI work-around not required, as + * these bits indicate 2.5G or 1G link up). + */ if (!(val & (1<<14)) || !(val & (1<<13))) { DP(NETIF_MSG_LINK, "XAUI work-around not required\n"); return 0; } else if (!(val & (1<<15))) { - DP(NETIF_MSG_LINK, "clc bit 15 went off\n"); - /* If bit 15 is 0, then poll Dev1, Reg $C841 until - it's MSB (bit 15) goes to 1 (indicating that the - XAUI workaround has completed), - then continue on with system initialization.*/ + DP(NETIF_MSG_LINK, "bit 15 went off\n"); + /* + * If bit 15 is 0, then poll Dev1, Reg $C841 until it's + * MSB (bit15) goes to 1 (indicating that the XAUI + * workaround has completed), then continue on with + * system initialization. + */ for (cnt1 = 0; cnt1 < 1000; cnt1++) { bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, @@ -4093,10 +4076,10 @@ static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy, gpio_port = params->port; /* Restore normal power mode*/ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, - MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port); + MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port); bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port); + MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port); /* enable LASI */ bnx2x_cl45_write(bp, phy, @@ -4114,10 +4097,6 @@ static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy, DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1); - /** - * If this is forced speed, set to KR or KX (all other are not - * supported) - */ /* Swap polarity if required - Must be done only in non-1G mode */ if (params->lane_config & PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) { /* Configure the 8073 to swap _P and _N of the KR lines */ @@ -4160,8 +4139,10 @@ static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy, val = (1<<7); } else if (phy->req_line_speed == SPEED_2500) { val = (1<<5); - /* Note that 2.5G works only - when used with 1G advertisment */ + /* + * Note that 2.5G works only when used with 1G + * advertisment + */ } else val = (1<<5); } else { @@ -4170,8 +4151,7 @@ static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy, PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) val |= (1<<7); - /* Note that 2.5G works only when - used with 1G advertisment */ + /* Note that 2.5G works only when used with 1G advertisment */ if (phy->speed_cap_mask & (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G | PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)) @@ -4211,9 +4191,11 @@ static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy, /* Add support for CL37 (passive mode) III */ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000); - /* The SNR will improve about 2db by changing - BW and FEE main tap. Rest commands are executed - after link is up*/ + /* + * The SNR will improve about 2db by changing BW and FEE main + * tap. Rest commands are executed after link is up + * Change FFE main cursor to 5 in EDC register + */ if (bnx2x_8073_is_snr_needed(bp, phy)) bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_EDC_FFE_MAIN, @@ -4297,12 +4279,11 @@ static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy, link_up = (((val1 & 4) == 4) || (an1000_status & (1<<1))); if (link_up && bnx2x_8073_is_snr_needed(bp, phy)) { - /* The SNR will improve about 2dbby - changing the BW and FEE main tap.*/ - /* The 1st write to change FFE main - tap is set before restart AN */ - /* Change PLL Bandwidth in EDC - register */ + /* + * The SNR will improve about 2dbby changing the BW and FEE main + * tap. The 1st write to change FFE main tap is set before + * restart AN. Change PLL Bandwidth in EDC register + */ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_PLL_BANDWIDTH, 0x26BC); @@ -4346,10 +4327,10 @@ static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy, bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, MDIO_XS_REG_8073_RX_CTRL_PCIE, &val1); - /** - * Set bit 3 to invert Rx in 1G mode and clear this bit - * when it`s in 10G mode. - */ + /* + * Set bit 3 to invert Rx in 1G mode and clear this bit + * when it`s in 10G mode. + */ if (vars->line_speed == SPEED_1000) { DP(NETIF_MSG_LINK, "Swapping 1G polarity for" "the 8073\n"); @@ -4381,8 +4362,8 @@ static void bnx2x_8073_link_reset(struct bnx2x_phy *phy, DP(NETIF_MSG_LINK, "Setting 8073 port %d into low power mode\n", gpio_port); bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, - MISC_REGISTERS_GPIO_OUTPUT_LOW, - gpio_port); + MISC_REGISTERS_GPIO_OUTPUT_LOW, + gpio_port); } /******************************************************************/ @@ -4396,11 +4377,11 @@ static u8 bnx2x_8705_config_init(struct bnx2x_phy *phy, DP(NETIF_MSG_LINK, "init 8705\n"); /* Restore normal power mode*/ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, - MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); + MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); /* HW reset */ bnx2x_ext_phy_hw_reset(bp, params->port); bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040); - bnx2x_wait_reset_complete(bp, phy); + bnx2x_wait_reset_complete(bp, phy, params); bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL, 0x8288); @@ -4451,35 +4432,79 @@ static u8 bnx2x_8705_read_status(struct bnx2x_phy *phy, /******************************************************************/ /* SFP+ module Section */ /******************************************************************/ -static void bnx2x_sfp_set_transmitter(struct bnx2x *bp, +static u8 bnx2x_get_gpio_port(struct link_params *params) +{ + u8 gpio_port; + u32 swap_val, swap_override; + struct bnx2x *bp = params->bp; + if (CHIP_IS_E2(bp)) + gpio_port = BP_PATH(bp); + else + gpio_port = params->port; + swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); + swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); + return gpio_port ^ (swap_val && swap_override); +} +static void bnx2x_sfp_set_transmitter(struct link_params *params, struct bnx2x_phy *phy, - u8 port, u8 tx_en) { u16 val; + u8 port = params->port; + struct bnx2x *bp = params->bp; + u32 tx_en_mode; - DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n", - tx_en, port); /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/ - bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_PHY_IDENTIFIER, - &val); + tx_en_mode = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].sfp_ctrl)) & + PORT_HW_CFG_TX_LASER_MASK; + DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x " + "mode = %x\n", tx_en, port, tx_en_mode); + switch (tx_en_mode) { + case PORT_HW_CFG_TX_LASER_MDIO: - if (tx_en) - val &= ~(1<<15); - else - val |= (1<<15); + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + &val); - bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_PHY_IDENTIFIER, - val); + if (tx_en) + val &= ~(1<<15); + else + val |= (1<<15); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + val); + break; + case PORT_HW_CFG_TX_LASER_GPIO0: + case PORT_HW_CFG_TX_LASER_GPIO1: + case PORT_HW_CFG_TX_LASER_GPIO2: + case PORT_HW_CFG_TX_LASER_GPIO3: + { + u16 gpio_pin; + u8 gpio_port, gpio_mode; + if (tx_en) + gpio_mode = MISC_REGISTERS_GPIO_OUTPUT_HIGH; + else + gpio_mode = MISC_REGISTERS_GPIO_OUTPUT_LOW; + + gpio_pin = tx_en_mode - PORT_HW_CFG_TX_LASER_GPIO0; + gpio_port = bnx2x_get_gpio_port(params); + bnx2x_set_gpio(bp, gpio_pin, gpio_mode, gpio_port); + break; + } + default: + DP(NETIF_MSG_LINK, "Invalid TX_LASER_MDIO 0x%x\n", tx_en_mode); + break; + } } static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy, struct link_params *params, - u16 addr, u8 byte_cnt, u8 *o_buf) + u16 addr, u8 byte_cnt, u8 *o_buf) { struct bnx2x *bp = params->bp; u16 val = 0; @@ -4492,23 +4517,23 @@ static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy, /* Set the read command byte count */ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT, - (byte_cnt | 0xa000)); + (byte_cnt | 0xa000)); /* Set the read command address */ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR, - addr); + addr); /* Activate read command */ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, - 0x2c0f); + 0x2c0f); /* Wait up to 500us for command complete status */ for (i = 0; i < 100; i++) { bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) == MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) break; @@ -4526,15 +4551,15 @@ static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy, /* Read the buffer */ for (i = 0; i < byte_cnt; i++) { bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val); o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK); } for (i = 0; i < 100; i++) { bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) == MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE) return 0; @@ -4545,7 +4570,7 @@ static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy, static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy, struct link_params *params, - u16 addr, u8 byte_cnt, u8 *o_buf) + u16 addr, u8 byte_cnt, u8 *o_buf) { struct bnx2x *bp = params->bp; u16 val, i; @@ -4558,41 +4583,43 @@ static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy, /* Need to read from 1.8000 to clear it */ bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, - &val); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, + &val); /* Set the read command byte count */ bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT, - ((byte_cnt < 2) ? 2 : byte_cnt)); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT, + ((byte_cnt < 2) ? 2 : byte_cnt)); /* Set the read command address */ bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR, - addr); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR, + addr); /* Set the destination address */ bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - 0x8004, - MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF); + MDIO_PMA_DEVAD, + 0x8004, + MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF); /* Activate read command */ bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, - 0x8002); - /* Wait appropriate time for two-wire command to finish before - polling the status register */ + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, + 0x8002); + /* + * Wait appropriate time for two-wire command to finish before + * polling the status register + */ msleep(1); /* Wait up to 500us for command complete status */ for (i = 0; i < 100; i++) { bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) == MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) break; @@ -4604,21 +4631,21 @@ static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy, DP(NETIF_MSG_LINK, "Got bad status 0x%x when reading from SFP+ EEPROM\n", (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK)); - return -EINVAL; + return -EFAULT; } /* Read the buffer */ for (i = 0; i < byte_cnt; i++) { bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val); o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK); } for (i = 0; i < 100; i++) { bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) == MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE) return 0; @@ -4628,22 +4655,22 @@ static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy, return -EINVAL; } -static u8 bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy, - struct link_params *params, u16 addr, - u8 byte_cnt, u8 *o_buf) +u8 bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy, + struct link_params *params, u16 addr, + u8 byte_cnt, u8 *o_buf) { if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) return bnx2x_8726_read_sfp_module_eeprom(phy, params, addr, - byte_cnt, o_buf); + byte_cnt, o_buf); else if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) return bnx2x_8727_read_sfp_module_eeprom(phy, params, addr, - byte_cnt, o_buf); + byte_cnt, o_buf); return -EINVAL; } static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy, struct link_params *params, - u16 *edc_mode) + u16 *edc_mode) { struct bnx2x *bp = params->bp; u8 val, check_limiting_mode = 0; @@ -4664,8 +4691,10 @@ static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy, { u8 copper_module_type; - /* Check if its active cable( includes SFP+ module) - of passive cable*/ + /* + * Check if its active cable (includes SFP+ module) + * of passive cable + */ if (bnx2x_read_sfp_module_eeprom(phy, params, SFP_EEPROM_FC_TX_TECH_ADDR, @@ -4724,8 +4753,10 @@ static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy, DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode); return 0; } -/* This function read the relevant field from the module ( SFP+ ), - and verify it is compliant with this board */ +/* + * This function read the relevant field from the module (SFP+), and verify it + * is compliant with this board + */ static u8 bnx2x_verify_sfp_module(struct bnx2x_phy *phy, struct link_params *params) { @@ -4774,24 +4805,24 @@ static u8 bnx2x_verify_sfp_module(struct bnx2x_phy *phy, /* format the warning message */ if (bnx2x_read_sfp_module_eeprom(phy, params, - SFP_EEPROM_VENDOR_NAME_ADDR, - SFP_EEPROM_VENDOR_NAME_SIZE, - (u8 *)vendor_name)) + SFP_EEPROM_VENDOR_NAME_ADDR, + SFP_EEPROM_VENDOR_NAME_SIZE, + (u8 *)vendor_name)) vendor_name[0] = '\0'; else vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0'; if (bnx2x_read_sfp_module_eeprom(phy, params, - SFP_EEPROM_PART_NO_ADDR, - SFP_EEPROM_PART_NO_SIZE, - (u8 *)vendor_pn)) + SFP_EEPROM_PART_NO_ADDR, + SFP_EEPROM_PART_NO_SIZE, + (u8 *)vendor_pn)) vendor_pn[0] = '\0'; else vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0'; - netdev_info(bp->dev, "Warning: Unqualified SFP+ module detected," - " Port %d from %s part number %s\n", - params->port, vendor_name, vendor_pn); + netdev_err(bp->dev, "Warning: Unqualified SFP+ module detected," + " Port %d from %s part number %s\n", + params->port, vendor_name, vendor_pn); phy->flags |= FLAGS_SFP_NOT_APPROVED; return -EINVAL; } @@ -4803,8 +4834,11 @@ static u8 bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy, u8 val; struct bnx2x *bp = params->bp; u16 timeout; - /* Initialization time after hot-plug may take up to 300ms for some - phys type ( e.g. JDSU ) */ + /* + * Initialization time after hot-plug may take up to 300ms for + * some phys type ( e.g. JDSU ) + */ + for (timeout = 0; timeout < 60; timeout++) { if (bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val) == 0) { @@ -4823,16 +4857,14 @@ static void bnx2x_8727_power_module(struct bnx2x *bp, /* Make sure GPIOs are not using for LED mode */ u16 val; /* - * In the GPIO register, bit 4 is use to detemine if the GPIOs are + * In the GPIO register, bit 4 is use to determine if the GPIOs are * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for * output * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0 * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1 * where the 1st bit is the over-current(only input), and 2nd bit is * for power( only output ) - */ - - /* + * * In case of NOC feature is disabled and power is up, set GPIO control * as input to enable listening of over-current indication */ @@ -4861,15 +4893,14 @@ static u8 bnx2x_8726_set_limiting_mode(struct bnx2x *bp, u16 cur_limiting_mode; bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_ROM_VER2, - &cur_limiting_mode); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, + &cur_limiting_mode); DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n", cur_limiting_mode); if (edc_mode == EDC_MODE_LIMITING) { - DP(NETIF_MSG_LINK, - "Setting LIMITING MODE\n"); + DP(NETIF_MSG_LINK, "Setting LIMITING MODE\n"); bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER2, @@ -4878,62 +4909,63 @@ static u8 bnx2x_8726_set_limiting_mode(struct bnx2x *bp, DP(NETIF_MSG_LINK, "Setting LRM MODE\n"); - /* Changing to LRM mode takes quite few seconds. - So do it only if current mode is limiting - ( default is LRM )*/ + /* + * Changing to LRM mode takes quite few seconds. So do it only + * if current mode is limiting (default is LRM) + */ if (cur_limiting_mode != EDC_MODE_LIMITING) return 0; bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_LRM_MODE, - 0); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_LRM_MODE, + 0); bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_ROM_VER2, - 0x128); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, + 0x128); bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_MISC_CTRL0, - 0x4008); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_MISC_CTRL0, + 0x4008); bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_LRM_MODE, - 0xaaaa); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_LRM_MODE, + 0xaaaa); } return 0; } static u8 bnx2x_8727_set_limiting_mode(struct bnx2x *bp, struct bnx2x_phy *phy, - u16 edc_mode) + u16 edc_mode) { u16 phy_identifier; u16 rom_ver2_val; bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_PHY_IDENTIFIER, - &phy_identifier); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + &phy_identifier); bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_PHY_IDENTIFIER, - (phy_identifier & ~(1<<9))); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + (phy_identifier & ~(1<<9))); bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_ROM_VER2, - &rom_ver2_val); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, + &rom_ver2_val); /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */ bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_ROM_VER2, - (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff)); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, + (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff)); bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_PHY_IDENTIFIER, - (phy_identifier | (1<<9))); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + (phy_identifier | (1<<9))); return 0; } @@ -4946,11 +4978,11 @@ static void bnx2x_8727_specific_func(struct bnx2x_phy *phy, switch (action) { case DISABLE_TX: - bnx2x_sfp_set_transmitter(bp, phy, params->port, 0); + bnx2x_sfp_set_transmitter(params, phy, 0); break; case ENABLE_TX: if (!(phy->flags & FLAGS_SFP_NOT_APPROVED)) - bnx2x_sfp_set_transmitter(bp, phy, params->port, 1); + bnx2x_sfp_set_transmitter(params, phy, 1); break; default: DP(NETIF_MSG_LINK, "Function 0x%x not supported by 8727\n", @@ -4959,6 +4991,38 @@ static void bnx2x_8727_specific_func(struct bnx2x_phy *phy, } } +static void bnx2x_set_sfp_module_fault_led(struct link_params *params, + u8 gpio_mode) +{ + struct bnx2x *bp = params->bp; + + u32 fault_led_gpio = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[params->port].sfp_ctrl)) & + PORT_HW_CFG_FAULT_MODULE_LED_MASK; + switch (fault_led_gpio) { + case PORT_HW_CFG_FAULT_MODULE_LED_DISABLED: + return; + case PORT_HW_CFG_FAULT_MODULE_LED_GPIO0: + case PORT_HW_CFG_FAULT_MODULE_LED_GPIO1: + case PORT_HW_CFG_FAULT_MODULE_LED_GPIO2: + case PORT_HW_CFG_FAULT_MODULE_LED_GPIO3: + { + u8 gpio_port = bnx2x_get_gpio_port(params); + u16 gpio_pin = fault_led_gpio - + PORT_HW_CFG_FAULT_MODULE_LED_GPIO0; + DP(NETIF_MSG_LINK, "Set fault module-detected led " + "pin %x port %x mode %x\n", + gpio_pin, gpio_port, gpio_mode); + bnx2x_set_gpio(bp, gpio_pin, gpio_mode, gpio_port); + } + break; + default: + DP(NETIF_MSG_LINK, "Error: Invalid fault led mode 0x%x\n", + fault_led_gpio); + } +} + static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy, struct link_params *params) { @@ -4976,15 +5040,14 @@ static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy, if (bnx2x_get_edc_mode(phy, params, &edc_mode) != 0) { DP(NETIF_MSG_LINK, "Failed to get valid module type\n"); return -EINVAL; - } else if (bnx2x_verify_sfp_module(phy, params) != - 0) { + } else if (bnx2x_verify_sfp_module(phy, params) != 0) { /* check SFP+ module compatibility */ DP(NETIF_MSG_LINK, "Module verification failed!!\n"); rc = -EINVAL; /* Turn on fault module-detected led */ - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, - MISC_REGISTERS_GPIO_HIGH, - params->port); + bnx2x_set_sfp_module_fault_led(params, + MISC_REGISTERS_GPIO_HIGH); + if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) && ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) { @@ -4995,18 +5058,17 @@ static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy, } } else { /* Turn off fault module-detected led */ - DP(NETIF_MSG_LINK, "Turn off fault module-detected led\n"); - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, - MISC_REGISTERS_GPIO_LOW, - params->port); + bnx2x_set_sfp_module_fault_led(params, MISC_REGISTERS_GPIO_LOW); } /* power up the SFP module */ if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) bnx2x_8727_power_module(bp, phy, 1); - /* Check and set limiting mode / LRM mode on 8726. - On 8727 it is done automatically */ + /* + * Check and set limiting mode / LRM mode on 8726. On 8727 it + * is done automatically + */ if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) bnx2x_8726_set_limiting_mode(bp, phy, edc_mode); else @@ -5018,9 +5080,9 @@ static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy, if (rc == 0 || (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) != PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) - bnx2x_sfp_set_transmitter(bp, phy, params->port, 1); + bnx2x_sfp_set_transmitter(params, phy, 1); else - bnx2x_sfp_set_transmitter(bp, phy, params->port, 0); + bnx2x_sfp_set_transmitter(params, phy, 0); return rc; } @@ -5033,11 +5095,9 @@ void bnx2x_handle_module_detect_int(struct link_params *params) u8 port = params->port; /* Set valid module led off */ - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, - MISC_REGISTERS_GPIO_HIGH, - params->port); + bnx2x_set_sfp_module_fault_led(params, MISC_REGISTERS_GPIO_HIGH); - /* Get current gpio val refelecting module plugged in / out*/ + /* Get current gpio val reflecting module plugged in / out*/ gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port); /* Call the handling function in case module is detected */ @@ -5053,18 +5113,20 @@ void bnx2x_handle_module_detect_int(struct link_params *params) DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n"); } else { u32 val = REG_RD(bp, params->shmem_base + - offsetof(struct shmem_region, dev_info. - port_feature_config[params->port]. - config)); + offsetof(struct shmem_region, dev_info. + port_feature_config[params->port]. + config)); bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3, MISC_REGISTERS_GPIO_INT_OUTPUT_SET, port); - /* Module was plugged out. */ - /* Disable transmit for this module */ + /* + * Module was plugged out. + * Disable transmit for this module + */ if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) - bnx2x_sfp_set_transmitter(bp, phy, params->port, 0); + bnx2x_sfp_set_transmitter(params, phy, 0); } } @@ -5100,9 +5162,9 @@ static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy, DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x pcs_status 0x%x 1Gbps" " link_status 0x%x\n", rx_sd, pcs_status, val2); - /* link is up if both bit 0 of pmd_rx_sd and - * bit 0 of pcs_status are set, or if the autoneg bit - * 1 is set + /* + * link is up if both bit 0 of pmd_rx_sd and bit 0 of pcs_status + * are set, or if the autoneg bit 1 is set */ link_up = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1))); if (link_up) { @@ -5123,14 +5185,15 @@ static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy, struct link_params *params, struct link_vars *vars) { - u16 cnt, val; + u32 tx_en_mode; + u16 cnt, val, tmp1; struct bnx2x *bp = params->bp; bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, - MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); + MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); /* HW reset */ bnx2x_ext_phy_hw_reset(bp, params->port); bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040); - bnx2x_wait_reset_complete(bp, phy); + bnx2x_wait_reset_complete(bp, phy, params); /* Wait until fw is loaded */ for (cnt = 0; cnt < 100; cnt++) { @@ -5197,6 +5260,26 @@ static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy, 0x0004); } bnx2x_save_bcm_spirom_ver(bp, phy, params->port); + + /* + * If TX Laser is controlled by GPIO_0, do not let PHY go into low + * power mode, if TX Laser is disabled + */ + + tx_en_mode = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[params->port].sfp_ctrl)) + & PORT_HW_CFG_TX_LASER_MASK; + + if (tx_en_mode == PORT_HW_CFG_TX_LASER_GPIO0) { + DP(NETIF_MSG_LINK, "Enabling TXONOFF_PWRDN_DIS\n"); + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_DIGITAL_CTRL, &tmp1); + tmp1 |= 0x1; + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_DIGITAL_CTRL, tmp1); + } + return 0; } @@ -5231,26 +5314,26 @@ static void bnx2x_8726_external_rom_boot(struct bnx2x_phy *phy, /* Set soft reset */ bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_GEN_CTRL, - MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_GEN_CTRL, + MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET); bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_MISC_CTRL1, 0x0001); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_MISC_CTRL1, 0x0001); bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_GEN_CTRL, - MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_GEN_CTRL, + MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP); /* wait for 150ms for microcode load */ msleep(150); /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */ bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_MISC_CTRL1, 0x0000); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_MISC_CTRL1, 0x0000); msleep(200); bnx2x_save_bcm_spirom_ver(bp, phy, params->port); @@ -5285,23 +5368,18 @@ static u8 bnx2x_8726_config_init(struct bnx2x_phy *phy, u32 val; u32 swap_val, swap_override, aeu_gpio_mask, offset; DP(NETIF_MSG_LINK, "Initializing BCM8726\n"); - /* Restore normal power mode*/ - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, - MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); - - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15); - bnx2x_wait_reset_complete(bp, phy); + bnx2x_wait_reset_complete(bp, phy, params); bnx2x_8726_external_rom_boot(phy, params); - /* Need to call module detected on initialization since - the module detection triggered by actual module - insertion might occur before driver is loaded, and when - driver is loaded, it reset all registers, including the - transmitter */ + /* + * Need to call module detected on initialization since the module + * detection triggered by actual module insertion might occur before + * driver is loaded, and when driver is loaded, it reset all + * registers, including the transmitter + */ bnx2x_sfp_module_detection(phy, params); if (phy->req_line_speed == SPEED_1000) { @@ -5334,8 +5412,10 @@ static u8 bnx2x_8726_config_init(struct bnx2x_phy *phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000); bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200); - /* Enable RX-ALARM control to receive - interrupt for 1G speed change */ + /* + * Enable RX-ALARM control to receive interrupt for 1G speed + * change + */ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x4); bnx2x_cl45_write(bp, phy, @@ -5367,7 +5447,7 @@ static u8 bnx2x_8726_config_init(struct bnx2x_phy *phy, /* Set GPIO3 to trigger SFP+ module insertion/removal */ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3, - MISC_REGISTERS_GPIO_INPUT_HI_Z, params->port); + MISC_REGISTERS_GPIO_INPUT_HI_Z, params->port); /* The GPIO should be swapped if the swap register is set and active */ swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); @@ -5458,7 +5538,7 @@ static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy, struct link_params *params) { u32 swap_val, swap_override; u8 port; - /** + /* * The PHY reset is controlled by GPIO 1. Fake the port number * to cancel the swap done in set_gpio() */ @@ -5467,20 +5547,21 @@ static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy, swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); port = (swap_val && swap_override) ^ 1; bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_OUTPUT_LOW, port); + MISC_REGISTERS_GPIO_OUTPUT_LOW, port); } static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy, struct link_params *params, struct link_vars *vars) { - u16 tmp1, val, mod_abs; + u32 tx_en_mode; + u16 tmp1, val, mod_abs, tmp2; u16 rx_alarm_ctrl_val; u16 lasi_ctrl_val; struct bnx2x *bp = params->bp; /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */ - bnx2x_wait_reset_complete(bp, phy); + bnx2x_wait_reset_complete(bp, phy, params); rx_alarm_ctrl_val = (1<<2) | (1<<5) ; lasi_ctrl_val = 0x0004; @@ -5493,14 +5574,17 @@ static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy, bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, lasi_ctrl_val); - /* Initially configure MOD_ABS to interrupt when - module is presence( bit 8) */ + /* + * Initially configure MOD_ABS to interrupt when module is + * presence( bit 8) + */ bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs); - /* Set EDC off by setting OPTXLOS signal input to low - (bit 9). - When the EDC is off it locks onto a reference clock and - avoids becoming 'lost'.*/ + /* + * Set EDC off by setting OPTXLOS signal input to low (bit 9). + * When the EDC is off it locks onto a reference clock and avoids + * becoming 'lost' + */ mod_abs &= ~(1<<8); if (!(phy->flags & FLAGS_NOC)) mod_abs &= ~(1<<9); @@ -5515,7 +5599,7 @@ static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy, if (phy->flags & FLAGS_NOC) val |= (3<<5); - /** + /* * Set 8727 GPIOs to input to allow reading from the 8727 GPIO0 * status which reflect SFP+ module over-current */ @@ -5542,7 +5626,7 @@ static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy, bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1); DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1); - /** + /* * Power down the XAUI until link is up in case of dual-media * and 1G */ @@ -5568,7 +5652,7 @@ static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy, bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300); } else { - /** + /* * Since the 8727 has only single reset pin, need to set the 10G * registers although it is default */ @@ -5584,7 +5668,8 @@ static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy, 0x0008); } - /* Set 2-wire transfer rate of SFP+ module EEPROM + /* + * Set 2-wire transfer rate of SFP+ module EEPROM * to 100Khz since some DACs(direct attached cables) do * not work at 400Khz. */ @@ -5607,6 +5692,26 @@ static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy, phy->tx_preemphasis[1]); } + /* + * If TX Laser is controlled by GPIO_0, do not let PHY go into low + * power mode, if TX Laser is disabled + */ + tx_en_mode = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[params->port].sfp_ctrl)) + & PORT_HW_CFG_TX_LASER_MASK; + + if (tx_en_mode == PORT_HW_CFG_TX_LASER_GPIO0) { + + DP(NETIF_MSG_LINK, "Enabling TXONOFF_PWRDN_DIS\n"); + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_OPT_CFG_REG, &tmp2); + tmp2 |= 0x1000; + tmp2 &= 0xFFEF; + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_OPT_CFG_REG, tmp2); + } + return 0; } @@ -5620,46 +5725,49 @@ static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy, port_feature_config[params->port]. config)); bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs); if (mod_abs & (1<<8)) { /* Module is absent */ DP(NETIF_MSG_LINK, "MOD_ABS indication " "show module is absent\n"); - /* 1. Set mod_abs to detect next module - presence event - 2. Set EDC off by setting OPTXLOS signal input to low - (bit 9). - When the EDC is off it locks onto a reference clock and - avoids becoming 'lost'.*/ + /* + * 1. Set mod_abs to detect next module + * presence event + * 2. Set EDC off by setting OPTXLOS signal input to low + * (bit 9). + * When the EDC is off it locks onto a reference clock and + * avoids becoming 'lost'. + */ mod_abs &= ~(1<<8); if (!(phy->flags & FLAGS_NOC)) mod_abs &= ~(1<<9); bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs); - /* Clear RX alarm since it stays up as long as - the mod_abs wasn't changed */ + /* + * Clear RX alarm since it stays up as long as + * the mod_abs wasn't changed + */ bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_RX_ALARM, &rx_alarm_status); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_RX_ALARM, &rx_alarm_status); } else { /* Module is present */ DP(NETIF_MSG_LINK, "MOD_ABS indication " "show module is present\n"); - /* First thing, disable transmitter, - and if the module is ok, the - module_detection will enable it*/ - - /* 1. Set mod_abs to detect next module - absent event ( bit 8) - 2. Restore the default polarity of the OPRXLOS signal and - this signal will then correctly indicate the presence or - absence of the Rx signal. (bit 9) */ + /* + * First disable transmitter, and if the module is ok, the + * module_detection will enable it + * 1. Set mod_abs to detect next module absent event ( bit 8) + * 2. Restore the default polarity of the OPRXLOS signal and + * this signal will then correctly indicate the presence or + * absence of the Rx signal. (bit 9) + */ mod_abs |= (1<<8); if (!(phy->flags & FLAGS_NOC)) mod_abs |= (1<<9); @@ -5667,10 +5775,12 @@ static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs); - /* Clear RX alarm since it stays up as long as - the mod_abs wasn't changed. This is need to be done - before calling the module detection, otherwise it will clear - the link update alarm */ + /* + * Clear RX alarm since it stays up as long as the mod_abs + * wasn't changed. This is need to be done before calling the + * module detection, otherwise it will clear* the link update + * alarm + */ bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &rx_alarm_status); @@ -5678,7 +5788,7 @@ static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy, if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) - bnx2x_sfp_set_transmitter(bp, phy, params->port, 0); + bnx2x_sfp_set_transmitter(params, phy, 0); if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0) bnx2x_sfp_module_detection(phy, params); @@ -5687,9 +5797,8 @@ static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy, } DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", - rx_alarm_status); - /* No need to check link status in case of - module plugged in/out */ + rx_alarm_status); + /* No need to check link status in case of module plugged in/out */ } static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy, @@ -5725,7 +5834,7 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy, bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1); - /** + /* * If a module is present and there is need to check * for over current */ @@ -5745,12 +5854,8 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy, " Please remove the SFP+ module and" " restart the system to clear this" " error.\n", - params->port); - - /* - * Disable all RX_ALARMs except for - * mod_abs - */ + params->port); + /* Disable all RX_ALARMs except for mod_abs */ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL, (1<<5)); @@ -5793,11 +5898,15 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_SPEED_LINK_STATUS, &link_status); - /* Bits 0..2 --> speed detected, - bits 13..15--> link is down */ + /* + * Bits 0..2 --> speed detected, + * Bits 13..15--> link is down + */ if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) { link_up = 1; vars->line_speed = SPEED_10000; + DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n", + params->port); } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) { link_up = 1; vars->line_speed = SPEED_1000; @@ -5819,7 +5928,7 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy, bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_GP, &val1); - /** + /* * In case of dual-media board and 1G, power up the XAUI side, * otherwise power it down. For 10G it is done automatically */ @@ -5839,7 +5948,7 @@ static void bnx2x_8727_link_reset(struct bnx2x_phy *phy, { struct bnx2x *bp = params->bp; /* Disable Transmitter */ - bnx2x_sfp_set_transmitter(bp, phy, params->port, 0); + bnx2x_sfp_set_transmitter(params, phy, 0); /* Clear LASI */ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0); @@ -5851,19 +5960,23 @@ static void bnx2x_8727_link_reset(struct bnx2x_phy *phy, static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy, struct link_params *params) { - u16 val, fw_ver1, fw_ver2, cnt; + u16 val, fw_ver1, fw_ver2, cnt, adj; struct bnx2x *bp = params->bp; + adj = 0; + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) + adj = -1; + /* For the 32 bits registers in 848xx, access via MDIO2ARM interface.*/ /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */ - bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014); - bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200); - bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000); - bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300); - bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819 + adj, 0x0014); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A + adj, 0xc200); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B + adj, 0x0000); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C + adj, 0x0300); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817 + adj, 0x0009); for (cnt = 0; cnt < 100; cnt++) { - bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val); + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818 + adj, &val); if (val & 1) break; udelay(5); @@ -5877,11 +5990,11 @@ static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy, /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */ - bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000); - bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200); - bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819 + adj, 0x0000); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A + adj, 0xc200); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817 + adj, 0x000A); for (cnt = 0; cnt < 100; cnt++) { - bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val); + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818 + adj, &val); if (val & 1) break; udelay(5); @@ -5894,9 +6007,9 @@ static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy, } /* lower 16 bits of the register SPI_FW_STATUS */ - bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1); + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B + adj, &fw_ver1); /* upper 16 bits of register SPI_FW_STATUS */ - bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2); + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C + adj, &fw_ver2); bnx2x_save_spirom_version(bp, params->port, (fw_ver2<<16) | fw_ver1, phy->ver_addr); @@ -5905,49 +6018,53 @@ static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy, static void bnx2x_848xx_set_led(struct bnx2x *bp, struct bnx2x_phy *phy) { - u16 val; + u16 val, adj; + + adj = 0; + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) + adj = -1; /* PHYC_CTL_LED_CTL */ bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LINK_SIGNAL, &val); + MDIO_PMA_REG_8481_LINK_SIGNAL + adj, &val); val &= 0xFE00; val |= 0x0092; bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LINK_SIGNAL, val); + MDIO_PMA_REG_8481_LINK_SIGNAL + adj, val); bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED1_MASK, + MDIO_PMA_REG_8481_LED1_MASK + adj, 0x80); bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED2_MASK, + MDIO_PMA_REG_8481_LED2_MASK + adj, 0x18); /* Select activity source by Tx and Rx, as suggested by PHY AE */ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED3_MASK, + MDIO_PMA_REG_8481_LED3_MASK + adj, 0x0006); /* Select the closest activity blink rate to that in 10/100/1000 */ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED3_BLINK, + MDIO_PMA_REG_8481_LED3_BLINK + adj, 0); bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, - MDIO_PMA_REG_84823_CTL_LED_CTL_1, &val); + MDIO_PMA_REG_84823_CTL_LED_CTL_1 + adj, &val); val |= MDIO_PMA_REG_84823_LED3_STRETCH_EN; /* stretch_en for LED3*/ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, - MDIO_PMA_REG_84823_CTL_LED_CTL_1, val); + MDIO_PMA_REG_84823_CTL_LED_CTL_1 + adj, val); /* 'Interrupt Mask' */ bnx2x_cl45_write(bp, phy, @@ -5961,7 +6078,11 @@ static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy, { struct bnx2x *bp = params->bp; u16 autoneg_val, an_1000_val, an_10_100_val; - + /* + * This phy uses the NIG latch mechanism since link indication + * arrives through its LED4 and not via its LASI signal, so we + * get steady signal instead of clear on read + */ bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4, 1 << NIG_LATCH_BC_ENABLE_MI_INT); @@ -6086,11 +6207,11 @@ static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy, struct bnx2x *bp = params->bp; /* Restore normal power mode*/ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, - MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); + MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); /* HW reset */ bnx2x_ext_phy_hw_reset(bp, params->port); - bnx2x_wait_reset_complete(bp, phy); + bnx2x_wait_reset_complete(bp, phy, params); bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15); return bnx2x_848xx_cmn_config_init(phy, params, vars); @@ -6102,12 +6223,15 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy, { struct bnx2x *bp = params->bp; u8 port, initialize = 1; - u16 val; + u16 val, adj; u16 temp; - u32 actual_phy_selection; + u32 actual_phy_selection, cms_enable; u8 rc = 0; /* This is just for MDIO_CTL_REG_84823_MEDIA register. */ + adj = 0; + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) + adj = 3; msleep(1); if (CHIP_IS_E2(bp)) @@ -6117,11 +6241,12 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy, bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3, MISC_REGISTERS_GPIO_OUTPUT_HIGH, port); - bnx2x_wait_reset_complete(bp, phy); + bnx2x_wait_reset_complete(bp, phy, params); /* Wait for GPHY to come out of reset */ msleep(50); - /* BCM84823 requires that XGXS links up first @ 10G for normal - behavior */ + /* + * BCM84823 requires that XGXS links up first @ 10G for normal behavior + */ temp = vars->line_speed; vars->line_speed = SPEED_10000; bnx2x_set_autoneg(¶ms->phy[INT_PHY], params, vars, 0); @@ -6131,7 +6256,7 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy, /* Set dual-media configuration according to configuration */ bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, - MDIO_CTL_REG_84823_MEDIA, &val); + MDIO_CTL_REG_84823_MEDIA + adj, &val); val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK | MDIO_CTL_REG_84823_MEDIA_LINE_MASK | MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN | @@ -6164,7 +6289,7 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy, val |= MDIO_CTL_REG_84823_MEDIA_FIBER_1G; bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, - MDIO_CTL_REG_84823_MEDIA, val); + MDIO_CTL_REG_84823_MEDIA + adj, val); DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n", params->multi_phy_config, val); @@ -6172,23 +6297,43 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy, rc = bnx2x_848xx_cmn_config_init(phy, params, vars); else bnx2x_save_848xx_spirom_version(phy, params); + cms_enable = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[params->port].default_cfg)) & + PORT_HW_CFG_ENABLE_CMS_MASK; + + bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, + MDIO_CTL_REG_84823_USER_CTRL_REG, &val); + if (cms_enable) + val |= MDIO_CTL_REG_84823_USER_CTRL_CMS; + else + val &= ~MDIO_CTL_REG_84823_USER_CTRL_CMS; + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_CTL_REG_84823_USER_CTRL_REG, val); + + return rc; } static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) + struct link_params *params, + struct link_vars *vars) { struct bnx2x *bp = params->bp; - u16 val, val1, val2; + u16 val, val1, val2, adj; u8 link_up = 0; + /* Reg offset adjustment for 84833 */ + adj = 0; + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) + adj = -1; + /* Check 10G-BaseT link status */ /* Check PMD signal ok */ bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, 0xFFFA, &val1); bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL, + MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL + adj, &val2); DP(NETIF_MSG_LINK, "BCM848xx: PMD_SIGNAL 1.a811 = 0x%x\n", val2); @@ -6273,9 +6418,9 @@ static void bnx2x_8481_hw_reset(struct bnx2x_phy *phy, struct link_params *params) { bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_OUTPUT_LOW, 0); + MISC_REGISTERS_GPIO_OUTPUT_LOW, 0); bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_OUTPUT_LOW, 1); + MISC_REGISTERS_GPIO_OUTPUT_LOW, 1); } static void bnx2x_8481_link_reset(struct bnx2x_phy *phy, @@ -6297,8 +6442,8 @@ static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy, else port = params->port; bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3, - MISC_REGISTERS_GPIO_OUTPUT_LOW, - port); + MISC_REGISTERS_GPIO_OUTPUT_LOW, + port); } static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy, @@ -6353,24 +6498,24 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy, /* Set LED masks */ bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED1_MASK, - 0x0); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED1_MASK, + 0x0); bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED2_MASK, - 0x0); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED2_MASK, + 0x0); bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED3_MASK, - 0x0); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED3_MASK, + 0x0); bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED5_MASK, - 0x20); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED5_MASK, + 0x20); } else { bnx2x_cl45_write(bp, phy, @@ -6394,35 +6539,35 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy, val |= 0x2492; bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LINK_SIGNAL, - val); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, + val); /* Set LED masks */ bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED1_MASK, - 0x0); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED1_MASK, + 0x0); bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED2_MASK, - 0x20); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED2_MASK, + 0x20); bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED3_MASK, - 0x20); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED3_MASK, + 0x20); bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED5_MASK, - 0x0); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED5_MASK, + 0x0); } else { bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED1_MASK, - 0x20); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED1_MASK, + 0x20); } break; @@ -6440,9 +6585,9 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy, &val); if (!((val & - MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_MASK) - >> MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_SHIFT)){ - DP(NETIF_MSG_LINK, "Seting LINK_SIGNAL\n"); + MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_MASK) + >> MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_SHIFT)) { + DP(NETIF_MSG_LINK, "Setting LINK_SIGNAL\n"); bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_LINK_SIGNAL, @@ -6451,24 +6596,24 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy, /* Set LED masks */ bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED1_MASK, - 0x10); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED1_MASK, + 0x10); bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED2_MASK, - 0x80); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED2_MASK, + 0x80); bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED3_MASK, - 0x98); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED3_MASK, + 0x98); bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED5_MASK, - 0x40); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED5_MASK, + 0x40); } else { bnx2x_cl45_write(bp, phy, @@ -6513,10 +6658,10 @@ static u8 bnx2x_7101_config_init(struct bnx2x_phy *phy, /* Restore normal power mode*/ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, - MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); + MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); /* HW reset */ bnx2x_ext_phy_hw_reset(bp, params->port); - bnx2x_wait_reset_complete(bp, phy); + bnx2x_wait_reset_complete(bp, phy, params); bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x1); @@ -6563,9 +6708,7 @@ static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy, DP(NETIF_MSG_LINK, "10G-base-T PMA status 0x%x->0x%x\n", val2, val1); link_up = ((val1 & 4) == 4); - /* if link is up - * print the AN outcome of the SFX7101 PHY - */ + /* if link is up print the AN outcome of the SFX7101 PHY */ if (link_up) { bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS, @@ -6599,20 +6742,20 @@ void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy) u16 val, cnt; bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_7101_RESET, &val); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_7101_RESET, &val); for (cnt = 0; cnt < 10; cnt++) { msleep(50); /* Writes a self-clearing reset */ bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_7101_RESET, - (val | (1<<15))); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_7101_RESET, + (val | (1<<15))); /* Wait for clear */ bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_7101_RESET, &val); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_7101_RESET, &val); if ((val & (1<<15)) == 0) break; @@ -6623,10 +6766,10 @@ static void bnx2x_7101_hw_reset(struct bnx2x_phy *phy, struct link_params *params) { /* Low power mode is controlled by GPIO 2 */ bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_2, - MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port); + MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port); /* The PHY reset is controlled by GPIO 1 */ bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port); + MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port); } static void bnx2x_7101_set_link_led(struct bnx2x_phy *phy, @@ -6668,9 +6811,9 @@ static struct bnx2x_phy phy_null = { .supported = 0, .media_type = ETH_PHY_NOT_PRESENT, .ver_addr = 0, - .req_flow_ctrl = 0, - .req_line_speed = 0, - .speed_cap_mask = 0, + .req_flow_ctrl = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, .config_init = (config_init_t)NULL, @@ -6705,8 +6848,8 @@ static struct bnx2x_phy phy_serdes = { .media_type = ETH_PHY_UNSPECIFIED, .ver_addr = 0, .req_flow_ctrl = 0, - .req_line_speed = 0, - .speed_cap_mask = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, .config_init = (config_init_t)bnx2x_init_serdes, @@ -6742,8 +6885,8 @@ static struct bnx2x_phy phy_xgxs = { .media_type = ETH_PHY_UNSPECIFIED, .ver_addr = 0, .req_flow_ctrl = 0, - .req_line_speed = 0, - .speed_cap_mask = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, .config_init = (config_init_t)bnx2x_init_xgxs, @@ -6773,8 +6916,8 @@ static struct bnx2x_phy phy_7101 = { .media_type = ETH_PHY_BASE_T, .ver_addr = 0, .req_flow_ctrl = 0, - .req_line_speed = 0, - .speed_cap_mask = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, .config_init = (config_init_t)bnx2x_7101_config_init, @@ -6804,9 +6947,9 @@ static struct bnx2x_phy phy_8073 = { SUPPORTED_Asym_Pause), .media_type = ETH_PHY_UNSPECIFIED, .ver_addr = 0, - .req_flow_ctrl = 0, - .req_line_speed = 0, - .speed_cap_mask = 0, + .req_flow_ctrl = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, .config_init = (config_init_t)bnx2x_8073_config_init, @@ -7015,6 +7158,43 @@ static struct bnx2x_phy phy_84823 = { .phy_specific_func = (phy_specific_func_t)NULL }; +static struct bnx2x_phy phy_84833 = { + .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833, + .addr = 0xff, + .flags = FLAGS_FAN_FAILURE_DET_REQ | + FLAGS_REARM_LATCH_SIGNAL, + .def_md_devad = 0, + .reserved = 0, + .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .mdio_ctrl = 0, + .supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_10000baseT_Full | + SUPPORTED_TP | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause), + .media_type = ETH_PHY_BASE_T, + .ver_addr = 0, + .req_flow_ctrl = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, + .req_duplex = 0, + .rsrv = 0, + .config_init = (config_init_t)bnx2x_848x3_config_init, + .read_status = (read_status_t)bnx2x_848xx_read_status, + .link_reset = (link_reset_t)bnx2x_848x3_link_reset, + .config_loopback = (config_loopback_t)NULL, + .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, + .hw_reset = (hw_reset_t)NULL, + .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led, + .phy_specific_func = (phy_specific_func_t)NULL +}; + /*****************************************************************/ /* */ /* Populate the phy according. Main function: bnx2x_populate_phy */ @@ -7028,7 +7208,7 @@ static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base, /* Get the 4 lanes xgxs config rx and tx */ u32 rx = 0, tx = 0, i; for (i = 0; i < 2; i++) { - /** + /* * INT_PHY and EXT_PHY1 share the same value location in the * shmem. When num_phys is greater than 1, than this value * applies only to EXT_PHY1 @@ -7036,19 +7216,19 @@ static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base, if (phy_index == INT_PHY || phy_index == EXT_PHY1) { rx = REG_RD(bp, shmem_base + offsetof(struct shmem_region, - dev_info.port_hw_config[port].xgxs_config_rx[i<<1])); + dev_info.port_hw_config[port].xgxs_config_rx[i<<1])); tx = REG_RD(bp, shmem_base + offsetof(struct shmem_region, - dev_info.port_hw_config[port].xgxs_config_tx[i<<1])); + dev_info.port_hw_config[port].xgxs_config_tx[i<<1])); } else { rx = REG_RD(bp, shmem_base + offsetof(struct shmem_region, - dev_info.port_hw_config[port].xgxs_config2_rx[i<<1])); + dev_info.port_hw_config[port].xgxs_config2_rx[i<<1])); tx = REG_RD(bp, shmem_base + offsetof(struct shmem_region, - dev_info.port_hw_config[port].xgxs_config2_rx[i<<1])); + dev_info.port_hw_config[port].xgxs_config2_rx[i<<1])); } phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff); @@ -7168,6 +7348,9 @@ static u8 bnx2x_populate_ext_phy(struct bnx2x *bp, case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823: *phy = phy_84823; break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833: + *phy = phy_84833; + break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: *phy = phy_7101; break; @@ -7182,21 +7365,21 @@ static u8 bnx2x_populate_ext_phy(struct bnx2x *bp, phy->addr = XGXS_EXT_PHY_ADDR(ext_phy_config); bnx2x_populate_preemphasis(bp, shmem_base, phy, port, phy_index); - /** - * The shmem address of the phy version is located on different - * structures. In case this structure is too old, do not set - * the address - */ + /* + * The shmem address of the phy version is located on different + * structures. In case this structure is too old, do not set + * the address + */ config2 = REG_RD(bp, shmem_base + offsetof(struct shmem_region, dev_info.shared_hw_config.config2)); if (phy_index == EXT_PHY1) { phy->ver_addr = shmem_base + offsetof(struct shmem_region, port_mb[port].ext_phy_fw_version); - /* Check specific mdc mdio settings */ - if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK) - mdc_mdio_access = config2 & - SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK; + /* Check specific mdc mdio settings */ + if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK) + mdc_mdio_access = config2 & + SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK; } else { u32 size = REG_RD(bp, shmem2_base); @@ -7215,7 +7398,7 @@ static u8 bnx2x_populate_ext_phy(struct bnx2x *bp, } phy->mdio_ctrl = bnx2x_get_emac_base(bp, mdc_mdio_access, port); - /** + /* * In case mdc/mdio_access of the external phy is different than the * mdc/mdio access of the XGXS, a HW lock must be taken in each access * to prevent one port interfere with another port's CL45 operations. @@ -7250,18 +7433,20 @@ static void bnx2x_phy_def_cfg(struct link_params *params, /* Populate the default phy configuration for MF mode */ if (phy_index == EXT_PHY2) { link_config = REG_RD(bp, params->shmem_base + - offsetof(struct shmem_region, dev_info. + offsetof(struct shmem_region, dev_info. port_feature_config[params->port].link_config2)); phy->speed_cap_mask = REG_RD(bp, params->shmem_base + - offsetof(struct shmem_region, dev_info. + offsetof(struct shmem_region, + dev_info. port_hw_config[params->port].speed_capability_mask2)); } else { link_config = REG_RD(bp, params->shmem_base + - offsetof(struct shmem_region, dev_info. + offsetof(struct shmem_region, dev_info. port_feature_config[params->port].link_config)); phy->speed_cap_mask = REG_RD(bp, params->shmem_base + - offsetof(struct shmem_region, dev_info. - port_hw_config[params->port].speed_capability_mask)); + offsetof(struct shmem_region, + dev_info. + port_hw_config[params->port].speed_capability_mask)); } DP(NETIF_MSG_LINK, "Default config phy idx %x cfg 0x%x speed_cap_mask" " 0x%x\n", phy_index, link_config, phy->speed_cap_mask); @@ -7408,7 +7593,7 @@ static void set_phy_vars(struct link_params *params) else if (phy_index == EXT_PHY2) actual_phy_idx = EXT_PHY1; } - params->phy[actual_phy_idx].req_flow_ctrl = + params->phy[actual_phy_idx].req_flow_ctrl = params->req_flow_ctrl[link_cfg_idx]; params->phy[actual_phy_idx].req_line_speed = @@ -7461,57 +7646,6 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) set_phy_vars(params); DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys); - if (CHIP_REV_IS_FPGA(bp)) { - - vars->link_up = 1; - vars->line_speed = SPEED_10000; - vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; - vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD); - /* enable on E1.5 FPGA */ - if (CHIP_IS_E1H(bp)) { - vars->flow_ctrl |= - (BNX2X_FLOW_CTRL_TX | - BNX2X_FLOW_CTRL_RX); - vars->link_status |= - (LINK_STATUS_TX_FLOW_CONTROL_ENABLED | - LINK_STATUS_RX_FLOW_CONTROL_ENABLED); - } - - bnx2x_emac_enable(params, vars, 0); - if (!(CHIP_IS_E2(bp))) - bnx2x_pbf_update(params, vars->flow_ctrl, - vars->line_speed); - /* disable drain */ - REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); - - /* update shared memory */ - bnx2x_update_mng(params, vars->link_status); - - return 0; - - } else - if (CHIP_REV_IS_EMUL(bp)) { - - vars->link_up = 1; - vars->line_speed = SPEED_10000; - vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; - vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD); - - bnx2x_bmac_enable(params, vars, 0); - - bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed); - /* Disable drain */ - REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE - + params->port*4, 0); - - /* update shared memory */ - bnx2x_update_mng(params, vars->link_status); - - return 0; - - } else if (params->loopback_mode == LOOPBACK_BMAC) { vars->link_up = 1; @@ -7527,8 +7661,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) /* set bmac loopback */ bnx2x_bmac_enable(params, vars, 1); - REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + - params->port*4, 0); + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); } else if (params->loopback_mode == LOOPBACK_EMAC) { @@ -7544,8 +7677,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) /* set bmac loopback */ bnx2x_emac_enable(params, vars, 1); bnx2x_emac_program(params, vars); - REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + - params->port*4, 0); + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); } else if ((params->loopback_mode == LOOPBACK_XGXS) || (params->loopback_mode == LOOPBACK_EXT_PHY)) { @@ -7568,8 +7700,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) bnx2x_emac_program(params, vars); bnx2x_emac_enable(params, vars, 0); } else - bnx2x_bmac_enable(params, vars, 0); - + bnx2x_bmac_enable(params, vars, 0); if (params->loopback_mode == LOOPBACK_XGXS) { /* set 10G XGXS loopback */ params->phy[INT_PHY].config_loopback( @@ -7587,9 +7718,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) params); } } - - REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + - params->port*4, 0); + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed); @@ -7608,7 +7737,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) return 0; } u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, - u8 reset_ext_phy) + u8 reset_ext_phy) { struct bnx2x *bp = params->bp; u8 phy_index, port = params->port, clear_latch_ind = 0; @@ -7617,10 +7746,10 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, vars->link_status = 0; bnx2x_update_mng(params, vars->link_status); bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, - (NIG_MASK_XGXS0_LINK_STATUS | - NIG_MASK_XGXS0_LINK10G | - NIG_MASK_SERDES0_LINK_STATUS | - NIG_MASK_MI_INT)); + (NIG_MASK_XGXS0_LINK_STATUS | + NIG_MASK_XGXS0_LINK10G | + NIG_MASK_SERDES0_LINK_STATUS | + NIG_MASK_MI_INT)); /* activate nig drain */ REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1); @@ -7719,21 +7848,22 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, /* disable attentions */ bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port_of_path*4, - (NIG_MASK_XGXS0_LINK_STATUS | - NIG_MASK_XGXS0_LINK10G | - NIG_MASK_SERDES0_LINK_STATUS | - NIG_MASK_MI_INT)); + (NIG_MASK_XGXS0_LINK_STATUS | + NIG_MASK_XGXS0_LINK10G | + NIG_MASK_SERDES0_LINK_STATUS | + NIG_MASK_MI_INT)); /* Need to take the phy out of low power mode in order to write to access its registers */ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, - MISC_REGISTERS_GPIO_OUTPUT_HIGH, port); + MISC_REGISTERS_GPIO_OUTPUT_HIGH, + port); /* Reset the phy */ bnx2x_cl45_write(bp, &phy[port], - MDIO_PMA_DEVAD, - MDIO_PMA_REG_CTRL, - 1<<15); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, + 1<<15); } /* Add delay of 150ms after reset */ @@ -7762,18 +7892,20 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, /* Only set bit 10 = 1 (Tx power down) */ bnx2x_cl45_read(bp, phy_blk[port], - MDIO_PMA_DEVAD, - MDIO_PMA_REG_TX_POWER_DOWN, &val); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_TX_POWER_DOWN, &val); /* Phase1 of TX_POWER_DOWN reset */ bnx2x_cl45_write(bp, phy_blk[port], - MDIO_PMA_DEVAD, - MDIO_PMA_REG_TX_POWER_DOWN, - (val | 1<<10)); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_TX_POWER_DOWN, + (val | 1<<10)); } - /* Toggle Transmitter: Power down and then up with 600ms - delay between */ + /* + * Toggle Transmitter: Power down and then up with 600ms delay + * between + */ msleep(600); /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */ @@ -7781,25 +7913,25 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, /* Phase2 of POWER_DOWN_RESET */ /* Release bit 10 (Release Tx power down) */ bnx2x_cl45_read(bp, phy_blk[port], - MDIO_PMA_DEVAD, - MDIO_PMA_REG_TX_POWER_DOWN, &val); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_TX_POWER_DOWN, &val); bnx2x_cl45_write(bp, phy_blk[port], - MDIO_PMA_DEVAD, - MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10)))); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10)))); msleep(15); /* Read modify write the SPI-ROM version select register */ bnx2x_cl45_read(bp, phy_blk[port], - MDIO_PMA_DEVAD, - MDIO_PMA_REG_EDC_FFE_MAIN, &val); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_EDC_FFE_MAIN, &val); bnx2x_cl45_write(bp, phy_blk[port], - MDIO_PMA_DEVAD, - MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12))); + MDIO_PMA_DEVAD, + MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12))); /* set GPIO2 back to LOW */ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, - MISC_REGISTERS_GPIO_OUTPUT_LOW, port); + MISC_REGISTERS_GPIO_OUTPUT_LOW, port); } return 0; } @@ -7846,32 +7978,90 @@ static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, /* Set fault module detected LED on */ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, - MISC_REGISTERS_GPIO_HIGH, - port); + MISC_REGISTERS_GPIO_HIGH, + port); } return 0; } +static void bnx2x_get_ext_phy_reset_gpio(struct bnx2x *bp, u32 shmem_base, + u8 *io_gpio, u8 *io_port) +{ + + u32 phy_gpio_reset = REG_RD(bp, shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[PORT_0].default_cfg)); + switch (phy_gpio_reset) { + case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO0_P0: + *io_gpio = 0; + *io_port = 0; + break; + case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO1_P0: + *io_gpio = 1; + *io_port = 0; + break; + case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO2_P0: + *io_gpio = 2; + *io_port = 0; + break; + case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO3_P0: + *io_gpio = 3; + *io_port = 0; + break; + case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO0_P1: + *io_gpio = 0; + *io_port = 1; + break; + case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO1_P1: + *io_gpio = 1; + *io_port = 1; + break; + case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO2_P1: + *io_gpio = 2; + *io_port = 1; + break; + case PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO3_P1: + *io_gpio = 3; + *io_port = 1; + break; + default: + /* Don't override the io_gpio and io_port */ + break; + } +} static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[], u32 shmem2_base_path[], u8 phy_index, u32 chip_id) { - s8 port; + s8 port, reset_gpio; u32 swap_val, swap_override; struct bnx2x_phy phy[PORT_MAX]; struct bnx2x_phy *phy_blk[PORT_MAX]; s8 port_of_path; - swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); - swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); + swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); + swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); + reset_gpio = MISC_REGISTERS_GPIO_1; port = 1; - bnx2x_ext_phy_hw_reset(bp, port ^ (swap_val && swap_override)); + /* + * Retrieve the reset gpio/port which control the reset. + * Default is GPIO1, PORT1 + */ + bnx2x_get_ext_phy_reset_gpio(bp, shmem_base_path[0], + (u8 *)&reset_gpio, (u8 *)&port); /* Calculate the port based on port swap */ port ^= (swap_val && swap_override); + /* Initiate PHY reset*/ + bnx2x_set_gpio(bp, reset_gpio, MISC_REGISTERS_GPIO_OUTPUT_LOW, + port); + msleep(1); + bnx2x_set_gpio(bp, reset_gpio, MISC_REGISTERS_GPIO_OUTPUT_HIGH, + port); + msleep(5); /* PART1 - Reset both phys */ @@ -7907,9 +8097,7 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, /* Reset the phy */ bnx2x_cl45_write(bp, &phy[port], - MDIO_PMA_DEVAD, - MDIO_PMA_REG_CTRL, - 1<<15); + MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15); } /* Add delay of 150ms after reset */ @@ -7923,7 +8111,7 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, } /* PART2 - Download firmware to both phys */ for (port = PORT_MAX - 1; port >= PORT_0; port--) { - if (CHIP_IS_E2(bp)) + if (CHIP_IS_E2(bp)) port_of_path = 0; else port_of_path = port; @@ -7958,8 +8146,10 @@ static u8 bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[], break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: - /* GPIO1 affects both ports, so there's need to pull - it for single port alone */ + /* + * GPIO1 affects both ports, so there's need to pull + * it for single port alone + */ rc = bnx2x_8726_common_init_phy(bp, shmem_base_path, shmem2_base_path, phy_index, chip_id); @@ -7969,11 +8159,15 @@ static u8 bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[], break; default: DP(NETIF_MSG_LINK, - "bnx2x_common_init_phy: ext_phy 0x%x not required\n", - ext_phy_type); + "ext_phy 0x%x common init not required\n", + ext_phy_type); break; } + if (rc != 0) + netdev_err(bp->dev, "Warning: PHY was not initialized," + " Port %d\n", + 0); return rc; } @@ -7986,9 +8180,6 @@ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[], u32 ext_phy_type, ext_phy_config; DP(NETIF_MSG_LINK, "Begin common phy init\n"); - if (CHIP_REV_IS_EMUL(bp)) - return 0; - /* Check if common init was already done */ phy_ver = REG_RD(bp, shmem_base_path[0] + offsetof(struct shmem_region, diff --git a/drivers/net/bnx2x/bnx2x_link.h b/drivers/net/bnx2x/bnx2x_link.h index bedab1a942c4..92f36b6950dc 100644 --- a/drivers/net/bnx2x/bnx2x_link.h +++ b/drivers/net/bnx2x/bnx2x_link.h @@ -1,4 +1,4 @@ -/* Copyright 2008-2010 Broadcom Corporation +/* Copyright 2008-2011 Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -33,7 +33,7 @@ #define BNX2X_FLOW_CTRL_BOTH PORT_FEATURE_FLOW_CONTROL_BOTH #define BNX2X_FLOW_CTRL_NONE PORT_FEATURE_FLOW_CONTROL_NONE -#define SPEED_AUTO_NEG 0 +#define SPEED_AUTO_NEG 0 #define SPEED_12000 12000 #define SPEED_12500 12500 #define SPEED_13000 13000 @@ -44,8 +44,8 @@ #define SFP_EEPROM_VENDOR_NAME_SIZE 16 #define SFP_EEPROM_VENDOR_OUI_ADDR 0x25 #define SFP_EEPROM_VENDOR_OUI_SIZE 3 -#define SFP_EEPROM_PART_NO_ADDR 0x28 -#define SFP_EEPROM_PART_NO_SIZE 16 +#define SFP_EEPROM_PART_NO_ADDR 0x28 +#define SFP_EEPROM_PART_NO_SIZE 16 #define PWR_FLT_ERR_MSG_LEN 250 #define XGXS_EXT_PHY_TYPE(ext_phy_config) \ @@ -62,7 +62,7 @@ #define SINGLE_MEDIA(params) (params->num_phys == 2) /* Dual Media board contains two external phy with different media */ #define DUAL_MEDIA(params) (params->num_phys == 3) -#define FW_PARAM_MDIO_CTRL_OFFSET 16 +#define FW_PARAM_MDIO_CTRL_OFFSET 16 #define FW_PARAM_SET(phy_addr, phy_type, mdio_access) \ (phy_addr | phy_type | mdio_access << FW_PARAM_MDIO_CTRL_OFFSET) @@ -201,12 +201,14 @@ struct link_params { /* Default / User Configuration */ u8 loopback_mode; -#define LOOPBACK_NONE 0 -#define LOOPBACK_EMAC 1 -#define LOOPBACK_BMAC 2 +#define LOOPBACK_NONE 0 +#define LOOPBACK_EMAC 1 +#define LOOPBACK_BMAC 2 #define LOOPBACK_XGXS 3 #define LOOPBACK_EXT_PHY 4 -#define LOOPBACK_EXT 5 +#define LOOPBACK_EXT 5 +#define LOOPBACK_UMAC 6 +#define LOOPBACK_XMAC 7 /* Device parameters */ u8 mac_addr[6]; @@ -230,10 +232,11 @@ struct link_params { /* Phy register parameter */ u32 chip_id; + /* features */ u32 feature_config_flags; -#define FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED (1<<0) -#define FEATURE_CONFIG_PFC_ENABLED (1<<1) -#define FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY (1<<2) +#define FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED (1<<0) +#define FEATURE_CONFIG_PFC_ENABLED (1<<1) +#define FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY (1<<2) #define FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY (1<<3) /* Will be populated during common init */ struct bnx2x_phy phy[MAX_PHYS]; @@ -334,6 +337,11 @@ void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port); /* Reset the external of SFX7101 */ void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy); +/* Read "byte_cnt" bytes from address "addr" from the SFP+ EEPROM */ +u8 bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy, + struct link_params *params, u16 addr, + u8 byte_cnt, u8 *o_buf); + void bnx2x_hw_reset_phy(struct link_params *params); /* Checks if HW lock is required for this phy/board type */ @@ -379,7 +387,7 @@ void bnx2x_ets_disabled(struct link_params *params); /* Used to configure the ETS to BW limited */ void bnx2x_ets_bw_limit(const struct link_params *params, const u32 cos0_bw, - const u32 cos1_bw); + const u32 cos1_bw); /* Used to configure the ETS to strict */ u8 bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos); diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index d584d32c747d..6c7745eee00d 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -586,7 +586,7 @@ static int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]); /* lock the dmae channel */ - mutex_lock(&bp->dmae_mutex); + spin_lock_bh(&bp->dmae_lock); /* reset completion */ *wb_comp = 0; @@ -617,7 +617,7 @@ static int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]); unlock: - mutex_unlock(&bp->dmae_mutex); + spin_unlock_bh(&bp->dmae_lock); return rc; } @@ -1397,7 +1397,7 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, } smp_mb__before_atomic_inc(); - atomic_inc(&bp->spq_left); + atomic_inc(&bp->cq_spq_left); /* push the change in fp->state and towards the memory */ smp_wmb(); @@ -2473,8 +2473,14 @@ static void bnx2x_pf_rx_cl_prep(struct bnx2x *bp, rxq_init->sge_map = fp->rx_sge_mapping; rxq_init->rcq_map = fp->rx_comp_mapping; rxq_init->rcq_np_map = fp->rx_comp_mapping + BCM_PAGE_SIZE; - rxq_init->mtu = bp->dev->mtu; - rxq_init->buf_sz = bp->rx_buf_size; + + /* Always use mini-jumbo MTU for FCoE L2 ring */ + if (IS_FCOE_FP(fp)) + rxq_init->mtu = BNX2X_FCOE_MINI_JUMBO_MTU; + else + rxq_init->mtu = bp->dev->mtu; + + rxq_init->buf_sz = fp->rx_buf_size; rxq_init->cl_qzone_id = fp->cl_qzone_id; rxq_init->cl_id = fp->cl_id; rxq_init->spcl_id = fp->cl_id; @@ -2726,11 +2732,18 @@ int bnx2x_sp_post(struct bnx2x *bp, int command, int cid, spin_lock_bh(&bp->spq_lock); - if (!atomic_read(&bp->spq_left)) { - BNX2X_ERR("BUG! SPQ ring full!\n"); - spin_unlock_bh(&bp->spq_lock); - bnx2x_panic(); - return -EBUSY; + if (common) { + if (!atomic_read(&bp->eq_spq_left)) { + BNX2X_ERR("BUG! EQ ring full!\n"); + spin_unlock_bh(&bp->spq_lock); + bnx2x_panic(); + return -EBUSY; + } + } else if (!atomic_read(&bp->cq_spq_left)) { + BNX2X_ERR("BUG! SPQ ring full!\n"); + spin_unlock_bh(&bp->spq_lock); + bnx2x_panic(); + return -EBUSY; } spe = bnx2x_sp_get_next(bp); @@ -2761,20 +2774,26 @@ int bnx2x_sp_post(struct bnx2x *bp, int command, int cid, spe->data.update_data_addr.lo = cpu_to_le32(data_lo); /* stats ramrod has it's own slot on the spq */ - if (command != RAMROD_CMD_ID_COMMON_STAT_QUERY) + if (command != RAMROD_CMD_ID_COMMON_STAT_QUERY) { /* It's ok if the actual decrement is issued towards the memory * somewhere between the spin_lock and spin_unlock. Thus no * more explict memory barrier is needed. */ - atomic_dec(&bp->spq_left); + if (common) + atomic_dec(&bp->eq_spq_left); + else + atomic_dec(&bp->cq_spq_left); + } + DP(BNX2X_MSG_SP/*NETIF_MSG_TIMER*/, "SPQE[%x] (%x:%x) command %d hw_cid %x data (%x:%x) " - "type(0x%x) left %x\n", + "type(0x%x) left (ETH, COMMON) (%x,%x)\n", bp->spq_prod_idx, (u32)U64_HI(bp->spq_mapping), (u32)(U64_LO(bp->spq_mapping) + (void *)bp->spq_prod_bd - (void *)bp->spq), command, - HW_CID(bp, cid), data_hi, data_lo, type, atomic_read(&bp->spq_left)); + HW_CID(bp, cid), data_hi, data_lo, type, + atomic_read(&bp->cq_spq_left), atomic_read(&bp->eq_spq_left)); bnx2x_sp_prod_update(bp); spin_unlock_bh(&bp->spq_lock); @@ -3686,8 +3705,8 @@ static void bnx2x_eq_int(struct bnx2x *bp) sw_cons = bp->eq_cons; sw_prod = bp->eq_prod; - DP(BNX2X_MSG_SP, "EQ: hw_cons %u sw_cons %u bp->spq_left %u\n", - hw_cons, sw_cons, atomic_read(&bp->spq_left)); + DP(BNX2X_MSG_SP, "EQ: hw_cons %u sw_cons %u bp->cq_spq_left %u\n", + hw_cons, sw_cons, atomic_read(&bp->eq_spq_left)); for (; sw_cons != hw_cons; sw_prod = NEXT_EQ_IDX(sw_prod), sw_cons = NEXT_EQ_IDX(sw_cons)) { @@ -3752,13 +3771,15 @@ static void bnx2x_eq_int(struct bnx2x *bp) case (EVENT_RING_OPCODE_SET_MAC | BNX2X_STATE_OPEN): case (EVENT_RING_OPCODE_SET_MAC | BNX2X_STATE_DIAG): DP(NETIF_MSG_IFUP, "got set mac ramrod\n"); - bp->set_mac_pending = 0; + if (elem->message.data.set_mac_event.echo) + bp->set_mac_pending = 0; break; case (EVENT_RING_OPCODE_SET_MAC | BNX2X_STATE_CLOSING_WAIT4_HALT): DP(NETIF_MSG_IFDOWN, "got (un)set mac ramrod\n"); - bp->set_mac_pending = 0; + if (elem->message.data.set_mac_event.echo) + bp->set_mac_pending = 0; break; default: /* unknown event log error and continue */ @@ -3770,7 +3791,7 @@ next_spqe: } /* for */ smp_mb__before_atomic_inc(); - atomic_add(spqe_cnt, &bp->spq_left); + atomic_add(spqe_cnt, &bp->eq_spq_left); bp->eq_cons = sw_cons; bp->eq_prod = sw_prod; @@ -4203,7 +4224,7 @@ void bnx2x_update_coalesce(struct bnx2x *bp) static void bnx2x_init_sp_ring(struct bnx2x *bp) { spin_lock_init(&bp->spq_lock); - atomic_set(&bp->spq_left, MAX_SPQ_PENDING); + atomic_set(&bp->cq_spq_left, MAX_SPQ_PENDING); bp->spq_prod_idx = 0; bp->dsb_sp_prod = BNX2X_SP_DSB_INDEX; @@ -4228,9 +4249,12 @@ static void bnx2x_init_eq_ring(struct bnx2x *bp) bp->eq_cons = 0; bp->eq_prod = NUM_EQ_DESC; bp->eq_cons_sb = BNX2X_EQ_INDEX; + /* we want a warning message before it gets rought... */ + atomic_set(&bp->eq_spq_left, + min_t(int, MAX_SP_DESC_CNT - MAX_SPQ_PENDING, NUM_EQ_DESC) - 1); } -static void bnx2x_init_ind_table(struct bnx2x *bp) +void bnx2x_push_indir_table(struct bnx2x *bp) { int func = BP_FUNC(bp); int i; @@ -4238,13 +4262,20 @@ static void bnx2x_init_ind_table(struct bnx2x *bp) if (bp->multi_mode == ETH_RSS_MODE_DISABLED) return; - DP(NETIF_MSG_IFUP, - "Initializing indirection table multi_mode %d\n", bp->multi_mode); for (i = 0; i < TSTORM_INDIRECTION_TABLE_SIZE; i++) REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_INDIRECTION_TABLE_OFFSET(func) + i, - bp->fp->cl_id + (i % (bp->num_queues - - NONE_ETH_CONTEXT_USE))); + bp->fp->cl_id + bp->rx_indir_table[i]); +} + +static void bnx2x_init_ind_table(struct bnx2x *bp) +{ + int i; + + for (i = 0; i < TSTORM_INDIRECTION_TABLE_SIZE; i++) + bp->rx_indir_table[i] = i % BNX2X_NUM_ETH_QUEUES(bp); + + bnx2x_push_indir_table(bp); } void bnx2x_set_storm_rx_mode(struct bnx2x *bp) @@ -5840,7 +5871,7 @@ int bnx2x_init_hw(struct bnx2x *bp, u32 load_code) BP_ABS_FUNC(bp), load_code); bp->dmae_ready = 0; - mutex_init(&bp->dmae_mutex); + spin_lock_init(&bp->dmae_lock); rc = bnx2x_gunzip_init(bp); if (rc) return rc; @@ -5992,6 +6023,8 @@ void bnx2x_free_mem(struct bnx2x *bp) BNX2X_PCI_FREE(bp->eq_ring, bp->eq_mapping, BCM_PAGE_SIZE * NUM_EQ_PAGES); + BNX2X_FREE(bp->rx_indir_table); + #undef BNX2X_PCI_FREE #undef BNX2X_KFREE } @@ -6122,6 +6155,9 @@ int bnx2x_alloc_mem(struct bnx2x *bp) /* EQ */ BNX2X_PCI_ALLOC(bp->eq_ring, &bp->eq_mapping, BCM_PAGE_SIZE * NUM_EQ_PAGES); + + BNX2X_ALLOC(bp->rx_indir_table, sizeof(bp->rx_indir_table[0]) * + TSTORM_INDIRECTION_TABLE_SIZE); return 0; alloc_mem_err: @@ -6175,12 +6211,14 @@ static void bnx2x_set_mac_addr_gen(struct bnx2x *bp, int set, const u8 *mac, int ramrod_flags = WAIT_RAMROD_COMMON; bp->set_mac_pending = 1; - smp_wmb(); config->hdr.length = 1; config->hdr.offset = cam_offset; config->hdr.client_id = 0xff; - config->hdr.reserved1 = 0; + /* Mark the single MAC configuration ramrod as opposed to a + * UC/MC list configuration). + */ + config->hdr.echo = 1; /* primary MAC */ config->config_table[0].msb_mac_addr = @@ -6212,6 +6250,8 @@ static void bnx2x_set_mac_addr_gen(struct bnx2x *bp, int set, const u8 *mac, config->config_table[0].middle_mac_addr, config->config_table[0].lsb_mac_addr, BP_FUNC(bp), cl_bit_vec); + mb(); + bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_SET_MAC, 0, U64_HI(bnx2x_sp_mapping(bp, mac_config)), U64_LO(bnx2x_sp_mapping(bp, mac_config)), 1); @@ -6276,20 +6316,15 @@ static u8 bnx2x_e1h_cam_offset(struct bnx2x *bp, u8 rel_offset) if (CHIP_IS_E1H(bp)) return E1H_FUNC_MAX * rel_offset + BP_FUNC(bp); else if (CHIP_MODE_IS_4_PORT(bp)) - return BP_FUNC(bp) * 32 + rel_offset; + return E2_FUNC_MAX * rel_offset + BP_FUNC(bp); else - return BP_VN(bp) * 32 + rel_offset; + return E2_FUNC_MAX * rel_offset + BP_VN(bp); } /** * LLH CAM line allocations: currently only iSCSI and ETH macs are * relevant. In addition, current implementation is tuned for a * single ETH MAC. - * - * When multiple unicast ETH MACs PF configuration in switch - * independent mode is required (NetQ, multiple netdev MACs, - * etc.), consider better utilisation of 16 per function MAC - * entries in the LLH memory. */ enum { LLH_CAM_ISCSI_ETH_LINE = 0, @@ -6364,14 +6399,37 @@ void bnx2x_set_eth_mac(struct bnx2x *bp, int set) bnx2x_set_mac_addr_gen(bp, set, bcast, 0, cam_offset + 1, 1); } } -static void bnx2x_set_e1_mc_list(struct bnx2x *bp, u8 offset) + +static inline u8 bnx2x_e1_cam_mc_offset(struct bnx2x *bp) +{ + return CHIP_REV_IS_SLOW(bp) ? + (BNX2X_MAX_EMUL_MULTI * (1 + BP_PORT(bp))) : + (BNX2X_MAX_MULTICAST * (1 + BP_PORT(bp))); +} + +/* set mc list, do not wait as wait implies sleep and + * set_rx_mode can be invoked from non-sleepable context. + * + * Instead we use the same ramrod data buffer each time we need + * to configure a list of addresses, and use the fact that the + * list of MACs is changed in an incremental way and that the + * function is called under the netif_addr_lock. A temporary + * inconsistent CAM configuration (possible in case of a very fast + * sequence of add/del/add on the host side) will shortly be + * restored by the handler of the last ramrod. + */ +static int bnx2x_set_e1_mc_list(struct bnx2x *bp) { int i = 0, old; struct net_device *dev = bp->dev; + u8 offset = bnx2x_e1_cam_mc_offset(bp); struct netdev_hw_addr *ha; struct mac_configuration_cmd *config_cmd = bnx2x_sp(bp, mcast_config); dma_addr_t config_cmd_map = bnx2x_sp_mapping(bp, mcast_config); + if (netdev_mc_count(dev) > BNX2X_MAX_MULTICAST) + return -EINVAL; + netdev_for_each_mc_addr(ha, dev) { /* copy mac */ config_cmd->config_table[i].msb_mac_addr = @@ -6412,32 +6470,47 @@ static void bnx2x_set_e1_mc_list(struct bnx2x *bp, u8 offset) } } + wmb(); + config_cmd->hdr.length = i; config_cmd->hdr.offset = offset; config_cmd->hdr.client_id = 0xff; - config_cmd->hdr.reserved1 = 0; + /* Mark that this ramrod doesn't use bp->set_mac_pending for + * synchronization. + */ + config_cmd->hdr.echo = 0; - bp->set_mac_pending = 1; - smp_wmb(); + mb(); - bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_SET_MAC, 0, + return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_SET_MAC, 0, U64_HI(config_cmd_map), U64_LO(config_cmd_map), 1); } -static void bnx2x_invlidate_e1_mc_list(struct bnx2x *bp) + +void bnx2x_invalidate_e1_mc_list(struct bnx2x *bp) { int i; struct mac_configuration_cmd *config_cmd = bnx2x_sp(bp, mcast_config); dma_addr_t config_cmd_map = bnx2x_sp_mapping(bp, mcast_config); int ramrod_flags = WAIT_RAMROD_COMMON; + u8 offset = bnx2x_e1_cam_mc_offset(bp); - bp->set_mac_pending = 1; - smp_wmb(); - - for (i = 0; i < config_cmd->hdr.length; i++) + for (i = 0; i < BNX2X_MAX_MULTICAST; i++) SET_FLAG(config_cmd->config_table[i].flags, MAC_CONFIGURATION_ENTRY_ACTION_TYPE, T_ETH_MAC_COMMAND_INVALIDATE); + wmb(); + + config_cmd->hdr.length = BNX2X_MAX_MULTICAST; + config_cmd->hdr.offset = offset; + config_cmd->hdr.client_id = 0xff; + /* We'll wait for a completion this time... */ + config_cmd->hdr.echo = 1; + + bp->set_mac_pending = 1; + + mb(); + bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_SET_MAC, 0, U64_HI(config_cmd_map), U64_LO(config_cmd_map), 1); @@ -6447,6 +6520,44 @@ static void bnx2x_invlidate_e1_mc_list(struct bnx2x *bp) } +/* Accept one or more multicasts */ +static int bnx2x_set_e1h_mc_list(struct bnx2x *bp) +{ + struct net_device *dev = bp->dev; + struct netdev_hw_addr *ha; + u32 mc_filter[MC_HASH_SIZE]; + u32 crc, bit, regidx; + int i; + + memset(mc_filter, 0, 4 * MC_HASH_SIZE); + + netdev_for_each_mc_addr(ha, dev) { + DP(NETIF_MSG_IFUP, "Adding mcast MAC: %pM\n", + bnx2x_mc_addr(ha)); + + crc = crc32c_le(0, bnx2x_mc_addr(ha), + ETH_ALEN); + bit = (crc >> 24) & 0xff; + regidx = bit >> 5; + bit &= 0x1f; + mc_filter[regidx] |= (1 << bit); + } + + for (i = 0; i < MC_HASH_SIZE; i++) + REG_WR(bp, MC_HASH_OFFSET(bp, i), + mc_filter[i]); + + return 0; +} + +void bnx2x_invalidate_e1h_mc_list(struct bnx2x *bp) +{ + int i; + + for (i = 0; i < MC_HASH_SIZE; i++) + REG_WR(bp, MC_HASH_OFFSET(bp, i), 0); +} + #ifdef BCM_CNIC /** * Set iSCSI MAC(s) at the next enties in the CAM after the ETH @@ -6465,12 +6576,13 @@ static int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set) u32 iscsi_l2_cl_id = BNX2X_ISCSI_ETH_CL_ID + BP_E1HVN(bp) * NONE_ETH_CONTEXT_USE; u32 cl_bit_vec = (1 << iscsi_l2_cl_id); + u8 *iscsi_mac = bp->cnic_eth_dev.iscsi_mac; /* Send a SET_MAC ramrod */ - bnx2x_set_mac_addr_gen(bp, set, bp->iscsi_mac, cl_bit_vec, + bnx2x_set_mac_addr_gen(bp, set, iscsi_mac, cl_bit_vec, cam_offset, 0); - bnx2x_set_mac_in_nig(bp, set, bp->iscsi_mac, LLH_CAM_ISCSI_ETH_LINE); + bnx2x_set_mac_in_nig(bp, set, iscsi_mac, LLH_CAM_ISCSI_ETH_LINE); return 0; } @@ -7112,20 +7224,15 @@ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode) /* Give HW time to discard old tx messages */ msleep(1); - if (CHIP_IS_E1(bp)) { - /* invalidate mc list, - * wait and poll (interrupts are off) - */ - bnx2x_invlidate_e1_mc_list(bp); - bnx2x_set_eth_mac(bp, 0); - - } else { - REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 0); + bnx2x_set_eth_mac(bp, 0); - bnx2x_set_eth_mac(bp, 0); + bnx2x_invalidate_uc_list(bp); - for (i = 0; i < MC_HASH_SIZE; i++) - REG_WR(bp, MC_HASH_OFFSET(bp, i), 0); + if (CHIP_IS_E1(bp)) + bnx2x_invalidate_e1_mc_list(bp); + else { + bnx2x_invalidate_e1h_mc_list(bp); + REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 0); } #ifdef BCM_CNIC @@ -8394,11 +8501,47 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) bp->common.shmem2_base); } +#ifdef BCM_CNIC +static void __devinit bnx2x_get_cnic_info(struct bnx2x *bp) +{ + u32 max_iscsi_conn = FW_ENCODE_32BIT_PATTERN ^ SHMEM_RD(bp, + drv_lic_key[BP_PORT(bp)].max_iscsi_conn); + u32 max_fcoe_conn = FW_ENCODE_32BIT_PATTERN ^ SHMEM_RD(bp, + drv_lic_key[BP_PORT(bp)].max_fcoe_conn); + + /* Get the number of maximum allowed iSCSI and FCoE connections */ + bp->cnic_eth_dev.max_iscsi_conn = + (max_iscsi_conn & BNX2X_MAX_ISCSI_INIT_CONN_MASK) >> + BNX2X_MAX_ISCSI_INIT_CONN_SHIFT; + + bp->cnic_eth_dev.max_fcoe_conn = + (max_fcoe_conn & BNX2X_MAX_FCOE_INIT_CONN_MASK) >> + BNX2X_MAX_FCOE_INIT_CONN_SHIFT; + + BNX2X_DEV_INFO("max_iscsi_conn 0x%x max_fcoe_conn 0x%x\n", + bp->cnic_eth_dev.max_iscsi_conn, + bp->cnic_eth_dev.max_fcoe_conn); + + /* If mamimum allowed number of connections is zero - + * disable the feature. + */ + if (!bp->cnic_eth_dev.max_iscsi_conn) + bp->flags |= NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG; + + if (!bp->cnic_eth_dev.max_fcoe_conn) + bp->flags |= NO_FCOE_FLAG; +} +#endif + static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp) { u32 val, val2; int func = BP_ABS_FUNC(bp); int port = BP_PORT(bp); +#ifdef BCM_CNIC + u8 *iscsi_mac = bp->cnic_eth_dev.iscsi_mac; + u8 *fip_mac = bp->fip_mac; +#endif if (BP_NOMCP(bp)) { BNX2X_ERROR("warning: random MAC workaround active\n"); @@ -8411,7 +8554,9 @@ static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp) bnx2x_set_mac_buf(bp->dev->dev_addr, val, val2); #ifdef BCM_CNIC - /* iSCSI NPAR MAC */ + /* iSCSI and FCoE NPAR MACs: if there is no either iSCSI or + * FCoE MAC then the appropriate feature should be disabled. + */ if (IS_MF_SI(bp)) { u32 cfg = MF_CFG_RD(bp, func_ext_config[func].func_cfg); if (cfg & MACP_FUNC_CFG_FLAGS_ISCSI_OFFLOAD) { @@ -8419,8 +8564,39 @@ static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp) iscsi_mac_addr_upper); val = MF_CFG_RD(bp, func_ext_config[func]. iscsi_mac_addr_lower); - bnx2x_set_mac_buf(bp->iscsi_mac, val, val2); - } + BNX2X_DEV_INFO("Read iSCSI MAC: " + "0x%x:0x%04x\n", val2, val); + bnx2x_set_mac_buf(iscsi_mac, val, val2); + + /* Disable iSCSI OOO if MAC configuration is + * invalid. + */ + if (!is_valid_ether_addr(iscsi_mac)) { + bp->flags |= NO_ISCSI_OOO_FLAG | + NO_ISCSI_FLAG; + memset(iscsi_mac, 0, ETH_ALEN); + } + } else + bp->flags |= NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG; + + if (cfg & MACP_FUNC_CFG_FLAGS_FCOE_OFFLOAD) { + val2 = MF_CFG_RD(bp, func_ext_config[func]. + fcoe_mac_addr_upper); + val = MF_CFG_RD(bp, func_ext_config[func]. + fcoe_mac_addr_lower); + BNX2X_DEV_INFO("Read FCoE MAC to " + "0x%x:0x%04x\n", val2, val); + bnx2x_set_mac_buf(fip_mac, val, val2); + + /* Disable FCoE if MAC configuration is + * invalid. + */ + if (!is_valid_ether_addr(fip_mac)) { + bp->flags |= NO_FCOE_FLAG; + memset(bp->fip_mac, 0, ETH_ALEN); + } + } else + bp->flags |= NO_FCOE_FLAG; } #endif } else { @@ -8434,7 +8610,7 @@ static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp) iscsi_mac_upper); val = SHMEM_RD(bp, dev_info.port_hw_config[port]. iscsi_mac_lower); - bnx2x_set_mac_buf(bp->iscsi_mac, val, val2); + bnx2x_set_mac_buf(iscsi_mac, val, val2); #endif } @@ -8442,14 +8618,12 @@ static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp) memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN); #ifdef BCM_CNIC - /* Inform the upper layers about FCoE MAC */ + /* Set the FCoE MAC in modes other then MF_SI */ if (!CHIP_IS_E1x(bp)) { if (IS_MF_SD(bp)) - memcpy(bp->fip_mac, bp->dev->dev_addr, - sizeof(bp->fip_mac)); - else - memcpy(bp->fip_mac, bp->iscsi_mac, - sizeof(bp->fip_mac)); + memcpy(fip_mac, bp->dev->dev_addr, ETH_ALEN); + else if (!IS_MF(bp)) + memcpy(fip_mac, iscsi_mac, ETH_ALEN); } #endif } @@ -8612,6 +8786,10 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) /* Get MAC addresses */ bnx2x_get_mac_hwinfo(bp); +#ifdef BCM_CNIC + bnx2x_get_cnic_info(bp); +#endif + return rc; } @@ -8826,12 +9004,197 @@ static int bnx2x_close(struct net_device *dev) return 0; } +#define E1_MAX_UC_LIST 29 +#define E1H_MAX_UC_LIST 30 +#define E2_MAX_UC_LIST 14 +static inline u8 bnx2x_max_uc_list(struct bnx2x *bp) +{ + if (CHIP_IS_E1(bp)) + return E1_MAX_UC_LIST; + else if (CHIP_IS_E1H(bp)) + return E1H_MAX_UC_LIST; + else + return E2_MAX_UC_LIST; +} + + +static inline u8 bnx2x_uc_list_cam_offset(struct bnx2x *bp) +{ + if (CHIP_IS_E1(bp)) + /* CAM Entries for Port0: + * 0 - prim ETH MAC + * 1 - BCAST MAC + * 2 - iSCSI L2 ring ETH MAC + * 3-31 - UC MACs + * + * Port1 entries are allocated the same way starting from + * entry 32. + */ + return 3 + 32 * BP_PORT(bp); + else if (CHIP_IS_E1H(bp)) { + /* CAM Entries: + * 0-7 - prim ETH MAC for each function + * 8-15 - iSCSI L2 ring ETH MAC for each function + * 16 till 255 UC MAC lists for each function + * + * Remark: There is no FCoE support for E1H, thus FCoE related + * MACs are not considered. + */ + return E1H_FUNC_MAX * (CAM_ISCSI_ETH_LINE + 1) + + bnx2x_max_uc_list(bp) * BP_FUNC(bp); + } else { + /* CAM Entries (there is a separate CAM per engine): + * 0-4 - prim ETH MAC for each function + * 4-7 - iSCSI L2 ring ETH MAC for each function + * 8-11 - FIP ucast L2 MAC for each function + * 12-15 - ALL_ENODE_MACS mcast MAC for each function + * 16 till 71 UC MAC lists for each function + */ + u8 func_idx = + (CHIP_MODE_IS_4_PORT(bp) ? BP_FUNC(bp) : BP_VN(bp)); + + return E2_FUNC_MAX * (CAM_MAX_PF_LINE + 1) + + bnx2x_max_uc_list(bp) * func_idx; + } +} + +/* set uc list, do not wait as wait implies sleep and + * set_rx_mode can be invoked from non-sleepable context. + * + * Instead we use the same ramrod data buffer each time we need + * to configure a list of addresses, and use the fact that the + * list of MACs is changed in an incremental way and that the + * function is called under the netif_addr_lock. A temporary + * inconsistent CAM configuration (possible in case of very fast + * sequence of add/del/add on the host side) will shortly be + * restored by the handler of the last ramrod. + */ +static int bnx2x_set_uc_list(struct bnx2x *bp) +{ + int i = 0, old; + struct net_device *dev = bp->dev; + u8 offset = bnx2x_uc_list_cam_offset(bp); + struct netdev_hw_addr *ha; + struct mac_configuration_cmd *config_cmd = bnx2x_sp(bp, uc_mac_config); + dma_addr_t config_cmd_map = bnx2x_sp_mapping(bp, uc_mac_config); + + if (netdev_uc_count(dev) > bnx2x_max_uc_list(bp)) + return -EINVAL; + + netdev_for_each_uc_addr(ha, dev) { + /* copy mac */ + config_cmd->config_table[i].msb_mac_addr = + swab16(*(u16 *)&bnx2x_uc_addr(ha)[0]); + config_cmd->config_table[i].middle_mac_addr = + swab16(*(u16 *)&bnx2x_uc_addr(ha)[2]); + config_cmd->config_table[i].lsb_mac_addr = + swab16(*(u16 *)&bnx2x_uc_addr(ha)[4]); + + config_cmd->config_table[i].vlan_id = 0; + config_cmd->config_table[i].pf_id = BP_FUNC(bp); + config_cmd->config_table[i].clients_bit_vector = + cpu_to_le32(1 << BP_L_ID(bp)); + + SET_FLAG(config_cmd->config_table[i].flags, + MAC_CONFIGURATION_ENTRY_ACTION_TYPE, + T_ETH_MAC_COMMAND_SET); + + DP(NETIF_MSG_IFUP, + "setting UCAST[%d] (%04x:%04x:%04x)\n", i, + config_cmd->config_table[i].msb_mac_addr, + config_cmd->config_table[i].middle_mac_addr, + config_cmd->config_table[i].lsb_mac_addr); + + i++; + + /* Set uc MAC in NIG */ + bnx2x_set_mac_in_nig(bp, 1, bnx2x_uc_addr(ha), + LLH_CAM_ETH_LINE + i); + } + old = config_cmd->hdr.length; + if (old > i) { + for (; i < old; i++) { + if (CAM_IS_INVALID(config_cmd-> + config_table[i])) { + /* already invalidated */ + break; + } + /* invalidate */ + SET_FLAG(config_cmd->config_table[i].flags, + MAC_CONFIGURATION_ENTRY_ACTION_TYPE, + T_ETH_MAC_COMMAND_INVALIDATE); + } + } + + wmb(); + + config_cmd->hdr.length = i; + config_cmd->hdr.offset = offset; + config_cmd->hdr.client_id = 0xff; + /* Mark that this ramrod doesn't use bp->set_mac_pending for + * synchronization. + */ + config_cmd->hdr.echo = 0; + + mb(); + + return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_SET_MAC, 0, + U64_HI(config_cmd_map), U64_LO(config_cmd_map), 1); + +} + +void bnx2x_invalidate_uc_list(struct bnx2x *bp) +{ + int i; + struct mac_configuration_cmd *config_cmd = bnx2x_sp(bp, uc_mac_config); + dma_addr_t config_cmd_map = bnx2x_sp_mapping(bp, uc_mac_config); + int ramrod_flags = WAIT_RAMROD_COMMON; + u8 offset = bnx2x_uc_list_cam_offset(bp); + u8 max_list_size = bnx2x_max_uc_list(bp); + + for (i = 0; i < max_list_size; i++) { + SET_FLAG(config_cmd->config_table[i].flags, + MAC_CONFIGURATION_ENTRY_ACTION_TYPE, + T_ETH_MAC_COMMAND_INVALIDATE); + bnx2x_set_mac_in_nig(bp, 0, NULL, LLH_CAM_ETH_LINE + 1 + i); + } + + wmb(); + + config_cmd->hdr.length = max_list_size; + config_cmd->hdr.offset = offset; + config_cmd->hdr.client_id = 0xff; + /* We'll wait for a completion this time... */ + config_cmd->hdr.echo = 1; + + bp->set_mac_pending = 1; + + mb(); + + bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_SET_MAC, 0, + U64_HI(config_cmd_map), U64_LO(config_cmd_map), 1); + + /* Wait for a completion */ + bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, + ramrod_flags); + +} + +static inline int bnx2x_set_mc_list(struct bnx2x *bp) +{ + /* some multicasts */ + if (CHIP_IS_E1(bp)) { + return bnx2x_set_e1_mc_list(bp); + } else { /* E1H and newer */ + return bnx2x_set_e1h_mc_list(bp); + } +} + /* called with netif_tx_lock from dev_mcast.c */ void bnx2x_set_rx_mode(struct net_device *dev) { struct bnx2x *bp = netdev_priv(dev); u32 rx_mode = BNX2X_RX_MODE_NORMAL; - int port = BP_PORT(bp); if (bp->state != BNX2X_STATE_OPEN) { DP(NETIF_MSG_IFUP, "state is %x, returning\n", bp->state); @@ -8842,47 +9205,16 @@ void bnx2x_set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) rx_mode = BNX2X_RX_MODE_PROMISC; - else if ((dev->flags & IFF_ALLMULTI) || - ((netdev_mc_count(dev) > BNX2X_MAX_MULTICAST) && - CHIP_IS_E1(bp))) + else if (dev->flags & IFF_ALLMULTI) rx_mode = BNX2X_RX_MODE_ALLMULTI; - else { /* some multicasts */ - if (CHIP_IS_E1(bp)) { - /* - * set mc list, do not wait as wait implies sleep - * and set_rx_mode can be invoked from non-sleepable - * context - */ - u8 offset = (CHIP_REV_IS_SLOW(bp) ? - BNX2X_MAX_EMUL_MULTI*(1 + port) : - BNX2X_MAX_MULTICAST*(1 + port)); - - bnx2x_set_e1_mc_list(bp, offset); - } else { /* E1H */ - /* Accept one or more multicasts */ - struct netdev_hw_addr *ha; - u32 mc_filter[MC_HASH_SIZE]; - u32 crc, bit, regidx; - int i; - - memset(mc_filter, 0, 4 * MC_HASH_SIZE); - - netdev_for_each_mc_addr(ha, dev) { - DP(NETIF_MSG_IFUP, "Adding mcast MAC: %pM\n", - bnx2x_mc_addr(ha)); - - crc = crc32c_le(0, bnx2x_mc_addr(ha), - ETH_ALEN); - bit = (crc >> 24) & 0xff; - regidx = bit >> 5; - bit &= 0x1f; - mc_filter[regidx] |= (1 << bit); - } + else { + /* some multicasts */ + if (bnx2x_set_mc_list(bp)) + rx_mode = BNX2X_RX_MODE_ALLMULTI; - for (i = 0; i < MC_HASH_SIZE; i++) - REG_WR(bp, MC_HASH_OFFSET(bp, i), - mc_filter[i]); - } + /* some unicasts */ + if (bnx2x_set_uc_list(bp)) + rx_mode = BNX2X_RX_MODE_PROMISC; } bp->rx_mode = rx_mode; @@ -8963,7 +9295,7 @@ static const struct net_device_ops bnx2x_netdev_ops = { .ndo_stop = bnx2x_close, .ndo_start_xmit = bnx2x_start_xmit, .ndo_select_queue = bnx2x_select_queue, - .ndo_set_multicast_list = bnx2x_set_rx_mode, + .ndo_set_rx_mode = bnx2x_set_rx_mode, .ndo_set_mac_address = bnx2x_change_mac_addr, .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = bnx2x_ioctl, @@ -9789,15 +10121,21 @@ static void bnx2x_cnic_sp_post(struct bnx2x *bp, int count) HW_CID(bp, BNX2X_ISCSI_ETH_CID)); } - /* There may be not more than 8 L2 and COMMON SPEs and not more - * than 8 L5 SPEs in the air. + /* There may be not more than 8 L2 and not more than 8 L5 SPEs + * We also check that the number of outstanding + * COMMON ramrods is not more than the EQ and SPQ can + * accommodate. */ - if ((type == NONE_CONNECTION_TYPE) || - (type == ETH_CONNECTION_TYPE)) { - if (!atomic_read(&bp->spq_left)) + if (type == ETH_CONNECTION_TYPE) { + if (!atomic_read(&bp->cq_spq_left)) break; else - atomic_dec(&bp->spq_left); + atomic_dec(&bp->cq_spq_left); + } else if (type == NONE_CONNECTION_TYPE) { + if (!atomic_read(&bp->eq_spq_left)) + break; + else + atomic_dec(&bp->eq_spq_left); } else if ((type == ISCSI_CONNECTION_TYPE) || (type == FCOE_CONNECTION_TYPE)) { if (bp->cnic_spq_pending >= @@ -9875,7 +10213,8 @@ static int bnx2x_cnic_ctl_send(struct bnx2x *bp, struct cnic_ctl_info *ctl) int rc = 0; mutex_lock(&bp->cnic_mutex); - c_ops = bp->cnic_ops; + c_ops = rcu_dereference_protected(bp->cnic_ops, + lockdep_is_held(&bp->cnic_mutex)); if (c_ops) rc = c_ops->cnic_ctl(bp->cnic_data, ctl); mutex_unlock(&bp->cnic_mutex); @@ -9989,7 +10328,7 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl) int count = ctl->data.credit.credit_count; smp_mb__before_atomic_inc(); - atomic_add(count, &bp->spq_left); + atomic_add(count, &bp->cq_spq_left); smp_mb__after_atomic_inc(); break; } @@ -10085,6 +10424,13 @@ struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev) struct bnx2x *bp = netdev_priv(dev); struct cnic_eth_dev *cp = &bp->cnic_eth_dev; + /* If both iSCSI and FCoE are disabled - return NULL in + * order to indicate CNIC that it should not try to work + * with this device. + */ + if (NO_ISCSI(bp) && NO_FCOE(bp)) + return NULL; + cp->drv_owner = THIS_MODULE; cp->chip_id = CHIP_ID(bp); cp->pdev = bp->pdev; @@ -10105,6 +10451,15 @@ struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev) BP_E1HVN(bp) * NONE_ETH_CONTEXT_USE; cp->iscsi_l2_cid = BNX2X_ISCSI_ETH_CID; + if (NO_ISCSI_OOO(bp)) + cp->drv_state |= CNIC_DRV_STATE_NO_ISCSI_OOO; + + if (NO_ISCSI(bp)) + cp->drv_state |= CNIC_DRV_STATE_NO_ISCSI; + + if (NO_FCOE(bp)) + cp->drv_state |= CNIC_DRV_STATE_NO_FCOE; + DP(BNX2X_MSG_SP, "page_size %d, tbl_offset %d, tbl_lines %d, " "starting cid %d\n", cp->ctx_blk_size, diff --git a/drivers/net/bnx2x/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h index e01330bb36c7..1c89f19a4425 100644 --- a/drivers/net/bnx2x/bnx2x_reg.h +++ b/drivers/net/bnx2x/bnx2x_reg.h @@ -6083,6 +6083,7 @@ Theotherbitsarereservedandshouldbezero*/ #define MDIO_PMA_REG_8727_PCS_OPT_CTRL 0xc808 #define MDIO_PMA_REG_8727_GPIO_CTRL 0xc80e #define MDIO_PMA_REG_8727_PCS_GP 0xc842 +#define MDIO_PMA_REG_8727_OPT_CFG_REG 0xc8e4 #define MDIO_AN_REG_8727_MISC_CTRL 0x8309 diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 163e0b06eaa5..77e3c6a7176a 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1372,8 +1372,8 @@ static int bond_compute_features(struct bonding *bond) { struct slave *slave; struct net_device *bond_dev = bond->dev; - unsigned long features = bond_dev->features; - unsigned long vlan_features = 0; + u32 features = bond_dev->features; + u32 vlan_features = 0; unsigned short max_hard_header_len = max((u16)ETH_HLEN, bond_dev->hard_header_len); int i; @@ -1400,8 +1400,8 @@ static int bond_compute_features(struct bonding *bond) done: features |= (bond_dev->features & BOND_VLAN_FEATURES); - bond_dev->features = netdev_fix_features(features, NULL); - bond_dev->vlan_features = netdev_fix_features(vlan_features, NULL); + bond_dev->features = netdev_fix_features(bond_dev, features); + bond_dev->vlan_features = netdev_fix_features(bond_dev, vlan_features); bond_dev->hard_header_len = max_hard_header_len; return 0; @@ -1594,9 +1594,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) } } - res = netdev_set_master(slave_dev, bond_dev); + res = netdev_set_bond_master(slave_dev, bond_dev); if (res) { - pr_debug("Error %d calling netdev_set_master\n", res); + pr_debug("Error %d calling netdev_set_bond_master\n", res); goto err_restore_mac; } /* open the slave since the application closed it */ @@ -1812,7 +1812,7 @@ err_close: dev_close(slave_dev); err_unset_master: - netdev_set_master(slave_dev, NULL); + netdev_set_bond_master(slave_dev, NULL); err_restore_mac: if (!bond->params.fail_over_mac) { @@ -1992,7 +1992,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) netif_addr_unlock_bh(bond_dev); } - netdev_set_master(slave_dev, NULL); + netdev_set_bond_master(slave_dev, NULL); #ifdef CONFIG_NET_POLL_CONTROLLER read_lock_bh(&bond->lock); @@ -2114,7 +2114,7 @@ static int bond_release_all(struct net_device *bond_dev) netif_addr_unlock_bh(bond_dev); } - netdev_set_master(slave_dev, NULL); + netdev_set_bond_master(slave_dev, NULL); /* close slave before restoring its mac address */ dev_close(slave_dev); @@ -4657,6 +4657,8 @@ static const struct net_device_ops bond_netdev_ops = { .ndo_netpoll_cleanup = bond_netpoll_cleanup, .ndo_poll_controller = bond_poll_controller, #endif + .ndo_add_slave = bond_enslave, + .ndo_del_slave = bond_release, }; static void bond_destructor(struct net_device *bond_dev) diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 8fd0174c5380..72bb0f6cc9bf 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -1198,7 +1198,7 @@ static ssize_t bonding_store_carrier(struct device *d, bond->dev->name, new_value); } out: - return count; + return ret; } static DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, bonding_show_carrier, bonding_store_carrier); @@ -1595,7 +1595,7 @@ static ssize_t bonding_store_slaves_active(struct device *d, } } out: - return count; + return ret; } static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR, bonding_show_slaves_active, bonding_store_slaves_active); diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 5dec456fd4a4..1d699e3df547 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -115,6 +115,8 @@ source "drivers/net/can/mscan/Kconfig" source "drivers/net/can/sja1000/Kconfig" +source "drivers/net/can/c_can/Kconfig" + source "drivers/net/can/usb/Kconfig" source "drivers/net/can/softing/Kconfig" diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile index 53c82a71778e..24ebfe8d758a 100644 --- a/drivers/net/can/Makefile +++ b/drivers/net/can/Makefile @@ -13,6 +13,7 @@ obj-y += softing/ obj-$(CONFIG_CAN_SJA1000) += sja1000/ obj-$(CONFIG_CAN_MSCAN) += mscan/ +obj-$(CONFIG_CAN_C_CAN) += c_can/ obj-$(CONFIG_CAN_AT91) += at91_can.o obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o obj-$(CONFIG_CAN_MCP251X) += mcp251x.o diff --git a/drivers/net/can/c_can/Kconfig b/drivers/net/can/c_can/Kconfig new file mode 100644 index 000000000000..ffb9773d102d --- /dev/null +++ b/drivers/net/can/c_can/Kconfig @@ -0,0 +1,15 @@ +menuconfig CAN_C_CAN + tristate "Bosch C_CAN devices" + depends on CAN_DEV && HAS_IOMEM + +if CAN_C_CAN + +config CAN_C_CAN_PLATFORM + tristate "Generic Platform Bus based C_CAN driver" + ---help--- + This driver adds support for the C_CAN chips connected to + the "platform bus" (Linux abstraction for directly to the + processor attached devices) which can be found on various + boards from ST Microelectronics (http://www.st.com) + like the SPEAr1310 and SPEAr320 evaluation boards. +endif diff --git a/drivers/net/can/c_can/Makefile b/drivers/net/can/c_can/Makefile new file mode 100644 index 000000000000..9273f6d5c4b7 --- /dev/null +++ b/drivers/net/can/c_can/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the Bosch C_CAN controller drivers. +# + +obj-$(CONFIG_CAN_C_CAN) += c_can.o +obj-$(CONFIG_CAN_C_CAN_PLATFORM) += c_can_platform.o + +ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c new file mode 100644 index 000000000000..14050786218a --- /dev/null +++ b/drivers/net/can/c_can/c_can.c @@ -0,0 +1,1158 @@ +/* + * CAN bus driver for Bosch C_CAN controller + * + * Copyright (C) 2010 ST Microelectronics + * Bhupesh Sharma <bhupesh.sharma@st.com> + * + * Borrowed heavily from the C_CAN driver originally written by: + * Copyright (C) 2007 + * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de> + * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch> + * + * TX and RX NAPI implementation has been borrowed from at91 CAN driver + * written by: + * Copyright + * (C) 2007 by Hans J. Koch <hjk@hansjkoch.de> + * (C) 2008, 2009 by Marc Kleine-Budde <kernel@pengutronix.de> + * + * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A and B. + * Bosch C_CAN user manual can be obtained from: + * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/ + * users_manual_c_can.pdf + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/version.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/if_arp.h> +#include <linux/if_ether.h> +#include <linux/list.h> +#include <linux/delay.h> +#include <linux/io.h> + +#include <linux/can.h> +#include <linux/can/dev.h> +#include <linux/can/error.h> + +#include "c_can.h" + +/* control register */ +#define CONTROL_TEST BIT(7) +#define CONTROL_CCE BIT(6) +#define CONTROL_DISABLE_AR BIT(5) +#define CONTROL_ENABLE_AR (0 << 5) +#define CONTROL_EIE BIT(3) +#define CONTROL_SIE BIT(2) +#define CONTROL_IE BIT(1) +#define CONTROL_INIT BIT(0) + +/* test register */ +#define TEST_RX BIT(7) +#define TEST_TX1 BIT(6) +#define TEST_TX2 BIT(5) +#define TEST_LBACK BIT(4) +#define TEST_SILENT BIT(3) +#define TEST_BASIC BIT(2) + +/* status register */ +#define STATUS_BOFF BIT(7) +#define STATUS_EWARN BIT(6) +#define STATUS_EPASS BIT(5) +#define STATUS_RXOK BIT(4) +#define STATUS_TXOK BIT(3) + +/* error counter register */ +#define ERR_CNT_TEC_MASK 0xff +#define ERR_CNT_TEC_SHIFT 0 +#define ERR_CNT_REC_SHIFT 8 +#define ERR_CNT_REC_MASK (0x7f << ERR_CNT_REC_SHIFT) +#define ERR_CNT_RP_SHIFT 15 +#define ERR_CNT_RP_MASK (0x1 << ERR_CNT_RP_SHIFT) + +/* bit-timing register */ +#define BTR_BRP_MASK 0x3f +#define BTR_BRP_SHIFT 0 +#define BTR_SJW_SHIFT 6 +#define BTR_SJW_MASK (0x3 << BTR_SJW_SHIFT) +#define BTR_TSEG1_SHIFT 8 +#define BTR_TSEG1_MASK (0xf << BTR_TSEG1_SHIFT) +#define BTR_TSEG2_SHIFT 12 +#define BTR_TSEG2_MASK (0x7 << BTR_TSEG2_SHIFT) + +/* brp extension register */ +#define BRP_EXT_BRPE_MASK 0x0f +#define BRP_EXT_BRPE_SHIFT 0 + +/* IFx command request */ +#define IF_COMR_BUSY BIT(15) + +/* IFx command mask */ +#define IF_COMM_WR BIT(7) +#define IF_COMM_MASK BIT(6) +#define IF_COMM_ARB BIT(5) +#define IF_COMM_CONTROL BIT(4) +#define IF_COMM_CLR_INT_PND BIT(3) +#define IF_COMM_TXRQST BIT(2) +#define IF_COMM_DATAA BIT(1) +#define IF_COMM_DATAB BIT(0) +#define IF_COMM_ALL (IF_COMM_MASK | IF_COMM_ARB | \ + IF_COMM_CONTROL | IF_COMM_TXRQST | \ + IF_COMM_DATAA | IF_COMM_DATAB) + +/* IFx arbitration */ +#define IF_ARB_MSGVAL BIT(15) +#define IF_ARB_MSGXTD BIT(14) +#define IF_ARB_TRANSMIT BIT(13) + +/* IFx message control */ +#define IF_MCONT_NEWDAT BIT(15) +#define IF_MCONT_MSGLST BIT(14) +#define IF_MCONT_CLR_MSGLST (0 << 14) +#define IF_MCONT_INTPND BIT(13) +#define IF_MCONT_UMASK BIT(12) +#define IF_MCONT_TXIE BIT(11) +#define IF_MCONT_RXIE BIT(10) +#define IF_MCONT_RMTEN BIT(9) +#define IF_MCONT_TXRQST BIT(8) +#define IF_MCONT_EOB BIT(7) +#define IF_MCONT_DLC_MASK 0xf + +/* + * IFx register masks: + * allow easy operation on 16-bit registers when the + * argument is 32-bit instead + */ +#define IFX_WRITE_LOW_16BIT(x) ((x) & 0xFFFF) +#define IFX_WRITE_HIGH_16BIT(x) (((x) & 0xFFFF0000) >> 16) + +/* message object split */ +#define C_CAN_NO_OF_OBJECTS 32 +#define C_CAN_MSG_OBJ_RX_NUM 16 +#define C_CAN_MSG_OBJ_TX_NUM 16 + +#define C_CAN_MSG_OBJ_RX_FIRST 1 +#define C_CAN_MSG_OBJ_RX_LAST (C_CAN_MSG_OBJ_RX_FIRST + \ + C_CAN_MSG_OBJ_RX_NUM - 1) + +#define C_CAN_MSG_OBJ_TX_FIRST (C_CAN_MSG_OBJ_RX_LAST + 1) +#define C_CAN_MSG_OBJ_TX_LAST (C_CAN_MSG_OBJ_TX_FIRST + \ + C_CAN_MSG_OBJ_TX_NUM - 1) + +#define C_CAN_MSG_OBJ_RX_SPLIT 9 +#define C_CAN_MSG_RX_LOW_LAST (C_CAN_MSG_OBJ_RX_SPLIT - 1) + +#define C_CAN_NEXT_MSG_OBJ_MASK (C_CAN_MSG_OBJ_TX_NUM - 1) +#define RECEIVE_OBJECT_BITS 0x0000ffff + +/* status interrupt */ +#define STATUS_INTERRUPT 0x8000 + +/* global interrupt masks */ +#define ENABLE_ALL_INTERRUPTS 1 +#define DISABLE_ALL_INTERRUPTS 0 + +/* minimum timeout for checking BUSY status */ +#define MIN_TIMEOUT_VALUE 6 + +/* napi related */ +#define C_CAN_NAPI_WEIGHT C_CAN_MSG_OBJ_RX_NUM + +/* c_can lec values */ +enum c_can_lec_type { + LEC_NO_ERROR = 0, + LEC_STUFF_ERROR, + LEC_FORM_ERROR, + LEC_ACK_ERROR, + LEC_BIT1_ERROR, + LEC_BIT0_ERROR, + LEC_CRC_ERROR, + LEC_UNUSED, +}; + +/* + * c_can error types: + * Bus errors (BUS_OFF, ERROR_WARNING, ERROR_PASSIVE) are supported + */ +enum c_can_bus_error_types { + C_CAN_NO_ERROR = 0, + C_CAN_BUS_OFF, + C_CAN_ERROR_WARNING, + C_CAN_ERROR_PASSIVE, +}; + +static struct can_bittiming_const c_can_bittiming_const = { + .name = KBUILD_MODNAME, + .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */ + .tseg1_max = 16, + .tseg2_min = 1, /* Time segment 2 = phase_seg2 */ + .tseg2_max = 8, + .sjw_max = 4, + .brp_min = 1, + .brp_max = 1024, /* 6-bit BRP field + 4-bit BRPE field*/ + .brp_inc = 1, +}; + +static inline int get_tx_next_msg_obj(const struct c_can_priv *priv) +{ + return (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) + + C_CAN_MSG_OBJ_TX_FIRST; +} + +static inline int get_tx_echo_msg_obj(const struct c_can_priv *priv) +{ + return (priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) + + C_CAN_MSG_OBJ_TX_FIRST; +} + +static u32 c_can_read_reg32(struct c_can_priv *priv, void *reg) +{ + u32 val = priv->read_reg(priv, reg); + val |= ((u32) priv->read_reg(priv, reg + 2)) << 16; + return val; +} + +static void c_can_enable_all_interrupts(struct c_can_priv *priv, + int enable) +{ + unsigned int cntrl_save = priv->read_reg(priv, + &priv->regs->control); + + if (enable) + cntrl_save |= (CONTROL_SIE | CONTROL_EIE | CONTROL_IE); + else + cntrl_save &= ~(CONTROL_EIE | CONTROL_IE | CONTROL_SIE); + + priv->write_reg(priv, &priv->regs->control, cntrl_save); +} + +static inline int c_can_msg_obj_is_busy(struct c_can_priv *priv, int iface) +{ + int count = MIN_TIMEOUT_VALUE; + + while (count && priv->read_reg(priv, + &priv->regs->ifregs[iface].com_req) & + IF_COMR_BUSY) { + count--; + udelay(1); + } + + if (!count) + return 1; + + return 0; +} + +static inline void c_can_object_get(struct net_device *dev, + int iface, int objno, int mask) +{ + struct c_can_priv *priv = netdev_priv(dev); + + /* + * As per specs, after writting the message object number in the + * IF command request register the transfer b/w interface + * register and message RAM must be complete in 6 CAN-CLK + * period. + */ + priv->write_reg(priv, &priv->regs->ifregs[iface].com_mask, + IFX_WRITE_LOW_16BIT(mask)); + priv->write_reg(priv, &priv->regs->ifregs[iface].com_req, + IFX_WRITE_LOW_16BIT(objno)); + + if (c_can_msg_obj_is_busy(priv, iface)) + netdev_err(dev, "timed out in object get\n"); +} + +static inline void c_can_object_put(struct net_device *dev, + int iface, int objno, int mask) +{ + struct c_can_priv *priv = netdev_priv(dev); + + /* + * As per specs, after writting the message object number in the + * IF command request register the transfer b/w interface + * register and message RAM must be complete in 6 CAN-CLK + * period. + */ + priv->write_reg(priv, &priv->regs->ifregs[iface].com_mask, + (IF_COMM_WR | IFX_WRITE_LOW_16BIT(mask))); + priv->write_reg(priv, &priv->regs->ifregs[iface].com_req, + IFX_WRITE_LOW_16BIT(objno)); + + if (c_can_msg_obj_is_busy(priv, iface)) + netdev_err(dev, "timed out in object put\n"); +} + +static void c_can_write_msg_object(struct net_device *dev, + int iface, struct can_frame *frame, int objno) +{ + int i; + u16 flags = 0; + unsigned int id; + struct c_can_priv *priv = netdev_priv(dev); + + if (!(frame->can_id & CAN_RTR_FLAG)) + flags |= IF_ARB_TRANSMIT; + + if (frame->can_id & CAN_EFF_FLAG) { + id = frame->can_id & CAN_EFF_MASK; + flags |= IF_ARB_MSGXTD; + } else + id = ((frame->can_id & CAN_SFF_MASK) << 18); + + flags |= IF_ARB_MSGVAL; + + priv->write_reg(priv, &priv->regs->ifregs[iface].arb1, + IFX_WRITE_LOW_16BIT(id)); + priv->write_reg(priv, &priv->regs->ifregs[iface].arb2, flags | + IFX_WRITE_HIGH_16BIT(id)); + + for (i = 0; i < frame->can_dlc; i += 2) { + priv->write_reg(priv, &priv->regs->ifregs[iface].data[i / 2], + frame->data[i] | (frame->data[i + 1] << 8)); + } + + /* enable interrupt for this message object */ + priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl, + IF_MCONT_TXIE | IF_MCONT_TXRQST | IF_MCONT_EOB | + frame->can_dlc); + c_can_object_put(dev, iface, objno, IF_COMM_ALL); +} + +static inline void c_can_mark_rx_msg_obj(struct net_device *dev, + int iface, int ctrl_mask, + int obj) +{ + struct c_can_priv *priv = netdev_priv(dev); + + priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl, + ctrl_mask & ~(IF_MCONT_MSGLST | IF_MCONT_INTPND)); + c_can_object_put(dev, iface, obj, IF_COMM_CONTROL); + +} + +static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device *dev, + int iface, + int ctrl_mask) +{ + int i; + struct c_can_priv *priv = netdev_priv(dev); + + for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_MSG_RX_LOW_LAST; i++) { + priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl, + ctrl_mask & ~(IF_MCONT_MSGLST | + IF_MCONT_INTPND | IF_MCONT_NEWDAT)); + c_can_object_put(dev, iface, i, IF_COMM_CONTROL); + } +} + +static inline void c_can_activate_rx_msg_obj(struct net_device *dev, + int iface, int ctrl_mask, + int obj) +{ + struct c_can_priv *priv = netdev_priv(dev); + + priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl, + ctrl_mask & ~(IF_MCONT_MSGLST | + IF_MCONT_INTPND | IF_MCONT_NEWDAT)); + c_can_object_put(dev, iface, obj, IF_COMM_CONTROL); +} + +static void c_can_handle_lost_msg_obj(struct net_device *dev, + int iface, int objno) +{ + struct c_can_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + struct sk_buff *skb; + struct can_frame *frame; + + netdev_err(dev, "msg lost in buffer %d\n", objno); + + c_can_object_get(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST); + + priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl, + IF_MCONT_CLR_MSGLST); + + c_can_object_put(dev, 0, objno, IF_COMM_CONTROL); + + /* create an error msg */ + skb = alloc_can_err_skb(dev, &frame); + if (unlikely(!skb)) + return; + + frame->can_id |= CAN_ERR_CRTL; + frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; + stats->rx_errors++; + stats->rx_over_errors++; + + netif_receive_skb(skb); +} + +static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl) +{ + u16 flags, data; + int i; + unsigned int val; + struct c_can_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + struct sk_buff *skb; + struct can_frame *frame; + + skb = alloc_can_skb(dev, &frame); + if (!skb) { + stats->rx_dropped++; + return -ENOMEM; + } + + frame->can_dlc = get_can_dlc(ctrl & 0x0F); + + flags = priv->read_reg(priv, &priv->regs->ifregs[iface].arb2); + val = priv->read_reg(priv, &priv->regs->ifregs[iface].arb1) | + (flags << 16); + + if (flags & IF_ARB_MSGXTD) + frame->can_id = (val & CAN_EFF_MASK) | CAN_EFF_FLAG; + else + frame->can_id = (val >> 18) & CAN_SFF_MASK; + + if (flags & IF_ARB_TRANSMIT) + frame->can_id |= CAN_RTR_FLAG; + else { + for (i = 0; i < frame->can_dlc; i += 2) { + data = priv->read_reg(priv, + &priv->regs->ifregs[iface].data[i / 2]); + frame->data[i] = data; + frame->data[i + 1] = data >> 8; + } + } + + netif_receive_skb(skb); + + stats->rx_packets++; + stats->rx_bytes += frame->can_dlc; + + return 0; +} + +static void c_can_setup_receive_object(struct net_device *dev, int iface, + int objno, unsigned int mask, + unsigned int id, unsigned int mcont) +{ + struct c_can_priv *priv = netdev_priv(dev); + + priv->write_reg(priv, &priv->regs->ifregs[iface].mask1, + IFX_WRITE_LOW_16BIT(mask)); + priv->write_reg(priv, &priv->regs->ifregs[iface].mask2, + IFX_WRITE_HIGH_16BIT(mask)); + + priv->write_reg(priv, &priv->regs->ifregs[iface].arb1, + IFX_WRITE_LOW_16BIT(id)); + priv->write_reg(priv, &priv->regs->ifregs[iface].arb2, + (IF_ARB_MSGVAL | IFX_WRITE_HIGH_16BIT(id))); + + priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl, mcont); + c_can_object_put(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST); + + netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno, + c_can_read_reg32(priv, &priv->regs->msgval1)); +} + +static void c_can_inval_msg_object(struct net_device *dev, int iface, int objno) +{ + struct c_can_priv *priv = netdev_priv(dev); + + priv->write_reg(priv, &priv->regs->ifregs[iface].arb1, 0); + priv->write_reg(priv, &priv->regs->ifregs[iface].arb2, 0); + priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl, 0); + + c_can_object_put(dev, iface, objno, IF_COMM_ARB | IF_COMM_CONTROL); + + netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno, + c_can_read_reg32(priv, &priv->regs->msgval1)); +} + +static inline int c_can_is_next_tx_obj_busy(struct c_can_priv *priv, int objno) +{ + int val = c_can_read_reg32(priv, &priv->regs->txrqst1); + + /* + * as transmission request register's bit n-1 corresponds to + * message object n, we need to handle the same properly. + */ + if (val & (1 << (objno - 1))) + return 1; + + return 0; +} + +static netdev_tx_t c_can_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + u32 msg_obj_no; + struct c_can_priv *priv = netdev_priv(dev); + struct can_frame *frame = (struct can_frame *)skb->data; + + if (can_dropped_invalid_skb(dev, skb)) + return NETDEV_TX_OK; + + msg_obj_no = get_tx_next_msg_obj(priv); + + /* prepare message object for transmission */ + c_can_write_msg_object(dev, 0, frame, msg_obj_no); + can_put_echo_skb(skb, dev, msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST); + + /* + * we have to stop the queue in case of a wrap around or + * if the next TX message object is still in use + */ + priv->tx_next++; + if (c_can_is_next_tx_obj_busy(priv, get_tx_next_msg_obj(priv)) || + (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) == 0) + netif_stop_queue(dev); + + return NETDEV_TX_OK; +} + +static int c_can_set_bittiming(struct net_device *dev) +{ + unsigned int reg_btr, reg_brpe, ctrl_save; + u8 brp, brpe, sjw, tseg1, tseg2; + u32 ten_bit_brp; + struct c_can_priv *priv = netdev_priv(dev); + const struct can_bittiming *bt = &priv->can.bittiming; + + /* c_can provides a 6-bit brp and 4-bit brpe fields */ + ten_bit_brp = bt->brp - 1; + brp = ten_bit_brp & BTR_BRP_MASK; + brpe = ten_bit_brp >> 6; + + sjw = bt->sjw - 1; + tseg1 = bt->prop_seg + bt->phase_seg1 - 1; + tseg2 = bt->phase_seg2 - 1; + reg_btr = brp | (sjw << BTR_SJW_SHIFT) | (tseg1 << BTR_TSEG1_SHIFT) | + (tseg2 << BTR_TSEG2_SHIFT); + reg_brpe = brpe & BRP_EXT_BRPE_MASK; + + netdev_info(dev, + "setting BTR=%04x BRPE=%04x\n", reg_btr, reg_brpe); + + ctrl_save = priv->read_reg(priv, &priv->regs->control); + priv->write_reg(priv, &priv->regs->control, + ctrl_save | CONTROL_CCE | CONTROL_INIT); + priv->write_reg(priv, &priv->regs->btr, reg_btr); + priv->write_reg(priv, &priv->regs->brp_ext, reg_brpe); + priv->write_reg(priv, &priv->regs->control, ctrl_save); + + return 0; +} + +/* + * Configure C_CAN message objects for Tx and Rx purposes: + * C_CAN provides a total of 32 message objects that can be configured + * either for Tx or Rx purposes. Here the first 16 message objects are used as + * a reception FIFO. The end of reception FIFO is signified by the EoB bit + * being SET. The remaining 16 message objects are kept aside for Tx purposes. + * See user guide document for further details on configuring message + * objects. + */ +static void c_can_configure_msg_objects(struct net_device *dev) +{ + int i; + + /* first invalidate all message objects */ + for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_NO_OF_OBJECTS; i++) + c_can_inval_msg_object(dev, 0, i); + + /* setup receive message objects */ + for (i = C_CAN_MSG_OBJ_RX_FIRST; i < C_CAN_MSG_OBJ_RX_LAST; i++) + c_can_setup_receive_object(dev, 0, i, 0, 0, + (IF_MCONT_RXIE | IF_MCONT_UMASK) & ~IF_MCONT_EOB); + + c_can_setup_receive_object(dev, 0, C_CAN_MSG_OBJ_RX_LAST, 0, 0, + IF_MCONT_EOB | IF_MCONT_RXIE | IF_MCONT_UMASK); +} + +/* + * Configure C_CAN chip: + * - enable/disable auto-retransmission + * - set operating mode + * - configure message objects + */ +static void c_can_chip_config(struct net_device *dev) +{ + struct c_can_priv *priv = netdev_priv(dev); + + if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT) + /* disable automatic retransmission */ + priv->write_reg(priv, &priv->regs->control, + CONTROL_DISABLE_AR); + else + /* enable automatic retransmission */ + priv->write_reg(priv, &priv->regs->control, + CONTROL_ENABLE_AR); + + if (priv->can.ctrlmode & (CAN_CTRLMODE_LISTENONLY & + CAN_CTRLMODE_LOOPBACK)) { + /* loopback + silent mode : useful for hot self-test */ + priv->write_reg(priv, &priv->regs->control, CONTROL_EIE | + CONTROL_SIE | CONTROL_IE | CONTROL_TEST); + priv->write_reg(priv, &priv->regs->test, + TEST_LBACK | TEST_SILENT); + } else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { + /* loopback mode : useful for self-test function */ + priv->write_reg(priv, &priv->regs->control, CONTROL_EIE | + CONTROL_SIE | CONTROL_IE | CONTROL_TEST); + priv->write_reg(priv, &priv->regs->test, TEST_LBACK); + } else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) { + /* silent mode : bus-monitoring mode */ + priv->write_reg(priv, &priv->regs->control, CONTROL_EIE | + CONTROL_SIE | CONTROL_IE | CONTROL_TEST); + priv->write_reg(priv, &priv->regs->test, TEST_SILENT); + } else + /* normal mode*/ + priv->write_reg(priv, &priv->regs->control, + CONTROL_EIE | CONTROL_SIE | CONTROL_IE); + + /* configure message objects */ + c_can_configure_msg_objects(dev); + + /* set a `lec` value so that we can check for updates later */ + priv->write_reg(priv, &priv->regs->status, LEC_UNUSED); + + /* set bittiming params */ + c_can_set_bittiming(dev); +} + +static void c_can_start(struct net_device *dev) +{ + struct c_can_priv *priv = netdev_priv(dev); + + /* enable status change, error and module interrupts */ + c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS); + + /* basic c_can configuration */ + c_can_chip_config(dev); + + priv->can.state = CAN_STATE_ERROR_ACTIVE; + + /* reset tx helper pointers */ + priv->tx_next = priv->tx_echo = 0; +} + +static void c_can_stop(struct net_device *dev) +{ + struct c_can_priv *priv = netdev_priv(dev); + + /* disable all interrupts */ + c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS); + + /* set the state as STOPPED */ + priv->can.state = CAN_STATE_STOPPED; +} + +static int c_can_set_mode(struct net_device *dev, enum can_mode mode) +{ + switch (mode) { + case CAN_MODE_START: + c_can_start(dev); + netif_wake_queue(dev); + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int c_can_get_berr_counter(const struct net_device *dev, + struct can_berr_counter *bec) +{ + unsigned int reg_err_counter; + struct c_can_priv *priv = netdev_priv(dev); + + reg_err_counter = priv->read_reg(priv, &priv->regs->err_cnt); + bec->rxerr = (reg_err_counter & ERR_CNT_REC_MASK) >> + ERR_CNT_REC_SHIFT; + bec->txerr = reg_err_counter & ERR_CNT_TEC_MASK; + + return 0; +} + +/* + * theory of operation: + * + * priv->tx_echo holds the number of the oldest can_frame put for + * transmission into the hardware, but not yet ACKed by the CAN tx + * complete IRQ. + * + * We iterate from priv->tx_echo to priv->tx_next and check if the + * packet has been transmitted, echo it back to the CAN framework. + * If we discover a not yet transmitted package, stop looking for more. + */ +static void c_can_do_tx(struct net_device *dev) +{ + u32 val; + u32 msg_obj_no; + struct c_can_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + + for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) { + msg_obj_no = get_tx_echo_msg_obj(priv); + c_can_inval_msg_object(dev, 0, msg_obj_no); + val = c_can_read_reg32(priv, &priv->regs->txrqst1); + if (!(val & (1 << msg_obj_no))) { + can_get_echo_skb(dev, + msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST); + stats->tx_bytes += priv->read_reg(priv, + &priv->regs->ifregs[0].msg_cntrl) + & IF_MCONT_DLC_MASK; + stats->tx_packets++; + } + } + + /* restart queue if wrap-up or if queue stalled on last pkt */ + if (((priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) != 0) || + ((priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) == 0)) + netif_wake_queue(dev); +} + +/* + * theory of operation: + * + * c_can core saves a received CAN message into the first free message + * object it finds free (starting with the lowest). Bits NEWDAT and + * INTPND are set for this message object indicating that a new message + * has arrived. To work-around this issue, we keep two groups of message + * objects whose partitioning is defined by C_CAN_MSG_OBJ_RX_SPLIT. + * + * To ensure in-order frame reception we use the following + * approach while re-activating a message object to receive further + * frames: + * - if the current message object number is lower than + * C_CAN_MSG_RX_LOW_LAST, do not clear the NEWDAT bit while clearing + * the INTPND bit. + * - if the current message object number is equal to + * C_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of all lower + * receive message objects. + * - if the current message object number is greater than + * C_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of + * only this message object. + */ +static int c_can_do_rx_poll(struct net_device *dev, int quota) +{ + u32 num_rx_pkts = 0; + unsigned int msg_obj, msg_ctrl_save; + struct c_can_priv *priv = netdev_priv(dev); + u32 val = c_can_read_reg32(priv, &priv->regs->intpnd1); + + for (msg_obj = C_CAN_MSG_OBJ_RX_FIRST; + msg_obj <= C_CAN_MSG_OBJ_RX_LAST && quota > 0; + val = c_can_read_reg32(priv, &priv->regs->intpnd1), + msg_obj++) { + /* + * as interrupt pending register's bit n-1 corresponds to + * message object n, we need to handle the same properly. + */ + if (val & (1 << (msg_obj - 1))) { + c_can_object_get(dev, 0, msg_obj, IF_COMM_ALL & + ~IF_COMM_TXRQST); + msg_ctrl_save = priv->read_reg(priv, + &priv->regs->ifregs[0].msg_cntrl); + + if (msg_ctrl_save & IF_MCONT_EOB) + return num_rx_pkts; + + if (msg_ctrl_save & IF_MCONT_MSGLST) { + c_can_handle_lost_msg_obj(dev, 0, msg_obj); + num_rx_pkts++; + quota--; + continue; + } + + if (!(msg_ctrl_save & IF_MCONT_NEWDAT)) + continue; + + /* read the data from the message object */ + c_can_read_msg_object(dev, 0, msg_ctrl_save); + + if (msg_obj < C_CAN_MSG_RX_LOW_LAST) + c_can_mark_rx_msg_obj(dev, 0, + msg_ctrl_save, msg_obj); + else if (msg_obj > C_CAN_MSG_RX_LOW_LAST) + /* activate this msg obj */ + c_can_activate_rx_msg_obj(dev, 0, + msg_ctrl_save, msg_obj); + else if (msg_obj == C_CAN_MSG_RX_LOW_LAST) + /* activate all lower message objects */ + c_can_activate_all_lower_rx_msg_obj(dev, + 0, msg_ctrl_save); + + num_rx_pkts++; + quota--; + } + } + + return num_rx_pkts; +} + +static inline int c_can_has_and_handle_berr(struct c_can_priv *priv) +{ + return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) && + (priv->current_status & LEC_UNUSED); +} + +static int c_can_handle_state_change(struct net_device *dev, + enum c_can_bus_error_types error_type) +{ + unsigned int reg_err_counter; + unsigned int rx_err_passive; + struct c_can_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + struct can_frame *cf; + struct sk_buff *skb; + struct can_berr_counter bec; + + /* propogate the error condition to the CAN stack */ + skb = alloc_can_err_skb(dev, &cf); + if (unlikely(!skb)) + return 0; + + c_can_get_berr_counter(dev, &bec); + reg_err_counter = priv->read_reg(priv, &priv->regs->err_cnt); + rx_err_passive = (reg_err_counter & ERR_CNT_RP_MASK) >> + ERR_CNT_RP_SHIFT; + + switch (error_type) { + case C_CAN_ERROR_WARNING: + /* error warning state */ + priv->can.can_stats.error_warning++; + priv->can.state = CAN_STATE_ERROR_WARNING; + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] = (bec.txerr > bec.rxerr) ? + CAN_ERR_CRTL_TX_WARNING : + CAN_ERR_CRTL_RX_WARNING; + cf->data[6] = bec.txerr; + cf->data[7] = bec.rxerr; + + break; + case C_CAN_ERROR_PASSIVE: + /* error passive state */ + priv->can.can_stats.error_passive++; + priv->can.state = CAN_STATE_ERROR_PASSIVE; + cf->can_id |= CAN_ERR_CRTL; + if (rx_err_passive) + cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE; + if (bec.txerr > 127) + cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE; + + cf->data[6] = bec.txerr; + cf->data[7] = bec.rxerr; + break; + case C_CAN_BUS_OFF: + /* bus-off state */ + priv->can.state = CAN_STATE_BUS_OFF; + cf->can_id |= CAN_ERR_BUSOFF; + /* + * disable all interrupts in bus-off mode to ensure that + * the CPU is not hogged down + */ + c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS); + can_bus_off(dev); + break; + default: + break; + } + + netif_receive_skb(skb); + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + + return 1; +} + +static int c_can_handle_bus_err(struct net_device *dev, + enum c_can_lec_type lec_type) +{ + struct c_can_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + struct can_frame *cf; + struct sk_buff *skb; + + /* + * early exit if no lec update or no error. + * no lec update means that no CAN bus event has been detected + * since CPU wrote 0x7 value to status reg. + */ + if (lec_type == LEC_UNUSED || lec_type == LEC_NO_ERROR) + return 0; + + /* propogate the error condition to the CAN stack */ + skb = alloc_can_err_skb(dev, &cf); + if (unlikely(!skb)) + return 0; + + /* + * check for 'last error code' which tells us the + * type of the last error to occur on the CAN bus + */ + + /* common for all type of bus errors */ + priv->can.can_stats.bus_error++; + stats->rx_errors++; + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + cf->data[2] |= CAN_ERR_PROT_UNSPEC; + + switch (lec_type) { + case LEC_STUFF_ERROR: + netdev_dbg(dev, "stuff error\n"); + cf->data[2] |= CAN_ERR_PROT_STUFF; + break; + case LEC_FORM_ERROR: + netdev_dbg(dev, "form error\n"); + cf->data[2] |= CAN_ERR_PROT_FORM; + break; + case LEC_ACK_ERROR: + netdev_dbg(dev, "ack error\n"); + cf->data[2] |= (CAN_ERR_PROT_LOC_ACK | + CAN_ERR_PROT_LOC_ACK_DEL); + break; + case LEC_BIT1_ERROR: + netdev_dbg(dev, "bit1 error\n"); + cf->data[2] |= CAN_ERR_PROT_BIT1; + break; + case LEC_BIT0_ERROR: + netdev_dbg(dev, "bit0 error\n"); + cf->data[2] |= CAN_ERR_PROT_BIT0; + break; + case LEC_CRC_ERROR: + netdev_dbg(dev, "CRC error\n"); + cf->data[2] |= (CAN_ERR_PROT_LOC_CRC_SEQ | + CAN_ERR_PROT_LOC_CRC_DEL); + break; + default: + break; + } + + /* set a `lec` value so that we can check for updates later */ + priv->write_reg(priv, &priv->regs->status, LEC_UNUSED); + + netif_receive_skb(skb); + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + + return 1; +} + +static int c_can_poll(struct napi_struct *napi, int quota) +{ + u16 irqstatus; + int lec_type = 0; + int work_done = 0; + struct net_device *dev = napi->dev; + struct c_can_priv *priv = netdev_priv(dev); + + irqstatus = priv->read_reg(priv, &priv->regs->interrupt); + if (!irqstatus) + goto end; + + /* status events have the highest priority */ + if (irqstatus == STATUS_INTERRUPT) { + priv->current_status = priv->read_reg(priv, + &priv->regs->status); + + /* handle Tx/Rx events */ + if (priv->current_status & STATUS_TXOK) + priv->write_reg(priv, &priv->regs->status, + priv->current_status & ~STATUS_TXOK); + + if (priv->current_status & STATUS_RXOK) + priv->write_reg(priv, &priv->regs->status, + priv->current_status & ~STATUS_RXOK); + + /* handle state changes */ + if ((priv->current_status & STATUS_EWARN) && + (!(priv->last_status & STATUS_EWARN))) { + netdev_dbg(dev, "entered error warning state\n"); + work_done += c_can_handle_state_change(dev, + C_CAN_ERROR_WARNING); + } + if ((priv->current_status & STATUS_EPASS) && + (!(priv->last_status & STATUS_EPASS))) { + netdev_dbg(dev, "entered error passive state\n"); + work_done += c_can_handle_state_change(dev, + C_CAN_ERROR_PASSIVE); + } + if ((priv->current_status & STATUS_BOFF) && + (!(priv->last_status & STATUS_BOFF))) { + netdev_dbg(dev, "entered bus off state\n"); + work_done += c_can_handle_state_change(dev, + C_CAN_BUS_OFF); + } + + /* handle bus recovery events */ + if ((!(priv->current_status & STATUS_BOFF)) && + (priv->last_status & STATUS_BOFF)) { + netdev_dbg(dev, "left bus off state\n"); + priv->can.state = CAN_STATE_ERROR_ACTIVE; + } + if ((!(priv->current_status & STATUS_EPASS)) && + (priv->last_status & STATUS_EPASS)) { + netdev_dbg(dev, "left error passive state\n"); + priv->can.state = CAN_STATE_ERROR_ACTIVE; + } + + priv->last_status = priv->current_status; + + /* handle lec errors on the bus */ + lec_type = c_can_has_and_handle_berr(priv); + if (lec_type) + work_done += c_can_handle_bus_err(dev, lec_type); + } else if ((irqstatus >= C_CAN_MSG_OBJ_RX_FIRST) && + (irqstatus <= C_CAN_MSG_OBJ_RX_LAST)) { + /* handle events corresponding to receive message objects */ + work_done += c_can_do_rx_poll(dev, (quota - work_done)); + } else if ((irqstatus >= C_CAN_MSG_OBJ_TX_FIRST) && + (irqstatus <= C_CAN_MSG_OBJ_TX_LAST)) { + /* handle events corresponding to transmit message objects */ + c_can_do_tx(dev); + } + +end: + if (work_done < quota) { + napi_complete(napi); + /* enable all IRQs */ + c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS); + } + + return work_done; +} + +static irqreturn_t c_can_isr(int irq, void *dev_id) +{ + u16 irqstatus; + struct net_device *dev = (struct net_device *)dev_id; + struct c_can_priv *priv = netdev_priv(dev); + + irqstatus = priv->read_reg(priv, &priv->regs->interrupt); + if (!irqstatus) + return IRQ_NONE; + + /* disable all interrupts and schedule the NAPI */ + c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS); + napi_schedule(&priv->napi); + + return IRQ_HANDLED; +} + +static int c_can_open(struct net_device *dev) +{ + int err; + struct c_can_priv *priv = netdev_priv(dev); + + /* open the can device */ + err = open_candev(dev); + if (err) { + netdev_err(dev, "failed to open can device\n"); + return err; + } + + /* register interrupt handler */ + err = request_irq(dev->irq, &c_can_isr, IRQF_SHARED, dev->name, + dev); + if (err < 0) { + netdev_err(dev, "failed to request interrupt\n"); + goto exit_irq_fail; + } + + /* start the c_can controller */ + c_can_start(dev); + + napi_enable(&priv->napi); + netif_start_queue(dev); + + return 0; + +exit_irq_fail: + close_candev(dev); + return err; +} + +static int c_can_close(struct net_device *dev) +{ + struct c_can_priv *priv = netdev_priv(dev); + + netif_stop_queue(dev); + napi_disable(&priv->napi); + c_can_stop(dev); + free_irq(dev->irq, dev); + close_candev(dev); + + return 0; +} + +struct net_device *alloc_c_can_dev(void) +{ + struct net_device *dev; + struct c_can_priv *priv; + + dev = alloc_candev(sizeof(struct c_can_priv), C_CAN_MSG_OBJ_TX_NUM); + if (!dev) + return NULL; + + priv = netdev_priv(dev); + netif_napi_add(dev, &priv->napi, c_can_poll, C_CAN_NAPI_WEIGHT); + + priv->dev = dev; + priv->can.bittiming_const = &c_can_bittiming_const; + priv->can.do_set_mode = c_can_set_mode; + priv->can.do_get_berr_counter = c_can_get_berr_counter; + priv->can.ctrlmode_supported = CAN_CTRLMODE_ONE_SHOT | + CAN_CTRLMODE_LOOPBACK | + CAN_CTRLMODE_LISTENONLY | + CAN_CTRLMODE_BERR_REPORTING; + + return dev; +} +EXPORT_SYMBOL_GPL(alloc_c_can_dev); + +void free_c_can_dev(struct net_device *dev) +{ + free_candev(dev); +} +EXPORT_SYMBOL_GPL(free_c_can_dev); + +static const struct net_device_ops c_can_netdev_ops = { + .ndo_open = c_can_open, + .ndo_stop = c_can_close, + .ndo_start_xmit = c_can_start_xmit, +}; + +int register_c_can_dev(struct net_device *dev) +{ + dev->flags |= IFF_ECHO; /* we support local echo */ + dev->netdev_ops = &c_can_netdev_ops; + + return register_candev(dev); +} +EXPORT_SYMBOL_GPL(register_c_can_dev); + +void unregister_c_can_dev(struct net_device *dev) +{ + struct c_can_priv *priv = netdev_priv(dev); + + /* disable all interrupts */ + c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS); + + unregister_candev(dev); +} +EXPORT_SYMBOL_GPL(unregister_c_can_dev); + +MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma@st.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("CAN bus driver for Bosch C_CAN controller"); diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h new file mode 100644 index 000000000000..9b7fbef3d09a --- /dev/null +++ b/drivers/net/can/c_can/c_can.h @@ -0,0 +1,86 @@ +/* + * CAN bus driver for Bosch C_CAN controller + * + * Copyright (C) 2010 ST Microelectronics + * Bhupesh Sharma <bhupesh.sharma@st.com> + * + * Borrowed heavily from the C_CAN driver originally written by: + * Copyright (C) 2007 + * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de> + * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch> + * + * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A and B. + * Bosch C_CAN user manual can be obtained from: + * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/ + * users_manual_c_can.pdf + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef C_CAN_H +#define C_CAN_H + +/* c_can IF registers */ +struct c_can_if_regs { + u16 com_req; + u16 com_mask; + u16 mask1; + u16 mask2; + u16 arb1; + u16 arb2; + u16 msg_cntrl; + u16 data[4]; + u16 _reserved[13]; +}; + +/* c_can hardware registers */ +struct c_can_regs { + u16 control; + u16 status; + u16 err_cnt; + u16 btr; + u16 interrupt; + u16 test; + u16 brp_ext; + u16 _reserved1; + struct c_can_if_regs ifregs[2]; /* [0] = IF1 and [1] = IF2 */ + u16 _reserved2[8]; + u16 txrqst1; + u16 txrqst2; + u16 _reserved3[6]; + u16 newdat1; + u16 newdat2; + u16 _reserved4[6]; + u16 intpnd1; + u16 intpnd2; + u16 _reserved5[6]; + u16 msgval1; + u16 msgval2; + u16 _reserved6[6]; +}; + +/* c_can private data structure */ +struct c_can_priv { + struct can_priv can; /* must be the first member */ + struct napi_struct napi; + struct net_device *dev; + int tx_object; + int current_status; + int last_status; + u16 (*read_reg) (struct c_can_priv *priv, void *reg); + void (*write_reg) (struct c_can_priv *priv, void *reg, u16 val); + struct c_can_regs __iomem *regs; + unsigned long irq_flags; /* for request_irq() */ + unsigned int tx_next; + unsigned int tx_echo; + void *priv; /* for board-specific data */ +}; + +struct net_device *alloc_c_can_dev(void); +void free_c_can_dev(struct net_device *dev); +int register_c_can_dev(struct net_device *dev); +void unregister_c_can_dev(struct net_device *dev); + +#endif /* C_CAN_H */ diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c new file mode 100644 index 000000000000..e629b961ae2d --- /dev/null +++ b/drivers/net/can/c_can/c_can_platform.c @@ -0,0 +1,215 @@ +/* + * Platform CAN bus driver for Bosch C_CAN controller + * + * Copyright (C) 2010 ST Microelectronics + * Bhupesh Sharma <bhupesh.sharma@st.com> + * + * Borrowed heavily from the C_CAN driver originally written by: + * Copyright (C) 2007 + * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de> + * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch> + * + * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A and B. + * Bosch C_CAN user manual can be obtained from: + * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/ + * users_manual_c_can.pdf + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/version.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/if_arp.h> +#include <linux/if_ether.h> +#include <linux/list.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/clk.h> + +#include <linux/can/dev.h> + +#include "c_can.h" + +/* + * 16-bit c_can registers can be arranged differently in the memory + * architecture of different implementations. For example: 16-bit + * registers can be aligned to a 16-bit boundary or 32-bit boundary etc. + * Handle the same by providing a common read/write interface. + */ +static u16 c_can_plat_read_reg_aligned_to_16bit(struct c_can_priv *priv, + void *reg) +{ + return readw(reg); +} + +static void c_can_plat_write_reg_aligned_to_16bit(struct c_can_priv *priv, + void *reg, u16 val) +{ + writew(val, reg); +} + +static u16 c_can_plat_read_reg_aligned_to_32bit(struct c_can_priv *priv, + void *reg) +{ + return readw(reg + (long)reg - (long)priv->regs); +} + +static void c_can_plat_write_reg_aligned_to_32bit(struct c_can_priv *priv, + void *reg, u16 val) +{ + writew(val, reg + (long)reg - (long)priv->regs); +} + +static int __devinit c_can_plat_probe(struct platform_device *pdev) +{ + int ret; + void __iomem *addr; + struct net_device *dev; + struct c_can_priv *priv; + struct resource *mem, *irq; +#ifdef CONFIG_HAVE_CLK + struct clk *clk; + + /* get the appropriate clk */ + clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "no clock defined\n"); + ret = -ENODEV; + goto exit; + } +#endif + + /* get the platform data */ + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!mem || (irq <= 0)) { + ret = -ENODEV; + goto exit_free_clk; + } + + if (!request_mem_region(mem->start, resource_size(mem), + KBUILD_MODNAME)) { + dev_err(&pdev->dev, "resource unavailable\n"); + ret = -ENODEV; + goto exit_free_clk; + } + + addr = ioremap(mem->start, resource_size(mem)); + if (!addr) { + dev_err(&pdev->dev, "failed to map can port\n"); + ret = -ENOMEM; + goto exit_release_mem; + } + + /* allocate the c_can device */ + dev = alloc_c_can_dev(); + if (!dev) { + ret = -ENOMEM; + goto exit_iounmap; + } + + priv = netdev_priv(dev); + + dev->irq = irq->start; + priv->regs = addr; +#ifdef CONFIG_HAVE_CLK + priv->can.clock.freq = clk_get_rate(clk); + priv->priv = clk; +#endif + + switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) { + case IORESOURCE_MEM_32BIT: + priv->read_reg = c_can_plat_read_reg_aligned_to_32bit; + priv->write_reg = c_can_plat_write_reg_aligned_to_32bit; + break; + case IORESOURCE_MEM_16BIT: + default: + priv->read_reg = c_can_plat_read_reg_aligned_to_16bit; + priv->write_reg = c_can_plat_write_reg_aligned_to_16bit; + break; + } + + platform_set_drvdata(pdev, dev); + SET_NETDEV_DEV(dev, &pdev->dev); + + ret = register_c_can_dev(dev); + if (ret) { + dev_err(&pdev->dev, "registering %s failed (err=%d)\n", + KBUILD_MODNAME, ret); + goto exit_free_device; + } + + dev_info(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n", + KBUILD_MODNAME, priv->regs, dev->irq); + return 0; + +exit_free_device: + platform_set_drvdata(pdev, NULL); + free_c_can_dev(dev); +exit_iounmap: + iounmap(addr); +exit_release_mem: + release_mem_region(mem->start, resource_size(mem)); +exit_free_clk: +#ifdef CONFIG_HAVE_CLK + clk_put(clk); +exit: +#endif + dev_err(&pdev->dev, "probe failed\n"); + + return ret; +} + +static int __devexit c_can_plat_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct c_can_priv *priv = netdev_priv(dev); + struct resource *mem; + + unregister_c_can_dev(dev); + platform_set_drvdata(pdev, NULL); + + free_c_can_dev(dev); + iounmap(priv->regs); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(mem->start, resource_size(mem)); + +#ifdef CONFIG_HAVE_CLK + clk_put(priv->priv); +#endif + + return 0; +} + +static struct platform_driver c_can_plat_driver = { + .driver = { + .name = KBUILD_MODNAME, + .owner = THIS_MODULE, + }, + .probe = c_can_plat_probe, + .remove = __devexit_p(c_can_plat_remove), +}; + +static int __init c_can_plat_init(void) +{ + return platform_driver_register(&c_can_plat_driver); +} +module_init(c_can_plat_init); + +static void __exit c_can_plat_exit(void) +{ + platform_driver_unregister(&c_can_plat_driver); +} +module_exit(c_can_plat_exit); + +MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma@st.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Platform CAN bus driver for Bosch C_CAN controller"); diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index 7ab534aee452..7513c4523ac4 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -940,7 +940,7 @@ static int mcp251x_open(struct net_device *net) goto open_unlock; } - priv->wq = create_freezeable_workqueue("mcp251x_wq"); + priv->wq = create_freezable_workqueue("mcp251x_wq"); INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler); INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler); diff --git a/drivers/net/can/mscan/Kconfig b/drivers/net/can/mscan/Kconfig index 27d1d398e25e..d38706958af6 100644 --- a/drivers/net/can/mscan/Kconfig +++ b/drivers/net/can/mscan/Kconfig @@ -1,5 +1,5 @@ config CAN_MSCAN - depends on CAN_DEV && (PPC || M68K || M68KNOMMU) + depends on CAN_DEV && (PPC || M68K) tristate "Support for Freescale MSCAN based chips" ---help--- The Motorola Scalable Controller Area Network (MSCAN) definition diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c index 7d8bc128044c..e54712b22c27 100644 --- a/drivers/net/can/pch_can.c +++ b/drivers/net/can/pch_can.c @@ -185,9 +185,9 @@ struct pch_can_priv { static struct can_bittiming_const pch_can_bittiming_const = { .name = KBUILD_MODNAME, - .tseg1_min = 1, + .tseg1_min = 2, .tseg1_max = 16, - .tseg2_min = 2, + .tseg2_min = 1, .tseg2_max = 8, .sjw_max = 4, .brp_min = 1, diff --git a/drivers/net/can/softing/Kconfig b/drivers/net/can/softing/Kconfig index 8ba81b3ddd90..5de46a9a77bb 100644 --- a/drivers/net/can/softing/Kconfig +++ b/drivers/net/can/softing/Kconfig @@ -18,7 +18,7 @@ config CAN_SOFTING config CAN_SOFTING_CS tristate "Softing Gmbh CAN pcmcia cards" depends on PCMCIA - select CAN_SOFTING + depends on CAN_SOFTING ---help--- Support for PCMCIA cards from Softing Gmbh & some cards from Vector Gmbh. diff --git a/drivers/net/can/softing/softing_cs.c b/drivers/net/can/softing/softing_cs.c index 300fe75dd1a7..c11bb4de8630 100644 --- a/drivers/net/can/softing/softing_cs.c +++ b/drivers/net/can/softing/softing_cs.c @@ -19,6 +19,7 @@ #include <linux/module.h> #include <linux/kernel.h> +#include <linux/slab.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c index 7ff170cbc7dc..2d2d28f58e91 100644 --- a/drivers/net/cnic.c +++ b/drivers/net/cnic.c @@ -65,7 +65,14 @@ static LIST_HEAD(cnic_udev_list); static DEFINE_RWLOCK(cnic_dev_lock); static DEFINE_MUTEX(cnic_lock); -static struct cnic_ulp_ops *cnic_ulp_tbl[MAX_CNIC_ULP_TYPE]; +static struct cnic_ulp_ops __rcu *cnic_ulp_tbl[MAX_CNIC_ULP_TYPE]; + +/* helper function, assuming cnic_lock is held */ +static inline struct cnic_ulp_ops *cnic_ulp_tbl_prot(int type) +{ + return rcu_dereference_protected(cnic_ulp_tbl[type], + lockdep_is_held(&cnic_lock)); +} static int cnic_service_bnx2(void *, void *); static int cnic_service_bnx2x(void *, void *); @@ -435,7 +442,7 @@ int cnic_register_driver(int ulp_type, struct cnic_ulp_ops *ulp_ops) return -EINVAL; } mutex_lock(&cnic_lock); - if (cnic_ulp_tbl[ulp_type]) { + if (cnic_ulp_tbl_prot(ulp_type)) { pr_err("%s: Type %d has already been registered\n", __func__, ulp_type); mutex_unlock(&cnic_lock); @@ -478,7 +485,7 @@ int cnic_unregister_driver(int ulp_type) return -EINVAL; } mutex_lock(&cnic_lock); - ulp_ops = cnic_ulp_tbl[ulp_type]; + ulp_ops = cnic_ulp_tbl_prot(ulp_type); if (!ulp_ops) { pr_err("%s: Type %d has not been registered\n", __func__, ulp_type); @@ -529,7 +536,7 @@ static int cnic_register_device(struct cnic_dev *dev, int ulp_type, return -EINVAL; } mutex_lock(&cnic_lock); - if (cnic_ulp_tbl[ulp_type] == NULL) { + if (cnic_ulp_tbl_prot(ulp_type) == NULL) { pr_err("%s: Driver with type %d has not been registered\n", __func__, ulp_type); mutex_unlock(&cnic_lock); @@ -544,7 +551,7 @@ static int cnic_register_device(struct cnic_dev *dev, int ulp_type, clear_bit(ULP_F_START, &cp->ulp_flags[ulp_type]); cp->ulp_handle[ulp_type] = ulp_ctx; - ulp_ops = cnic_ulp_tbl[ulp_type]; + ulp_ops = cnic_ulp_tbl_prot(ulp_type); rcu_assign_pointer(cp->ulp_ops[ulp_type], ulp_ops); cnic_hold(dev); @@ -2953,7 +2960,8 @@ static void cnic_ulp_stop(struct cnic_dev *dev) struct cnic_ulp_ops *ulp_ops; mutex_lock(&cnic_lock); - ulp_ops = cp->ulp_ops[if_type]; + ulp_ops = rcu_dereference_protected(cp->ulp_ops[if_type], + lockdep_is_held(&cnic_lock)); if (!ulp_ops) { mutex_unlock(&cnic_lock); continue; @@ -2977,7 +2985,8 @@ static void cnic_ulp_start(struct cnic_dev *dev) struct cnic_ulp_ops *ulp_ops; mutex_lock(&cnic_lock); - ulp_ops = cp->ulp_ops[if_type]; + ulp_ops = rcu_dereference_protected(cp->ulp_ops[if_type], + lockdep_is_held(&cnic_lock)); if (!ulp_ops || !ulp_ops->cnic_start) { mutex_unlock(&cnic_lock); continue; @@ -3041,7 +3050,7 @@ static void cnic_ulp_init(struct cnic_dev *dev) struct cnic_ulp_ops *ulp_ops; mutex_lock(&cnic_lock); - ulp_ops = cnic_ulp_tbl[i]; + ulp_ops = cnic_ulp_tbl_prot(i); if (!ulp_ops || !ulp_ops->cnic_init) { mutex_unlock(&cnic_lock); continue; @@ -3065,7 +3074,7 @@ static void cnic_ulp_exit(struct cnic_dev *dev) struct cnic_ulp_ops *ulp_ops; mutex_lock(&cnic_lock); - ulp_ops = cnic_ulp_tbl[i]; + ulp_ops = cnic_ulp_tbl_prot(i); if (!ulp_ops || !ulp_ops->cnic_exit) { mutex_unlock(&cnic_lock); continue; @@ -4170,6 +4179,14 @@ static void cnic_enable_bnx2_int(struct cnic_dev *dev) BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | cp->last_status_idx); } +static void cnic_get_bnx2_iscsi_info(struct cnic_dev *dev) +{ + u32 max_conn; + + max_conn = cnic_reg_rd_ind(dev, BNX2_FW_MAX_ISCSI_CONN); + dev->max_iscsi_conn = max_conn; +} + static void cnic_disable_bnx2_int_sync(struct cnic_dev *dev) { struct cnic_local *cp = dev->cnic_priv; @@ -4494,6 +4511,8 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev) return err; } + cnic_get_bnx2_iscsi_info(dev); + return 0; } @@ -4705,129 +4724,6 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev, cp->rx_cons = *cp->rx_cons_ptr; } -static int cnic_read_bnx2x_iscsi_mac(struct cnic_dev *dev, u32 upper_addr, - u32 lower_addr) -{ - u32 val; - u8 mac[6]; - - val = CNIC_RD(dev, upper_addr); - - mac[0] = (u8) (val >> 8); - mac[1] = (u8) val; - - val = CNIC_RD(dev, lower_addr); - - mac[2] = (u8) (val >> 24); - mac[3] = (u8) (val >> 16); - mac[4] = (u8) (val >> 8); - mac[5] = (u8) val; - - if (is_valid_ether_addr(mac)) { - memcpy(dev->mac_addr, mac, 6); - return 0; - } else { - return -EINVAL; - } -} - -static void cnic_get_bnx2x_iscsi_info(struct cnic_dev *dev) -{ - struct cnic_local *cp = dev->cnic_priv; - u32 base, base2, addr, addr1, val; - int port = CNIC_PORT(cp); - - dev->max_iscsi_conn = 0; - base = CNIC_RD(dev, MISC_REG_SHARED_MEM_ADDR); - if (base == 0) - return; - - base2 = CNIC_RD(dev, (CNIC_PATH(cp) ? MISC_REG_GENERIC_CR_1 : - MISC_REG_GENERIC_CR_0)); - addr = BNX2X_SHMEM_ADDR(base, - dev_info.port_hw_config[port].iscsi_mac_upper); - - addr1 = BNX2X_SHMEM_ADDR(base, - dev_info.port_hw_config[port].iscsi_mac_lower); - - cnic_read_bnx2x_iscsi_mac(dev, addr, addr1); - - addr = BNX2X_SHMEM_ADDR(base, validity_map[port]); - val = CNIC_RD(dev, addr); - - if (!(val & SHR_MEM_VALIDITY_LIC_NO_KEY_IN_EFFECT)) { - u16 val16; - - addr = BNX2X_SHMEM_ADDR(base, - drv_lic_key[port].max_iscsi_init_conn); - val16 = CNIC_RD16(dev, addr); - - if (val16) - val16 ^= 0x1e1e; - dev->max_iscsi_conn = val16; - } - - if (BNX2X_CHIP_IS_E2(cp->chip_id)) - dev->max_fcoe_conn = BNX2X_FCOE_NUM_CONNECTIONS; - - if (BNX2X_CHIP_IS_E1H(cp->chip_id) || BNX2X_CHIP_IS_E2(cp->chip_id)) { - int func = CNIC_FUNC(cp); - u32 mf_cfg_addr; - - if (BNX2X_SHMEM2_HAS(base2, mf_cfg_addr)) - mf_cfg_addr = CNIC_RD(dev, BNX2X_SHMEM2_ADDR(base2, - mf_cfg_addr)); - else - mf_cfg_addr = base + BNX2X_SHMEM_MF_BLK_OFFSET; - - if (BNX2X_CHIP_IS_E2(cp->chip_id)) { - /* Must determine if the MF is SD vs SI mode */ - addr = BNX2X_SHMEM_ADDR(base, - dev_info.shared_feature_config.config); - val = CNIC_RD(dev, addr); - if ((val & SHARED_FEAT_CFG_FORCE_SF_MODE_MASK) == - SHARED_FEAT_CFG_FORCE_SF_MODE_SWITCH_INDEPT) { - int rc; - - /* MULTI_FUNCTION_SI mode */ - addr = BNX2X_MF_CFG_ADDR(mf_cfg_addr, - func_ext_config[func].func_cfg); - val = CNIC_RD(dev, addr); - if (!(val & MACP_FUNC_CFG_FLAGS_ISCSI_OFFLOAD)) - dev->max_iscsi_conn = 0; - - if (!(val & MACP_FUNC_CFG_FLAGS_FCOE_OFFLOAD)) - dev->max_fcoe_conn = 0; - - addr = BNX2X_MF_CFG_ADDR(mf_cfg_addr, - func_ext_config[func]. - iscsi_mac_addr_upper); - addr1 = BNX2X_MF_CFG_ADDR(mf_cfg_addr, - func_ext_config[func]. - iscsi_mac_addr_lower); - rc = cnic_read_bnx2x_iscsi_mac(dev, addr, - addr1); - if (rc && func > 1) - dev->max_iscsi_conn = 0; - - return; - } - } - - addr = BNX2X_MF_CFG_ADDR(mf_cfg_addr, - func_mf_config[func].e1hov_tag); - - val = CNIC_RD(dev, addr); - val &= FUNC_MF_CFG_E1HOV_TAG_MASK; - if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) { - dev->max_fcoe_conn = 0; - dev->max_iscsi_conn = 0; - } - } - if (!is_valid_ether_addr(dev->mac_addr)) - dev->max_iscsi_conn = 0; -} - static void cnic_init_bnx2x_kcq(struct cnic_dev *dev) { struct cnic_local *cp = dev->cnic_priv; @@ -4909,8 +4805,6 @@ static int cnic_start_bnx2x_hw(struct cnic_dev *dev) cnic_init_bnx2x_kcq(dev); - cnic_get_bnx2x_iscsi_info(dev); - /* Only 1 EQ */ CNIC_WR16(dev, cp->kcq1.io_addr, MAX_KCQ_IDX); CNIC_WR(dev, BAR_CSTRORM_INTMEM + @@ -5343,6 +5237,14 @@ static struct cnic_dev *init_bnx2x_cnic(struct net_device *dev) cdev->pcidev = pdev; cp->chip_id = ethdev->chip_id; + if (!(ethdev->drv_state & CNIC_DRV_STATE_NO_ISCSI)) + cdev->max_iscsi_conn = ethdev->max_iscsi_conn; + if (BNX2X_CHIP_IS_E2(cp->chip_id) && + !(ethdev->drv_state & CNIC_DRV_STATE_NO_FCOE)) + cdev->max_fcoe_conn = ethdev->max_fcoe_conn; + + memcpy(cdev->mac_addr, ethdev->iscsi_mac, 6); + cp->cnic_ops = &cnic_bnx2x_ops; cp->start_hw = cnic_start_bnx2x_hw; cp->stop_hw = cnic_stop_bnx2x_hw; diff --git a/drivers/net/cnic.h b/drivers/net/cnic.h index b328f6c924c3..4456260c653c 100644 --- a/drivers/net/cnic.h +++ b/drivers/net/cnic.h @@ -220,7 +220,7 @@ struct cnic_local { #define ULP_F_INIT 0 #define ULP_F_START 1 #define ULP_F_CALL_PENDING 2 - struct cnic_ulp_ops *ulp_ops[MAX_CNIC_ULP_TYPE]; + struct cnic_ulp_ops __rcu *ulp_ops[MAX_CNIC_ULP_TYPE]; unsigned long cnic_local_flags; #define CNIC_LCL_FL_KWQ_INIT 0x0 diff --git a/drivers/net/cnic_if.h b/drivers/net/cnic_if.h index 9f44e0ffe003..e01b49ee3591 100644 --- a/drivers/net/cnic_if.h +++ b/drivers/net/cnic_if.h @@ -12,8 +12,8 @@ #ifndef CNIC_IF_H #define CNIC_IF_H -#define CNIC_MODULE_VERSION "2.2.12" -#define CNIC_MODULE_RELDATE "Jan 03, 2011" +#define CNIC_MODULE_VERSION "2.2.13" +#define CNIC_MODULE_RELDATE "Jan 31, 2011" #define CNIC_ULP_RDMA 0 #define CNIC_ULP_ISCSI 1 @@ -159,6 +159,9 @@ struct cnic_eth_dev { u32 drv_state; #define CNIC_DRV_STATE_REGD 0x00000001 #define CNIC_DRV_STATE_USING_MSIX 0x00000002 +#define CNIC_DRV_STATE_NO_ISCSI_OOO 0x00000004 +#define CNIC_DRV_STATE_NO_ISCSI 0x00000008 +#define CNIC_DRV_STATE_NO_FCOE 0x00000010 u32 chip_id; u32 max_kwqe_pending; struct pci_dev *pdev; @@ -176,6 +179,7 @@ struct cnic_eth_dev { u32 fcoe_init_cid; u16 iscsi_l2_client_id; u16 iscsi_l2_cid; + u8 iscsi_mac[ETH_ALEN]; int num_irq; struct cnic_irq irq_arr[MAX_CNIC_VEC]; diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index ef02aa68c926..862804f32b6e 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -186,9 +186,10 @@ static struct net_device *get_iff_from_mac(struct adapter *adapter, dev = NULL; if (grp) dev = vlan_group_get_device(grp, vlan); - } else + } else if (netif_is_bond_slave(dev)) { while (dev->master) dev = dev->master; + } return dev; } } @@ -967,8 +968,6 @@ static int nb_callback(struct notifier_block *self, unsigned long event, cxgb_neigh_update((struct neighbour *)ctx); break; } - case (NETEVENT_PMTU_UPDATE): - break; case (NETEVENT_REDIRECT):{ struct netevent_redirect *nr = ctx; cxgb_redirect(nr->old, nr->new); diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c index ec35d458102c..5352c8a23f4d 100644 --- a/drivers/net/cxgb4/cxgb4_main.c +++ b/drivers/net/cxgb4/cxgb4_main.c @@ -2471,7 +2471,6 @@ static int netevent_cb(struct notifier_block *nb, unsigned long event, case NETEVENT_NEIGH_UPDATE: check_neigh_update(data); break; - case NETEVENT_PMTU_UPDATE: case NETEVENT_REDIRECT: default: break; diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c index 56166ae2059f..6aad64df4dcb 100644 --- a/drivers/net/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/cxgb4vf/cxgb4vf_main.c @@ -2040,7 +2040,7 @@ static int __devinit setup_debugfs(struct adapter *adapter) { int i; - BUG_ON(adapter->debugfs_root == NULL); + BUG_ON(IS_ERR_OR_NULL(adapter->debugfs_root)); /* * Debugfs support is best effort. @@ -2061,7 +2061,7 @@ static int __devinit setup_debugfs(struct adapter *adapter) */ static void cleanup_debugfs(struct adapter *adapter) { - BUG_ON(adapter->debugfs_root == NULL); + BUG_ON(IS_ERR_OR_NULL(adapter->debugfs_root)); /* * Unlike our sister routine cleanup_proc(), we don't need to remove @@ -2489,17 +2489,6 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev, struct net_device *netdev; /* - * Vet our module parameters. - */ - if (msi != MSI_MSIX && msi != MSI_MSI) { - dev_err(&pdev->dev, "bad module parameter msi=%d; must be %d" - " (MSI-X or MSI) or %d (MSI)\n", msi, MSI_MSIX, - MSI_MSI); - err = -EINVAL; - goto err_out; - } - - /* * Print our driver banner the first time we're called to initialize a * device. */ @@ -2711,11 +2700,11 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev, /* * Set up our debugfs entries. */ - if (cxgb4vf_debugfs_root) { + if (!IS_ERR_OR_NULL(cxgb4vf_debugfs_root)) { adapter->debugfs_root = debugfs_create_dir(pci_name(pdev), cxgb4vf_debugfs_root); - if (adapter->debugfs_root == NULL) + if (IS_ERR_OR_NULL(adapter->debugfs_root)) dev_warn(&pdev->dev, "could not create debugfs" " directory"); else @@ -2770,7 +2759,7 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev, */ err_free_debugfs: - if (adapter->debugfs_root) { + if (!IS_ERR_OR_NULL(adapter->debugfs_root)) { cleanup_debugfs(adapter); debugfs_remove_recursive(adapter->debugfs_root); } @@ -2802,7 +2791,6 @@ err_release_regions: err_disable_device: pci_disable_device(pdev); -err_out: return err; } @@ -2840,7 +2828,7 @@ static void __devexit cxgb4vf_pci_remove(struct pci_dev *pdev) /* * Tear down our debugfs entries. */ - if (adapter->debugfs_root) { + if (!IS_ERR_OR_NULL(adapter->debugfs_root)) { cleanup_debugfs(adapter); debugfs_remove_recursive(adapter->debugfs_root); } @@ -2874,6 +2862,46 @@ static void __devexit cxgb4vf_pci_remove(struct pci_dev *pdev) } /* + * "Shutdown" quiesce the device, stopping Ingress Packet and Interrupt + * delivery. + */ +static void __devexit cxgb4vf_pci_shutdown(struct pci_dev *pdev) +{ + struct adapter *adapter; + int pidx; + + adapter = pci_get_drvdata(pdev); + if (!adapter) + return; + + /* + * Disable all Virtual Interfaces. This will shut down the + * delivery of all ingress packets into the chip for these + * Virtual Interfaces. + */ + for_each_port(adapter, pidx) { + struct net_device *netdev; + struct port_info *pi; + + if (!test_bit(pidx, &adapter->registered_device_map)) + continue; + + netdev = adapter->port[pidx]; + if (!netdev) + continue; + + pi = netdev_priv(netdev); + t4vf_enable_vi(adapter, pi->viid, false, false); + } + + /* + * Free up all Queues which will prevent further DMA and + * Interrupts allowing various internal pathways to drain. + */ + t4vf_free_sge_resources(adapter); +} + +/* * PCI Device registration data structures. */ #define CH_DEVICE(devid, idx) \ @@ -2906,6 +2934,7 @@ static struct pci_driver cxgb4vf_driver = { .id_table = cxgb4vf_pci_tbl, .probe = cxgb4vf_pci_probe, .remove = __devexit_p(cxgb4vf_pci_remove), + .shutdown = __devexit_p(cxgb4vf_pci_shutdown), }; /* @@ -2915,14 +2944,25 @@ static int __init cxgb4vf_module_init(void) { int ret; + /* + * Vet our module parameters. + */ + if (msi != MSI_MSIX && msi != MSI_MSI) { + printk(KERN_WARNING KBUILD_MODNAME + ": bad module parameter msi=%d; must be %d" + " (MSI-X or MSI) or %d (MSI)\n", + msi, MSI_MSIX, MSI_MSI); + return -EINVAL; + } + /* Debugfs support is optional, just warn if this fails */ cxgb4vf_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!cxgb4vf_debugfs_root) + if (IS_ERR_OR_NULL(cxgb4vf_debugfs_root)) printk(KERN_WARNING KBUILD_MODNAME ": could not create" " debugfs entry, continuing\n"); ret = pci_register_driver(&cxgb4vf_driver); - if (ret < 0) + if (ret < 0 && !IS_ERR_OR_NULL(cxgb4vf_debugfs_root)) debugfs_remove(cxgb4vf_debugfs_root); return ret; } diff --git a/drivers/net/cxgb4vf/t4vf_hw.c b/drivers/net/cxgb4vf/t4vf_hw.c index 0f51c80475ce..192db226ec7f 100644 --- a/drivers/net/cxgb4vf/t4vf_hw.c +++ b/drivers/net/cxgb4vf/t4vf_hw.c @@ -171,7 +171,7 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size, delay_idx = 0; ms = delay[0]; - for (i = 0; i < 500; i += ms) { + for (i = 0; i < FW_CMD_MAX_TIMEOUT; i += ms) { if (sleep_ok) { ms = delay[delay_idx]; if (delay_idx < ARRAY_SIZE(delay) - 1) diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index e610e1369053..00bf595ebd67 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -364,6 +364,7 @@ struct e1000_adapter { /* structs defined in e1000_hw.h */ struct e1000_hw hw; + spinlock_t stats64_lock; struct e1000_hw_stats stats; struct e1000_phy_info phy_info; struct e1000_phy_stats phy_stats; @@ -494,7 +495,9 @@ extern int e1000e_setup_rx_resources(struct e1000_adapter *adapter); extern int e1000e_setup_tx_resources(struct e1000_adapter *adapter); extern void e1000e_free_rx_resources(struct e1000_adapter *adapter); extern void e1000e_free_tx_resources(struct e1000_adapter *adapter); -extern void e1000e_update_stats(struct e1000_adapter *adapter); +extern struct rtnl_link_stats64 *e1000e_get_stats64(struct net_device *netdev, + struct rtnl_link_stats64 + *stats); extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter); extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter); extern void e1000e_get_hw_control(struct e1000_adapter *adapter); diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index fa08b6336cfb..65ef9b5548d8 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -46,15 +46,15 @@ struct e1000_stats { }; #define E1000_STAT(str, m) { \ - .stat_string = str, \ - .type = E1000_STATS, \ - .sizeof_stat = sizeof(((struct e1000_adapter *)0)->m), \ - .stat_offset = offsetof(struct e1000_adapter, m) } + .stat_string = str, \ + .type = E1000_STATS, \ + .sizeof_stat = sizeof(((struct e1000_adapter *)0)->m), \ + .stat_offset = offsetof(struct e1000_adapter, m) } #define E1000_NETDEV_STAT(str, m) { \ - .stat_string = str, \ - .type = NETDEV_STATS, \ - .sizeof_stat = sizeof(((struct net_device *)0)->m), \ - .stat_offset = offsetof(struct net_device, m) } + .stat_string = str, \ + .type = NETDEV_STATS, \ + .sizeof_stat = sizeof(((struct rtnl_link_stats64 *)0)->m), \ + .stat_offset = offsetof(struct rtnl_link_stats64, m) } static const struct e1000_stats e1000_gstrings_stats[] = { E1000_STAT("rx_packets", stats.gprc), @@ -65,21 +65,21 @@ static const struct e1000_stats e1000_gstrings_stats[] = { E1000_STAT("tx_broadcast", stats.bptc), E1000_STAT("rx_multicast", stats.mprc), E1000_STAT("tx_multicast", stats.mptc), - E1000_NETDEV_STAT("rx_errors", stats.rx_errors), - E1000_NETDEV_STAT("tx_errors", stats.tx_errors), - E1000_NETDEV_STAT("tx_dropped", stats.tx_dropped), + E1000_NETDEV_STAT("rx_errors", rx_errors), + E1000_NETDEV_STAT("tx_errors", tx_errors), + E1000_NETDEV_STAT("tx_dropped", tx_dropped), E1000_STAT("multicast", stats.mprc), E1000_STAT("collisions", stats.colc), - E1000_NETDEV_STAT("rx_length_errors", stats.rx_length_errors), - E1000_NETDEV_STAT("rx_over_errors", stats.rx_over_errors), + E1000_NETDEV_STAT("rx_length_errors", rx_length_errors), + E1000_NETDEV_STAT("rx_over_errors", rx_over_errors), E1000_STAT("rx_crc_errors", stats.crcerrs), - E1000_NETDEV_STAT("rx_frame_errors", stats.rx_frame_errors), + E1000_NETDEV_STAT("rx_frame_errors", rx_frame_errors), E1000_STAT("rx_no_buffer_count", stats.rnbc), E1000_STAT("rx_missed_errors", stats.mpc), E1000_STAT("tx_aborted_errors", stats.ecol), E1000_STAT("tx_carrier_errors", stats.tncrs), - E1000_NETDEV_STAT("tx_fifo_errors", stats.tx_fifo_errors), - E1000_NETDEV_STAT("tx_heartbeat_errors", stats.tx_heartbeat_errors), + E1000_NETDEV_STAT("tx_fifo_errors", tx_fifo_errors), + E1000_NETDEV_STAT("tx_heartbeat_errors", tx_heartbeat_errors), E1000_STAT("tx_window_errors", stats.latecol), E1000_STAT("tx_abort_late_coll", stats.latecol), E1000_STAT("tx_deferred_ok", stats.dc), @@ -684,20 +684,13 @@ static int e1000_set_ringparam(struct net_device *netdev, rx_old = adapter->rx_ring; err = -ENOMEM; - tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); + tx_ring = kmemdup(tx_old, sizeof(struct e1000_ring), GFP_KERNEL); if (!tx_ring) goto err_alloc_tx; - /* - * use a memcpy to save any previously configured - * items like napi structs from having to be - * reinitialized - */ - memcpy(tx_ring, tx_old, sizeof(struct e1000_ring)); - rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); + rx_ring = kmemdup(rx_old, sizeof(struct e1000_ring), GFP_KERNEL); if (!rx_ring) goto err_alloc_rx; - memcpy(rx_ring, rx_old, sizeof(struct e1000_ring)); adapter->tx_ring = tx_ring; adapter->rx_ring = rx_ring; @@ -1255,7 +1248,6 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; u32 ctrl_reg = 0; - u32 stat_reg = 0; u16 phy_reg = 0; s32 ret_val = 0; @@ -1363,8 +1355,7 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter) * Set the ILOS bit on the fiber Nic if half duplex link is * detected. */ - stat_reg = er32(STATUS); - if ((stat_reg & E1000_STATUS_FD) == 0) + if ((er32(STATUS) & E1000_STATUS_FD) == 0) ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); } @@ -1972,8 +1963,15 @@ static int e1000_set_coalesce(struct net_device *netdev, static int e1000_nway_reset(struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); - if (netif_running(netdev)) - e1000e_reinit_locked(adapter); + + if (!netif_running(netdev)) + return -EAGAIN; + + if (!adapter->hw.mac.autoneg) + return -EINVAL; + + e1000e_reinit_locked(adapter); + return 0; } @@ -1982,14 +1980,15 @@ static void e1000_get_ethtool_stats(struct net_device *netdev, u64 *data) { struct e1000_adapter *adapter = netdev_priv(netdev); + struct rtnl_link_stats64 net_stats; int i; char *p = NULL; - e1000e_update_stats(adapter); + e1000e_get_stats64(netdev, &net_stats); for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) { switch (e1000_gstrings_stats[i].type) { case NETDEV_STATS: - p = (char *) netdev + + p = (char *) &net_stats + e1000_gstrings_stats[i].stat_offset; break; case E1000_STATS: @@ -2014,7 +2013,7 @@ static void e1000_get_strings(struct net_device *netdev, u32 stringset, switch (stringset) { case ETH_SS_TEST: - memcpy(data, *e1000_gstrings_test, sizeof(e1000_gstrings_test)); + memcpy(data, e1000_gstrings_test, sizeof(e1000_gstrings_test)); break; case ETH_SS_STATS: for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) { diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index fb46974cfec1..232b42b7f7ce 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -2104,7 +2104,6 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw) { union ich8_hws_flash_status hsfsts; s32 ret_val = -E1000_ERR_NVM; - s32 i = 0; hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); @@ -2140,6 +2139,8 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw) ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval); ret_val = 0; } else { + s32 i = 0; + /* * Otherwise poll for sometime so the current * cycle has a chance to end before giving up. diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index 68aa1749bf66..96921de5df2e 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -1978,15 +1978,15 @@ static s32 e1000_ready_nvm_eeprom(struct e1000_hw *hw) { struct e1000_nvm_info *nvm = &hw->nvm; u32 eecd = er32(EECD); - u16 timeout = 0; u8 spi_stat_reg; if (nvm->type == e1000_nvm_eeprom_spi) { + u16 timeout = NVM_MAX_RETRY_SPI; + /* Clear SK and CS */ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); ew32(EECD, eecd); udelay(1); - timeout = NVM_MAX_RETRY_SPI; /* * Read "Status Register" repeatedly until the LSB is cleared. diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 3065870cf2a7..ec0b803c501e 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -900,8 +900,6 @@ next_desc: adapter->total_rx_bytes += total_rx_bytes; adapter->total_rx_packets += total_rx_packets; - netdev->stats.rx_bytes += total_rx_bytes; - netdev->stats.rx_packets += total_rx_packets; return cleaned; } @@ -937,6 +935,9 @@ static void e1000_print_hw_hang(struct work_struct *work) u16 phy_status, phy_1000t_status, phy_ext_status; u16 pci_status; + if (test_bit(__E1000_DOWN, &adapter->state)) + return; + e1e_rphy(hw, PHY_STATUS, &phy_status); e1e_rphy(hw, PHY_1000T_STATUS, &phy_1000t_status); e1e_rphy(hw, PHY_EXT_STATUS, &phy_ext_status); @@ -1057,8 +1058,6 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter) } adapter->total_tx_bytes += total_tx_bytes; adapter->total_tx_packets += total_tx_packets; - netdev->stats.tx_bytes += total_tx_bytes; - netdev->stats.tx_packets += total_tx_packets; return count < tx_ring->count; } @@ -1245,8 +1244,6 @@ next_desc: adapter->total_rx_bytes += total_rx_bytes; adapter->total_rx_packets += total_rx_packets; - netdev->stats.rx_bytes += total_rx_bytes; - netdev->stats.rx_packets += total_rx_packets; return cleaned; } @@ -1426,8 +1423,6 @@ next_desc: adapter->total_rx_bytes += total_rx_bytes; adapter->total_rx_packets += total_rx_packets; - netdev->stats.rx_bytes += total_rx_bytes; - netdev->stats.rx_packets += total_rx_packets; return cleaned; } @@ -1506,6 +1501,9 @@ static void e1000e_downshift_workaround(struct work_struct *work) struct e1000_adapter *adapter = container_of(work, struct e1000_adapter, downshift_task); + if (test_bit(__E1000_DOWN, &adapter->state)) + return; + e1000e_gig_downshift_workaround_ich8lan(&adapter->hw); } @@ -1851,7 +1849,9 @@ static int e1000_request_msix(struct e1000_adapter *adapter) int err = 0, vector = 0; if (strlen(netdev->name) < (IFNAMSIZ - 5)) - sprintf(adapter->rx_ring->name, "%s-rx-0", netdev->name); + snprintf(adapter->rx_ring->name, + sizeof(adapter->rx_ring->name) - 1, + "%s-rx-0", netdev->name); else memcpy(adapter->rx_ring->name, netdev->name, IFNAMSIZ); err = request_irq(adapter->msix_entries[vector].vector, @@ -1864,7 +1864,9 @@ static int e1000_request_msix(struct e1000_adapter *adapter) vector++; if (strlen(netdev->name) < (IFNAMSIZ - 5)) - sprintf(adapter->tx_ring->name, "%s-tx-0", netdev->name); + snprintf(adapter->tx_ring->name, + sizeof(adapter->tx_ring->name) - 1, + "%s-tx-0", netdev->name); else memcpy(adapter->tx_ring->name, netdev->name, IFNAMSIZ); err = request_irq(adapter->msix_entries[vector].vector, @@ -2728,7 +2730,6 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; u32 rctl, rfctl; - u32 psrctl = 0; u32 pages = 0; /* Workaround Si errata on 82579 - configure jumbo frame flow */ @@ -2827,6 +2828,8 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter) adapter->rx_ps_pages = 0; if (adapter->rx_ps_pages) { + u32 psrctl = 0; + /* Configure extra packet-split registers */ rfctl = er32(RFCTL); rfctl |= E1000_RFCTL_EXTEN; @@ -3028,7 +3031,6 @@ static void e1000_set_multi(struct net_device *netdev) struct netdev_hw_addr *ha; u8 *mta_list; u32 rctl; - int i; /* Check for Promiscuous and All Multicast modes */ @@ -3051,12 +3053,13 @@ static void e1000_set_multi(struct net_device *netdev) ew32(RCTL, rctl); if (!netdev_mc_empty(netdev)) { + int i = 0; + mta_list = kmalloc(netdev_mc_count(netdev) * 6, GFP_ATOMIC); if (!mta_list) return; /* prepare a packed array of only addresses. */ - i = 0; netdev_for_each_mc_addr(ha, netdev) memcpy(mta_list + (i++ * ETH_ALEN), ha->addr, ETH_ALEN); @@ -3338,6 +3341,23 @@ int e1000e_up(struct e1000_adapter *adapter) return 0; } +static void e1000e_flush_descriptors(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + + if (!(adapter->flags2 & FLAG2_DMA_BURST)) + return; + + /* flush pending descriptor writebacks to memory */ + ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD); + ew32(RDTR, adapter->rx_int_delay | E1000_RDTR_FPD); + + /* execute the writes immediately */ + e1e_flush(); +} + +static void e1000e_update_stats(struct e1000_adapter *adapter); + void e1000e_down(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; @@ -3372,11 +3392,19 @@ void e1000e_down(struct e1000_adapter *adapter) del_timer_sync(&adapter->phy_info_timer); netif_carrier_off(netdev); + + spin_lock(&adapter->stats64_lock); + e1000e_update_stats(adapter); + spin_unlock(&adapter->stats64_lock); + adapter->link_speed = 0; adapter->link_duplex = 0; if (!pci_channel_offline(adapter->pdev)) e1000e_reset(adapter); + + e1000e_flush_descriptors(adapter); + e1000_clean_tx_ring(adapter); e1000_clean_rx_ring(adapter); @@ -3413,6 +3441,8 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter) adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN; + spin_lock_init(&adapter->stats64_lock); + e1000e_set_interrupt_capability(adapter); if (e1000_alloc_queues(adapter)) @@ -3765,6 +3795,10 @@ static void e1000e_update_phy_task(struct work_struct *work) { struct e1000_adapter *adapter = container_of(work, struct e1000_adapter, update_phy_task); + + if (test_bit(__E1000_DOWN, &adapter->state)) + return; + e1000_get_phy_info(&adapter->hw); } @@ -3775,6 +3809,10 @@ static void e1000e_update_phy_task(struct work_struct *work) static void e1000_update_phy_info(unsigned long data) { struct e1000_adapter *adapter = (struct e1000_adapter *) data; + + if (test_bit(__E1000_DOWN, &adapter->state)) + return; + schedule_work(&adapter->update_phy_task); } @@ -3886,7 +3924,7 @@ release: * e1000e_update_stats - Update the board statistics counters * @adapter: board private structure **/ -void e1000e_update_stats(struct e1000_adapter *adapter) +static void e1000e_update_stats(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; struct e1000_hw *hw = &adapter->hw; @@ -3998,10 +4036,11 @@ static void e1000_phy_read_status(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; struct e1000_phy_regs *phy = &adapter->phy_regs; - int ret_val; if ((er32(STATUS) & E1000_STATUS_LU) && (adapter->hw.phy.media_type == e1000_media_type_copper)) { + int ret_val; + ret_val = e1e_rphy(hw, PHY_CONTROL, &phy->bmcr); ret_val |= e1e_rphy(hw, PHY_STATUS, &phy->bmsr); ret_val |= e1e_rphy(hw, PHY_AUTONEG_ADV, &phy->advertise); @@ -4147,7 +4186,9 @@ static void e1000_watchdog_task(struct work_struct *work) struct e1000_ring *tx_ring = adapter->tx_ring; struct e1000_hw *hw = &adapter->hw; u32 link, tctl; - int tx_pending = 0; + + if (test_bit(__E1000_DOWN, &adapter->state)) + return; link = e1000e_has_link(adapter); if ((netif_carrier_ok(netdev)) && link) { @@ -4285,7 +4326,9 @@ static void e1000_watchdog_task(struct work_struct *work) } link_up: + spin_lock(&adapter->stats64_lock); e1000e_update_stats(adapter); + spin_unlock(&adapter->stats64_lock); mac->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old; adapter->tpt_old = adapter->stats.tpt; @@ -4299,20 +4342,17 @@ link_up: e1000e_update_adaptive(&adapter->hw); - if (!netif_carrier_ok(netdev)) { - tx_pending = (e1000_desc_unused(tx_ring) + 1 < - tx_ring->count); - if (tx_pending) { - /* - * We've lost link, so the controller stops DMA, - * but we've got queued Tx work that's never going - * to get done, so reset controller to flush Tx. - * (Do the reset outside of interrupt context). - */ - schedule_work(&adapter->reset_task); - /* return immediately since reset is imminent */ - return; - } + if (!netif_carrier_ok(netdev) && + (e1000_desc_unused(tx_ring) + 1 < tx_ring->count)) { + /* + * We've lost link, so the controller stops DMA, + * but we've got queued Tx work that's never going + * to get done, so reset controller to flush Tx. + * (Do the reset outside of interrupt context). + */ + schedule_work(&adapter->reset_task); + /* return immediately since reset is imminent */ + return; } /* Simple mode for Interrupt Throttle Rate (ITR) */ @@ -4337,19 +4377,12 @@ link_up: else ew32(ICS, E1000_ICS_RXDMT0); + /* flush pending descriptors to memory before detecting Tx hang */ + e1000e_flush_descriptors(adapter); + /* Force detection of hung controller every watchdog period */ adapter->detect_tx_hung = 1; - /* flush partial descriptors to memory before detecting Tx hang */ - if (adapter->flags2 & FLAG2_DMA_BURST) { - ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD); - ew32(RDTR, adapter->rx_int_delay | E1000_RDTR_FPD); - /* - * no need to flush the writes because the timeout code does - * an er32 first thing - */ - } - /* * With 82571 controllers, LAA may be overwritten due to controller * reset from the other port. Set the appropriate LAA in RAR[0] @@ -4383,13 +4416,13 @@ static int e1000_tso(struct e1000_adapter *adapter, u32 cmd_length = 0; u16 ipcse = 0, tucse, mss; u8 ipcss, ipcso, tucss, tucso, hdr_len; - int err; if (!skb_is_gso(skb)) return 0; if (skb_header_cloned(skb)) { - err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); + int err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); + if (err) return err; } @@ -4887,6 +4920,10 @@ static void e1000_reset_task(struct work_struct *work) struct e1000_adapter *adapter; adapter = container_of(work, struct e1000_adapter, reset_task); + /* don't run the task if already down */ + if (test_bit(__E1000_DOWN, &adapter->state)) + return; + if (!((adapter->flags & FLAG_RX_NEEDS_RESTART) && (adapter->flags & FLAG_RX_RESTART_NOW))) { e1000e_dump(adapter); @@ -4896,16 +4933,55 @@ static void e1000_reset_task(struct work_struct *work) } /** - * e1000_get_stats - Get System Network Statistics + * e1000_get_stats64 - Get System Network Statistics * @netdev: network interface device structure + * @stats: rtnl_link_stats64 pointer * * Returns the address of the device statistics structure. - * The statistics are actually updated from the timer callback. **/ -static struct net_device_stats *e1000_get_stats(struct net_device *netdev) +struct rtnl_link_stats64 *e1000e_get_stats64(struct net_device *netdev, + struct rtnl_link_stats64 *stats) { - /* only return the current stats */ - return &netdev->stats; + struct e1000_adapter *adapter = netdev_priv(netdev); + + memset(stats, 0, sizeof(struct rtnl_link_stats64)); + spin_lock(&adapter->stats64_lock); + e1000e_update_stats(adapter); + /* Fill out the OS statistics structure */ + stats->rx_bytes = adapter->stats.gorc; + stats->rx_packets = adapter->stats.gprc; + stats->tx_bytes = adapter->stats.gotc; + stats->tx_packets = adapter->stats.gptc; + stats->multicast = adapter->stats.mprc; + stats->collisions = adapter->stats.colc; + + /* Rx Errors */ + + /* + * RLEC on some newer hardware can be incorrect so build + * our own version based on RUC and ROC + */ + stats->rx_errors = adapter->stats.rxerrc + + adapter->stats.crcerrs + adapter->stats.algnerrc + + adapter->stats.ruc + adapter->stats.roc + + adapter->stats.cexterr; + stats->rx_length_errors = adapter->stats.ruc + + adapter->stats.roc; + stats->rx_crc_errors = adapter->stats.crcerrs; + stats->rx_frame_errors = adapter->stats.algnerrc; + stats->rx_missed_errors = adapter->stats.mpc; + + /* Tx Errors */ + stats->tx_errors = adapter->stats.ecol + + adapter->stats.latecol; + stats->tx_aborted_errors = adapter->stats.ecol; + stats->tx_window_errors = adapter->stats.latecol; + stats->tx_carrier_errors = adapter->stats.tncrs; + + /* Tx Dropped needs to be maintained elsewhere */ + + spin_unlock(&adapter->stats64_lock); + return stats; } /** @@ -5475,9 +5551,10 @@ static irqreturn_t e1000_intr_msix(int irq, void *data) { struct net_device *netdev = data; struct e1000_adapter *adapter = netdev_priv(netdev); - int vector, msix_irq; if (adapter->msix_entries) { + int vector, msix_irq; + vector = 0; msix_irq = adapter->msix_entries[vector].vector; disable_irq(msix_irq); @@ -5674,7 +5751,7 @@ static const struct net_device_ops e1000e_netdev_ops = { .ndo_open = e1000_open, .ndo_stop = e1000_close, .ndo_start_xmit = e1000_xmit_frame, - .ndo_get_stats = e1000_get_stats, + .ndo_get_stats64 = e1000e_get_stats64, .ndo_set_multicast_list = e1000_set_multi, .ndo_set_mac_address = e1000_set_mac, .ndo_change_mtu = e1000_change_mtu, diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c index 6bea051b134b..6ae31fcfb629 100644 --- a/drivers/net/e1000e/phy.c +++ b/drivers/net/e1000e/phy.c @@ -2409,9 +2409,7 @@ static u32 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg) s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data) { s32 ret_val; - u32 page_select = 0; u32 page = offset >> IGP_PAGE_SHIFT; - u32 page_shift = 0; ret_val = hw->phy.ops.acquire(hw); if (ret_val) @@ -2427,6 +2425,8 @@ s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data) hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset); if (offset > MAX_PHY_MULTI_PAGE_REG) { + u32 page_shift, page_select; + /* * Page select is register 31 for phy address 1 and 22 for * phy address 2 and 3. Page select is shifted only for @@ -2468,9 +2468,7 @@ out: s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data) { s32 ret_val; - u32 page_select = 0; u32 page = offset >> IGP_PAGE_SHIFT; - u32 page_shift = 0; ret_val = hw->phy.ops.acquire(hw); if (ret_val) @@ -2486,6 +2484,8 @@ s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data) hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset); if (offset > MAX_PHY_MULTI_PAGE_REG) { + u32 page_shift, page_select; + /* * Page select is register 31 for phy address 1 and 22 for * phy address 2 and 3. Page select is shifted only for diff --git a/drivers/net/enic/Makefile b/drivers/net/enic/Makefile index e7b6c31880ba..2e573be16c13 100644 --- a/drivers/net/enic/Makefile +++ b/drivers/net/enic/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_ENIC) := enic.o enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \ - enic_res.o vnic_dev.o vnic_rq.o vnic_vic.o + enic_res.o enic_dev.o vnic_dev.o vnic_rq.o vnic_vic.o diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index a937f49d9db7..aee5256e522b 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -32,13 +32,13 @@ #define DRV_NAME "enic" #define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver" -#define DRV_VERSION "1.4.1.10" -#define DRV_COPYRIGHT "Copyright 2008-2010 Cisco Systems, Inc" +#define DRV_VERSION "2.1.1.9" +#define DRV_COPYRIGHT "Copyright 2008-2011 Cisco Systems, Inc" #define ENIC_BARS_MAX 6 -#define ENIC_WQ_MAX 8 -#define ENIC_RQ_MAX 8 +#define ENIC_WQ_MAX 1 +#define ENIC_RQ_MAX 1 #define ENIC_CQ_MAX (ENIC_WQ_MAX + ENIC_RQ_MAX) #define ENIC_INTR_MAX (ENIC_CQ_MAX + 2) @@ -49,7 +49,7 @@ struct enic_msix_entry { void *devid; }; -#define ENIC_SET_APPLIED (1 << 0) +#define ENIC_PORT_REQUEST_APPLIED (1 << 0) #define ENIC_SET_REQUEST (1 << 1) #define ENIC_SET_NAME (1 << 2) #define ENIC_SET_INSTANCE (1 << 3) @@ -101,7 +101,6 @@ struct enic { /* receive queue cache line section */ ____cacheline_aligned struct vnic_rq rq[ENIC_RQ_MAX]; unsigned int rq_count; - int (*rq_alloc_buf)(struct vnic_rq *rq); u64 rq_truncated_pkts; u64 rq_bad_fcs; struct napi_struct napi[ENIC_RQ_MAX]; diff --git a/drivers/net/enic/enic_dev.c b/drivers/net/enic/enic_dev.c new file mode 100644 index 000000000000..37ad3a1c82ee --- /dev/null +++ b/drivers/net/enic/enic_dev.c @@ -0,0 +1,221 @@ +/* + * Copyright 2011 Cisco Systems, Inc. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include <linux/pci.h> +#include <linux/etherdevice.h> + +#include "vnic_dev.h" +#include "vnic_vic.h" +#include "enic_res.h" +#include "enic.h" +#include "enic_dev.h" + +int enic_dev_fw_info(struct enic *enic, struct vnic_devcmd_fw_info **fw_info) +{ + int err; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_fw_info(enic->vdev, fw_info); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +int enic_dev_stats_dump(struct enic *enic, struct vnic_stats **vstats) +{ + int err; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_stats_dump(enic->vdev, vstats); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +int enic_dev_add_station_addr(struct enic *enic) +{ + int err; + + if (!is_valid_ether_addr(enic->netdev->dev_addr)) + return -EADDRNOTAVAIL; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_add_addr(enic->vdev, enic->netdev->dev_addr); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +int enic_dev_del_station_addr(struct enic *enic) +{ + int err; + + if (!is_valid_ether_addr(enic->netdev->dev_addr)) + return -EADDRNOTAVAIL; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_del_addr(enic->vdev, enic->netdev->dev_addr); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +int enic_dev_packet_filter(struct enic *enic, int directed, int multicast, + int broadcast, int promisc, int allmulti) +{ + int err; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_packet_filter(enic->vdev, directed, + multicast, broadcast, promisc, allmulti); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +int enic_dev_add_addr(struct enic *enic, u8 *addr) +{ + int err; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_add_addr(enic->vdev, addr); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +int enic_dev_del_addr(struct enic *enic, u8 *addr) +{ + int err; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_del_addr(enic->vdev, addr); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +int enic_dev_notify_unset(struct enic *enic) +{ + int err; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_notify_unset(enic->vdev); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +int enic_dev_hang_notify(struct enic *enic) +{ + int err; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_hang_notify(enic->vdev); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic) +{ + int err; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_set_ig_vlan_rewrite_mode(enic->vdev, + IG_VLAN_REWRITE_MODE_PRIORITY_TAG_DEFAULT_VLAN); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +int enic_dev_enable(struct enic *enic) +{ + int err; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_enable_wait(enic->vdev); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +int enic_dev_disable(struct enic *enic) +{ + int err; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_disable(enic->vdev); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +int enic_vnic_dev_deinit(struct enic *enic) +{ + int err; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_deinit(enic->vdev); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +int enic_dev_init_prov(struct enic *enic, struct vic_provinfo *vp) +{ + int err; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_init_prov(enic->vdev, + (u8 *)vp, vic_provinfo_size(vp)); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +int enic_dev_init_done(struct enic *enic, int *done, int *error) +{ + int err; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_init_done(enic->vdev, done, error); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +/* rtnl lock is held */ +void enic_vlan_rx_add_vid(struct net_device *netdev, u16 vid) +{ + struct enic *enic = netdev_priv(netdev); + + spin_lock(&enic->devcmd_lock); + enic_add_vlan(enic, vid); + spin_unlock(&enic->devcmd_lock); +} + +/* rtnl lock is held */ +void enic_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) +{ + struct enic *enic = netdev_priv(netdev); + + spin_lock(&enic->devcmd_lock); + enic_del_vlan(enic, vid); + spin_unlock(&enic->devcmd_lock); +} diff --git a/drivers/net/enic/enic_dev.h b/drivers/net/enic/enic_dev.h new file mode 100644 index 000000000000..495f57fcb887 --- /dev/null +++ b/drivers/net/enic/enic_dev.h @@ -0,0 +1,41 @@ +/* + * Copyright 2011 Cisco Systems, Inc. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _ENIC_DEV_H_ +#define _ENIC_DEV_H_ + +int enic_dev_fw_info(struct enic *enic, struct vnic_devcmd_fw_info **fw_info); +int enic_dev_stats_dump(struct enic *enic, struct vnic_stats **vstats); +int enic_dev_add_station_addr(struct enic *enic); +int enic_dev_del_station_addr(struct enic *enic); +int enic_dev_packet_filter(struct enic *enic, int directed, int multicast, + int broadcast, int promisc, int allmulti); +int enic_dev_add_addr(struct enic *enic, u8 *addr); +int enic_dev_del_addr(struct enic *enic, u8 *addr); +void enic_vlan_rx_add_vid(struct net_device *netdev, u16 vid); +void enic_vlan_rx_kill_vid(struct net_device *netdev, u16 vid); +int enic_dev_notify_unset(struct enic *enic); +int enic_dev_hang_notify(struct enic *enic); +int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic); +int enic_dev_enable(struct enic *enic); +int enic_dev_disable(struct enic *enic); +int enic_vnic_dev_deinit(struct enic *enic); +int enic_dev_init_prov(struct enic *enic, struct vic_provinfo *vp); +int enic_dev_init_done(struct enic *enic, int *done, int *error); + +#endif /* _ENIC_DEV_H_ */ diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index a0af48c51fb3..4f1710e31eb4 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -44,6 +44,7 @@ #include "vnic_vic.h" #include "enic_res.h" #include "enic.h" +#include "enic_dev.h" #define ENIC_NOTIFY_TIMER_PERIOD (2 * HZ) #define WQ_ENET_MAX_DESC_LEN (1 << WQ_ENET_LEN_BITS) @@ -190,18 +191,6 @@ static int enic_get_settings(struct net_device *netdev, return 0; } -static int enic_dev_fw_info(struct enic *enic, - struct vnic_devcmd_fw_info **fw_info) -{ - int err; - - spin_lock(&enic->devcmd_lock); - err = vnic_dev_fw_info(enic->vdev, fw_info); - spin_unlock(&enic->devcmd_lock); - - return err; -} - static void enic_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) { @@ -246,17 +235,6 @@ static int enic_get_sset_count(struct net_device *netdev, int sset) } } -static int enic_dev_stats_dump(struct enic *enic, struct vnic_stats **vstats) -{ - int err; - - spin_lock(&enic->devcmd_lock); - err = vnic_dev_stats_dump(enic->vdev, vstats); - spin_unlock(&enic->devcmd_lock); - - return err; -} - static void enic_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data) { @@ -896,9 +874,10 @@ static struct net_device_stats *enic_get_stats(struct net_device *netdev) return net_stats; } -static void enic_reset_multicast_list(struct enic *enic) +static void enic_reset_addr_lists(struct enic *enic) { enic->mc_count = 0; + enic->uc_count = 0; enic->flags = 0; } @@ -919,32 +898,6 @@ static int enic_set_mac_addr(struct net_device *netdev, char *addr) return 0; } -static int enic_dev_add_station_addr(struct enic *enic) -{ - int err = 0; - - if (is_valid_ether_addr(enic->netdev->dev_addr)) { - spin_lock(&enic->devcmd_lock); - err = vnic_dev_add_addr(enic->vdev, enic->netdev->dev_addr); - spin_unlock(&enic->devcmd_lock); - } - - return err; -} - -static int enic_dev_del_station_addr(struct enic *enic) -{ - int err = 0; - - if (is_valid_ether_addr(enic->netdev->dev_addr)) { - spin_lock(&enic->devcmd_lock); - err = vnic_dev_del_addr(enic->vdev, enic->netdev->dev_addr); - spin_unlock(&enic->devcmd_lock); - } - - return err; -} - static int enic_set_mac_address_dynamic(struct net_device *netdev, void *p) { struct enic *enic = netdev_priv(netdev); @@ -989,42 +942,7 @@ static int enic_set_mac_address(struct net_device *netdev, void *p) return enic_dev_add_station_addr(enic); } -static int enic_dev_packet_filter(struct enic *enic, int directed, - int multicast, int broadcast, int promisc, int allmulti) -{ - int err; - - spin_lock(&enic->devcmd_lock); - err = vnic_dev_packet_filter(enic->vdev, directed, - multicast, broadcast, promisc, allmulti); - spin_unlock(&enic->devcmd_lock); - - return err; -} - -static int enic_dev_add_addr(struct enic *enic, u8 *addr) -{ - int err; - - spin_lock(&enic->devcmd_lock); - err = vnic_dev_add_addr(enic->vdev, addr); - spin_unlock(&enic->devcmd_lock); - - return err; -} - -static int enic_dev_del_addr(struct enic *enic, u8 *addr) -{ - int err; - - spin_lock(&enic->devcmd_lock); - err = vnic_dev_del_addr(enic->vdev, addr); - spin_unlock(&enic->devcmd_lock); - - return err; -} - -static void enic_add_multicast_addr_list(struct enic *enic) +static void enic_update_multicast_addr_list(struct enic *enic) { struct net_device *netdev = enic->netdev; struct netdev_hw_addr *ha; @@ -1079,7 +997,7 @@ static void enic_add_multicast_addr_list(struct enic *enic) enic->mc_count = mc_count; } -static void enic_add_unicast_addr_list(struct enic *enic) +static void enic_update_unicast_addr_list(struct enic *enic) { struct net_device *netdev = enic->netdev; struct netdev_hw_addr *ha; @@ -1156,9 +1074,9 @@ static void enic_set_rx_mode(struct net_device *netdev) } if (!promisc) { - enic_add_unicast_addr_list(enic); + enic_update_unicast_addr_list(enic); if (!allmulti) - enic_add_multicast_addr_list(enic); + enic_update_multicast_addr_list(enic); } } @@ -1170,26 +1088,6 @@ static void enic_vlan_rx_register(struct net_device *netdev, enic->vlan_group = vlan_group; } -/* rtnl lock is held */ -static void enic_vlan_rx_add_vid(struct net_device *netdev, u16 vid) -{ - struct enic *enic = netdev_priv(netdev); - - spin_lock(&enic->devcmd_lock); - enic_add_vlan(enic, vid); - spin_unlock(&enic->devcmd_lock); -} - -/* rtnl lock is held */ -static void enic_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) -{ - struct enic *enic = netdev_priv(netdev); - - spin_lock(&enic->devcmd_lock); - enic_del_vlan(enic, vid); - spin_unlock(&enic->devcmd_lock); -} - /* netif_tx_lock held, BHs disabled */ static void enic_tx_timeout(struct net_device *netdev) { @@ -1197,40 +1095,6 @@ static void enic_tx_timeout(struct net_device *netdev) schedule_work(&enic->reset); } -static int enic_vnic_dev_deinit(struct enic *enic) -{ - int err; - - spin_lock(&enic->devcmd_lock); - err = vnic_dev_deinit(enic->vdev); - spin_unlock(&enic->devcmd_lock); - - return err; -} - -static int enic_dev_init_prov(struct enic *enic, struct vic_provinfo *vp) -{ - int err; - - spin_lock(&enic->devcmd_lock); - err = vnic_dev_init_prov(enic->vdev, - (u8 *)vp, vic_provinfo_size(vp)); - spin_unlock(&enic->devcmd_lock); - - return err; -} - -static int enic_dev_init_done(struct enic *enic, int *done, int *error) -{ - int err; - - spin_lock(&enic->devcmd_lock); - err = vnic_dev_init_done(enic->vdev, done, error); - spin_unlock(&enic->devcmd_lock); - - return err; -} - static int enic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) { struct enic *enic = netdev_priv(netdev); @@ -1318,18 +1182,20 @@ static int enic_set_port_profile(struct enic *enic, u8 *mac) vic_provinfo_free(vp); if (err) return err; - - enic->pp.set |= ENIC_SET_APPLIED; break; case PORT_REQUEST_DISASSOCIATE: - enic->pp.set &= ~ENIC_SET_APPLIED; break; default: return -EINVAL; } + /* Set flag to indicate that the port assoc/disassoc + * request has been sent out to fw + */ + enic->pp.set |= ENIC_PORT_REQUEST_APPLIED; + return 0; } @@ -1379,9 +1245,6 @@ static int enic_set_vf_port(struct net_device *netdev, int vf, if (is_zero_ether_addr(netdev->dev_addr)) random_ether_addr(netdev->dev_addr); - } else if (new_pp.request == PORT_REQUEST_DISASSOCIATE) { - if (!is_zero_ether_addr(enic->pp.mac_addr)) - enic_dev_del_addr(enic, enic->pp.mac_addr); } memcpy(&enic->pp, &new_pp, sizeof(struct enic_port_profile)); @@ -1390,9 +1253,6 @@ static int enic_set_vf_port(struct net_device *netdev, int vf, if (err) goto set_port_profile_cleanup; - if (!is_zero_ether_addr(enic->pp.mac_addr)) - enic_dev_add_addr(enic, enic->pp.mac_addr); - set_port_profile_cleanup: memset(enic->pp.vf_mac, 0, ETH_ALEN); @@ -1411,7 +1271,7 @@ static int enic_get_vf_port(struct net_device *netdev, int vf, int err, error, done; u16 response = PORT_PROFILE_RESPONSE_SUCCESS; - if (!(enic->pp.set & ENIC_SET_APPLIED)) + if (!(enic->pp.set & ENIC_PORT_REQUEST_APPLIED)) return -ENODATA; err = enic_dev_init_done(enic, &done, &error); @@ -1489,62 +1349,6 @@ static int enic_rq_alloc_buf(struct vnic_rq *rq) return 0; } -static int enic_rq_alloc_buf_a1(struct vnic_rq *rq) -{ - struct rq_enet_desc *desc = vnic_rq_next_desc(rq); - - if (vnic_rq_posting_soon(rq)) { - - /* SW workaround for A0 HW erratum: if we're just about - * to write posted_index, insert a dummy desc - * of type resvd - */ - - rq_enet_desc_enc(desc, 0, RQ_ENET_TYPE_RESV2, 0); - vnic_rq_post(rq, 0, 0, 0, 0); - } else { - return enic_rq_alloc_buf(rq); - } - - return 0; -} - -static int enic_dev_hw_version(struct enic *enic, - enum vnic_dev_hw_version *hw_ver) -{ - int err; - - spin_lock(&enic->devcmd_lock); - err = vnic_dev_hw_version(enic->vdev, hw_ver); - spin_unlock(&enic->devcmd_lock); - - return err; -} - -static int enic_set_rq_alloc_buf(struct enic *enic) -{ - enum vnic_dev_hw_version hw_ver; - int err; - - err = enic_dev_hw_version(enic, &hw_ver); - if (err) - return err; - - switch (hw_ver) { - case VNIC_DEV_HW_VER_A1: - enic->rq_alloc_buf = enic_rq_alloc_buf_a1; - break; - case VNIC_DEV_HW_VER_A2: - case VNIC_DEV_HW_VER_UNKNOWN: - enic->rq_alloc_buf = enic_rq_alloc_buf; - break; - default: - return -ENODEV; - } - - return 0; -} - static void enic_rq_indicate_buf(struct vnic_rq *rq, struct cq_desc *cq_desc, struct vnic_rq_buf *buf, int skipped, void *opaque) @@ -1681,7 +1485,7 @@ static int enic_poll(struct napi_struct *napi, int budget) 0 /* don't unmask intr */, 0 /* don't reset intr timer */); - err = vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf); + err = vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf); /* Buffer allocation failed. Stay in polling * mode so we can try to fill the ring again. @@ -1731,7 +1535,7 @@ static int enic_poll_msix(struct napi_struct *napi, int budget) 0 /* don't unmask intr */, 0 /* don't reset intr timer */); - err = vnic_rq_fill(&enic->rq[rq], enic->rq_alloc_buf); + err = vnic_rq_fill(&enic->rq[rq], enic_rq_alloc_buf); /* Buffer allocation failed. Stay in polling mode * so we can try to fill the ring again. @@ -1901,39 +1705,6 @@ static int enic_dev_notify_set(struct enic *enic) return err; } -static int enic_dev_notify_unset(struct enic *enic) -{ - int err; - - spin_lock(&enic->devcmd_lock); - err = vnic_dev_notify_unset(enic->vdev); - spin_unlock(&enic->devcmd_lock); - - return err; -} - -static int enic_dev_enable(struct enic *enic) -{ - int err; - - spin_lock(&enic->devcmd_lock); - err = vnic_dev_enable_wait(enic->vdev); - spin_unlock(&enic->devcmd_lock); - - return err; -} - -static int enic_dev_disable(struct enic *enic) -{ - int err; - - spin_lock(&enic->devcmd_lock); - err = vnic_dev_disable(enic->vdev); - spin_unlock(&enic->devcmd_lock); - - return err; -} - static void enic_notify_timer_start(struct enic *enic) { switch (vnic_dev_get_intr_mode(enic->vdev)) { @@ -1967,7 +1738,7 @@ static int enic_open(struct net_device *netdev) } for (i = 0; i < enic->rq_count; i++) { - vnic_rq_fill(&enic->rq[i], enic->rq_alloc_buf); + vnic_rq_fill(&enic->rq[i], enic_rq_alloc_buf); /* Need at least one buffer on ring to get going */ if (vnic_rq_desc_used(&enic->rq[i]) == 0) { netdev_err(netdev, "Unable to alloc receive buffers\n"); @@ -2285,29 +2056,6 @@ static int enic_set_rss_nic_cfg(struct enic *enic) rss_hash_bits, rss_base_cpu, rss_enable); } -static int enic_dev_hang_notify(struct enic *enic) -{ - int err; - - spin_lock(&enic->devcmd_lock); - err = vnic_dev_hang_notify(enic->vdev); - spin_unlock(&enic->devcmd_lock); - - return err; -} - -static int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic) -{ - int err; - - spin_lock(&enic->devcmd_lock); - err = vnic_dev_set_ig_vlan_rewrite_mode(enic->vdev, - IG_VLAN_REWRITE_MODE_PRIORITY_TAG_DEFAULT_VLAN); - spin_unlock(&enic->devcmd_lock); - - return err; -} - static void enic_reset(struct work_struct *work) { struct enic *enic = container_of(work, struct enic, reset); @@ -2320,7 +2068,7 @@ static void enic_reset(struct work_struct *work) enic_dev_hang_notify(enic); enic_stop(enic->netdev); enic_dev_hang_reset(enic); - enic_reset_multicast_list(enic); + enic_reset_addr_lists(enic); enic_init_vnic_resources(enic); enic_set_rss_nic_cfg(enic); enic_dev_set_ig_vlan_rewrite_mode(enic); @@ -2332,7 +2080,7 @@ static void enic_reset(struct work_struct *work) static int enic_set_intr_mode(struct enic *enic) { unsigned int n = min_t(unsigned int, enic->rq_count, ENIC_RQ_MAX); - unsigned int m = 1; + unsigned int m = min_t(unsigned int, enic->wq_count, ENIC_WQ_MAX); unsigned int i; /* Set interrupt mode (INTx, MSI, MSI-X) depending @@ -2475,9 +2223,7 @@ static const struct net_device_ops enic_netdev_dynamic_ops = { .ndo_tx_timeout = enic_tx_timeout, .ndo_set_vf_port = enic_set_vf_port, .ndo_get_vf_port = enic_get_vf_port, -#ifdef IFLA_VF_MAX .ndo_set_vf_mac = enic_set_vf_mac, -#endif #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = enic_poll_controller, #endif @@ -2556,25 +2302,12 @@ static int enic_dev_init(struct enic *enic) enic_init_vnic_resources(enic); - err = enic_set_rq_alloc_buf(enic); - if (err) { - dev_err(dev, "Failed to set RQ buffer allocator, aborting\n"); - goto err_out_free_vnic_resources; - } - err = enic_set_rss_nic_cfg(enic); if (err) { dev_err(dev, "Failed to config nic, aborting\n"); goto err_out_free_vnic_resources; } - err = enic_dev_set_ig_vlan_rewrite_mode(enic); - if (err) { - dev_err(dev, - "Failed to set ingress vlan rewrite mode, aborting.\n"); - goto err_out_free_vnic_resources; - } - switch (vnic_dev_get_intr_mode(enic->vdev)) { default: netif_napi_add(netdev, &enic->napi[0], enic_poll, 64); @@ -2713,6 +2446,22 @@ static int __devinit enic_probe(struct pci_dev *pdev, goto err_out_vnic_unregister; } + /* Setup devcmd lock + */ + + spin_lock_init(&enic->devcmd_lock); + + /* + * Set ingress vlan rewrite mode before vnic initialization + */ + + err = enic_dev_set_ig_vlan_rewrite_mode(enic); + if (err) { + dev_err(dev, + "Failed to set ingress vlan rewrite mode, aborting.\n"); + goto err_out_dev_close; + } + /* Issue device init to initialize the vnic-to-switch link. * We'll start with carrier off and wait for link UP * notification later to turn on carrier. We don't need @@ -2736,11 +2485,6 @@ static int __devinit enic_probe(struct pci_dev *pdev, } } - /* Setup devcmd lock - */ - - spin_lock_init(&enic->devcmd_lock); - err = enic_dev_init(enic); if (err) { dev_err(dev, "Device initialization failed, aborting\n"); diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c index fb35d8b17668..c489e72107de 100644 --- a/drivers/net/enic/vnic_dev.c +++ b/drivers/net/enic/vnic_dev.c @@ -419,25 +419,6 @@ int vnic_dev_fw_info(struct vnic_dev *vdev, return err; } -int vnic_dev_hw_version(struct vnic_dev *vdev, enum vnic_dev_hw_version *hw_ver) -{ - struct vnic_devcmd_fw_info *fw_info; - int err; - - err = vnic_dev_fw_info(vdev, &fw_info); - if (err) - return err; - - if (strncmp(fw_info->hw_version, "A1", sizeof("A1")) == 0) - *hw_ver = VNIC_DEV_HW_VER_A1; - else if (strncmp(fw_info->hw_version, "A2", sizeof("A2")) == 0) - *hw_ver = VNIC_DEV_HW_VER_A2; - else - *hw_ver = VNIC_DEV_HW_VER_UNKNOWN; - - return 0; -} - int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size, void *value) { diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h index 05f9a24cd459..e837546213a8 100644 --- a/drivers/net/enic/vnic_dev.h +++ b/drivers/net/enic/vnic_dev.h @@ -44,12 +44,6 @@ static inline void writeq(u64 val, void __iomem *reg) #undef pr_fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -enum vnic_dev_hw_version { - VNIC_DEV_HW_VER_UNKNOWN, - VNIC_DEV_HW_VER_A1, - VNIC_DEV_HW_VER_A2, -}; - enum vnic_dev_intr_mode { VNIC_DEV_INTR_MODE_UNKNOWN, VNIC_DEV_INTR_MODE_INTX, @@ -93,8 +87,6 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, u64 *a0, u64 *a1, int wait); int vnic_dev_fw_info(struct vnic_dev *vdev, struct vnic_devcmd_fw_info **fw_info); -int vnic_dev_hw_version(struct vnic_dev *vdev, - enum vnic_dev_hw_version *hw_ver); int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size, void *value); int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats); diff --git a/drivers/net/enic/vnic_rq.h b/drivers/net/enic/vnic_rq.h index 37f08de2454a..2056586f4d4b 100644 --- a/drivers/net/enic/vnic_rq.h +++ b/drivers/net/enic/vnic_rq.h @@ -141,11 +141,6 @@ static inline void vnic_rq_post(struct vnic_rq *rq, } } -static inline int vnic_rq_posting_soon(struct vnic_rq *rq) -{ - return (rq->to_use->index & VNIC_RQ_RETURN_RATE) == 0; -} - static inline void vnic_rq_return_descs(struct vnic_rq *rq, unsigned int count) { rq->ring.desc_avail += count; diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index af09296ef0dd..9c0b1bac6af6 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -5645,6 +5645,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i goto out_error; } + netif_carrier_off(dev); + dev_info(&pci_dev->dev, "ifname %s, PHY OUI 0x%x @ %d, addr %pM\n", dev->name, np->phy_oui, np->phyaddr, dev->dev_addr); diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index ac1d323c5eb5..8931168d3e74 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -400,13 +400,14 @@ static void *bpq_seq_start(struct seq_file *seq, loff_t *pos) static void *bpq_seq_next(struct seq_file *seq, void *v, loff_t *pos) { struct list_head *p; + struct bpqdev *bpqdev = v; ++*pos; if (v == SEQ_START_TOKEN) - p = rcu_dereference(bpq_devices.next); + p = rcu_dereference(list_next_rcu(&bpq_devices)); else - p = rcu_dereference(((struct bpqdev *)v)->bpq_list.next); + p = rcu_dereference(list_next_rcu(&bpqdev->bpq_list)); return (p == &bpq_devices) ? NULL : list_entry(p, struct bpqdev, bpq_list); diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index 0a2368fa6bc6..65c1833244f7 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -129,6 +129,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) break; case E1000_DEV_ID_82580_COPPER: case E1000_DEV_ID_82580_FIBER: + case E1000_DEV_ID_82580_QUAD_FIBER: case E1000_DEV_ID_82580_SERDES: case E1000_DEV_ID_82580_SGMII: case E1000_DEV_ID_82580_COPPER_DUAL: @@ -237,9 +238,15 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) size = 14; nvm->word_size = 1 << size; - /* if 82576 then initialize mailbox parameters */ - if (mac->type == e1000_82576) + /* if part supports SR-IOV then initialize mailbox parameters */ + switch (mac->type) { + case e1000_82576: + case e1000_i350: igb_init_mbx_params_pf(hw); + break; + default: + break; + } /* setup PHY parameters */ if (phy->media_type != e1000_media_type_copper) { diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h index e2638afb8cdc..281324e85980 100644 --- a/drivers/net/igb/e1000_hw.h +++ b/drivers/net/igb/e1000_hw.h @@ -54,6 +54,7 @@ struct e1000_hw; #define E1000_DEV_ID_82580_SERDES 0x1510 #define E1000_DEV_ID_82580_SGMII 0x1511 #define E1000_DEV_ID_82580_COPPER_DUAL 0x1516 +#define E1000_DEV_ID_82580_QUAD_FIBER 0x1527 #define E1000_DEV_ID_DH89XXCC_SGMII 0x0438 #define E1000_DEV_ID_DH89XXCC_SERDES 0x043A #define E1000_DEV_ID_DH89XXCC_BACKPLANE 0x043C diff --git a/drivers/net/igb/e1000_mbx.c b/drivers/net/igb/e1000_mbx.c index c474cdb70047..78d48c7fa859 100644 --- a/drivers/net/igb/e1000_mbx.c +++ b/drivers/net/igb/e1000_mbx.c @@ -422,26 +422,24 @@ s32 igb_init_mbx_params_pf(struct e1000_hw *hw) { struct e1000_mbx_info *mbx = &hw->mbx; - if (hw->mac.type == e1000_82576) { - mbx->timeout = 0; - mbx->usec_delay = 0; - - mbx->size = E1000_VFMAILBOX_SIZE; - - mbx->ops.read = igb_read_mbx_pf; - mbx->ops.write = igb_write_mbx_pf; - mbx->ops.read_posted = igb_read_posted_mbx; - mbx->ops.write_posted = igb_write_posted_mbx; - mbx->ops.check_for_msg = igb_check_for_msg_pf; - mbx->ops.check_for_ack = igb_check_for_ack_pf; - mbx->ops.check_for_rst = igb_check_for_rst_pf; - - mbx->stats.msgs_tx = 0; - mbx->stats.msgs_rx = 0; - mbx->stats.reqs = 0; - mbx->stats.acks = 0; - mbx->stats.rsts = 0; - } + mbx->timeout = 0; + mbx->usec_delay = 0; + + mbx->size = E1000_VFMAILBOX_SIZE; + + mbx->ops.read = igb_read_mbx_pf; + mbx->ops.write = igb_write_mbx_pf; + mbx->ops.read_posted = igb_read_posted_mbx; + mbx->ops.write_posted = igb_write_posted_mbx; + mbx->ops.check_for_msg = igb_check_for_msg_pf; + mbx->ops.check_for_ack = igb_check_for_ack_pf; + mbx->ops.check_for_rst = igb_check_for_rst_pf; + + mbx->stats.msgs_tx = 0; + mbx->stats.msgs_rx = 0; + mbx->stats.reqs = 0; + mbx->stats.acks = 0; + mbx->stats.rsts = 0; return 0; } diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 58c665b7513d..cb6bf7b815ae 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -68,6 +68,7 @@ static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_SGMII), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_FIBER), board_82575 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_QUAD_FIBER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SERDES), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SGMII), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER_DUAL), board_82575 }, @@ -2286,9 +2287,14 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter) spin_lock_init(&adapter->stats64_lock); #ifdef CONFIG_PCI_IOV - if (hw->mac.type == e1000_82576) + switch (hw->mac.type) { + case e1000_82576: + case e1000_i350: adapter->vfs_allocated_count = (max_vfs > 7) ? 7 : max_vfs; - + break; + default: + break; + } #endif /* CONFIG_PCI_IOV */ adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES, num_online_cpus()); diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 3b8c92463617..12769b58c2e7 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -334,6 +334,10 @@ struct ixgbe_adapter { u16 bd_number; struct work_struct reset_task; struct ixgbe_q_vector *q_vector[MAX_MSIX_Q_VECTORS]; + + /* DCB parameters */ + struct ieee_pfc *ixgbe_ieee_pfc; + struct ieee_ets *ixgbe_ieee_ets; struct ixgbe_dcb_config dcb_cfg; struct ixgbe_dcb_config temp_dcb_cfg; u8 dcb_set_bitmap; @@ -521,7 +525,6 @@ extern void ixgbe_unmap_and_free_tx_resource(struct ixgbe_ring *, extern void ixgbe_alloc_rx_buffers(struct ixgbe_ring *, u16); extern void ixgbe_write_eitr(struct ixgbe_q_vector *); extern int ethtool_ioctl(struct ifreq *ifr); -extern u8 ixgbe_dcb_txq_to_tc(struct ixgbe_adapter *adapter, u8 index); extern s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw); extern s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc); extern s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc); diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h index 66ed045a8cf0..90cceb4a6317 100644 --- a/drivers/net/ixgbe/ixgbe_common.h +++ b/drivers/net/ixgbe/ixgbe_common.h @@ -29,6 +29,7 @@ #define _IXGBE_COMMON_H_ #include "ixgbe_type.h" +#include "ixgbe.h" u32 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw); s32 ixgbe_init_ops_generic(struct ixgbe_hw *hw); @@ -110,9 +111,8 @@ void ixgbe_set_vlan_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf); #define IXGBE_WRITE_FLUSH(a) IXGBE_READ_REG(a, IXGBE_STATUS) -extern struct net_device *ixgbe_get_hw_dev(struct ixgbe_hw *hw); #define hw_dbg(hw, format, arg...) \ - netdev_dbg(ixgbe_get_hw_dev(hw), format, ##arg) + netdev_dbg(((struct ixgbe_adapter *)(hw->back))->netdev, format, ##arg) #define e_dev_info(format, arg...) \ dev_info(&adapter->pdev->dev, format, ## arg) #define e_dev_warn(format, arg...) \ diff --git a/drivers/net/ixgbe/ixgbe_dcb.c b/drivers/net/ixgbe/ixgbe_dcb.c index d16c260c1f50..13c962efbfc9 100644 --- a/drivers/net/ixgbe/ixgbe_dcb.c +++ b/drivers/net/ixgbe/ixgbe_dcb.c @@ -34,6 +34,42 @@ #include "ixgbe_dcb_82599.h" /** + * ixgbe_ieee_credits - This calculates the ieee traffic class + * credits from the configured bandwidth percentages. Credits + * are the smallest unit programable into the underlying + * hardware. The IEEE 802.1Qaz specification do not use bandwidth + * groups so this is much simplified from the CEE case. + */ +s32 ixgbe_ieee_credits(__u8 *bw, __u16 *refill, __u16 *max, int max_frame) +{ + int min_percent = 100; + int min_credit, multiplier; + int i; + + min_credit = ((max_frame / 2) + DCB_CREDIT_QUANTUM - 1) / + DCB_CREDIT_QUANTUM; + + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + if (bw[i] < min_percent && bw[i]) + min_percent = bw[i]; + } + + multiplier = (min_credit / min_percent) + 1; + + /* Find out the hw credits for each TC */ + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + int val = min(bw[i] * multiplier, MAX_CREDIT_REFILL); + + if (val < min_credit) + val = min_credit; + refill[i] = val; + + max[i] = (bw[i] * MAX_CREDIT)/100; + } + return 0; +} + +/** * ixgbe_dcb_calculate_tc_credits - Calculates traffic class credits * @ixgbe_dcb_config: Struct containing DCB settings. * @direction: Configuring either Tx or Rx. @@ -141,6 +177,59 @@ out: return ret_val; } +void ixgbe_dcb_unpack_pfc(struct ixgbe_dcb_config *cfg, u8 *pfc_en) +{ + int i; + + *pfc_en = 0; + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) + *pfc_en |= (cfg->tc_config[i].dcb_pfc & 0xF) << i; +} + +void ixgbe_dcb_unpack_refill(struct ixgbe_dcb_config *cfg, int direction, + u16 *refill) +{ + struct tc_bw_alloc *p; + int i; + + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + p = &cfg->tc_config[i].path[direction]; + refill[i] = p->data_credits_refill; + } +} + +void ixgbe_dcb_unpack_max(struct ixgbe_dcb_config *cfg, u16 *max) +{ + int i; + + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) + max[i] = cfg->tc_config[i].desc_credits_max; +} + +void ixgbe_dcb_unpack_bwgid(struct ixgbe_dcb_config *cfg, int direction, + u8 *bwgid) +{ + struct tc_bw_alloc *p; + int i; + + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + p = &cfg->tc_config[i].path[direction]; + bwgid[i] = p->bwg_id; + } +} + +void ixgbe_dcb_unpack_prio(struct ixgbe_dcb_config *cfg, int direction, + u8 *ptype) +{ + struct tc_bw_alloc *p; + int i; + + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + p = &cfg->tc_config[i].path[direction]; + ptype[i] = p->prio_type; + } +} + /** * ixgbe_dcb_hw_config - Config and enable DCB * @hw: pointer to hardware structure @@ -152,13 +241,30 @@ s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw, struct ixgbe_dcb_config *dcb_config) { s32 ret = 0; + u8 pfc_en; + u8 ptype[MAX_TRAFFIC_CLASS]; + u8 bwgid[MAX_TRAFFIC_CLASS]; + u16 refill[MAX_TRAFFIC_CLASS]; + u16 max[MAX_TRAFFIC_CLASS]; + + /* Unpack CEE standard containers */ + ixgbe_dcb_unpack_pfc(dcb_config, &pfc_en); + ixgbe_dcb_unpack_refill(dcb_config, DCB_TX_CONFIG, refill); + ixgbe_dcb_unpack_max(dcb_config, max); + ixgbe_dcb_unpack_bwgid(dcb_config, DCB_TX_CONFIG, bwgid); + ixgbe_dcb_unpack_prio(dcb_config, DCB_TX_CONFIG, ptype); + switch (hw->mac.type) { case ixgbe_mac_82598EB: - ret = ixgbe_dcb_hw_config_82598(hw, dcb_config); + ret = ixgbe_dcb_hw_config_82598(hw, dcb_config->rx_pba_cfg, + pfc_en, refill, max, bwgid, + ptype); break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: - ret = ixgbe_dcb_hw_config_82599(hw, dcb_config); + ret = ixgbe_dcb_hw_config_82599(hw, dcb_config->rx_pba_cfg, + pfc_en, refill, max, bwgid, + ptype); break; default: break; @@ -166,3 +272,70 @@ s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw, return ret; } +/* Helper routines to abstract HW specifics from DCB netlink ops */ +s32 ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en) +{ + int ret = -EINVAL; + + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + ret = ixgbe_dcb_config_pfc_82598(hw, pfc_en); + break; + case ixgbe_mac_82599EB: + case ixgbe_mac_X540: + ret = ixgbe_dcb_config_pfc_82599(hw, pfc_en); + break; + default: + break; + } + return ret; +} + +s32 ixgbe_dcb_hw_ets_config(struct ixgbe_hw *hw, + u16 *refill, u16 *max, u8 *bwg_id, u8 *tsa) +{ + int i; + u8 prio_type[IEEE_8021QAZ_MAX_TCS]; + + /* Map TSA onto CEE prio type */ + for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { + switch (tsa[i]) { + case IEEE_8021QAZ_TSA_STRICT: + prio_type[i] = 2; + break; + case IEEE_8021QAZ_TSA_ETS: + prio_type[i] = 0; + break; + default: + /* Hardware only supports priority strict or + * ETS transmission selection algorithms if + * we receive some other value from dcbnl + * throw an error + */ + return -EINVAL; + } + } + + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + ixgbe_dcb_config_rx_arbiter_82598(hw, refill, max, + prio_type); + ixgbe_dcb_config_tx_desc_arbiter_82598(hw, refill, max, + bwg_id, prio_type); + ixgbe_dcb_config_tx_data_arbiter_82598(hw, refill, max, + bwg_id, prio_type); + break; + case ixgbe_mac_82599EB: + case ixgbe_mac_X540: + ixgbe_dcb_config_rx_arbiter_82599(hw, refill, max, + bwg_id, prio_type); + ixgbe_dcb_config_tx_desc_arbiter_82599(hw, refill, max, + bwg_id, prio_type); + ixgbe_dcb_config_tx_data_arbiter_82599(hw, refill, max, + bwg_id, prio_type); + break; + default: + break; + } + return 0; +} diff --git a/drivers/net/ixgbe/ixgbe_dcb.h b/drivers/net/ixgbe/ixgbe_dcb.h index 1cfe38ee1644..e5935114815e 100644 --- a/drivers/net/ixgbe/ixgbe_dcb.h +++ b/drivers/net/ixgbe/ixgbe_dcb.h @@ -139,7 +139,6 @@ struct ixgbe_dcb_config { struct tc_configuration tc_config[MAX_TRAFFIC_CLASS]; u8 bw_percentage[2][MAX_BW_GROUP]; /* One each for Tx/Rx */ bool pfc_mode_enable; - bool round_robin_enable; enum dcb_rx_pba_cfg rx_pba_cfg; @@ -148,12 +147,21 @@ struct ixgbe_dcb_config { }; /* DCB driver APIs */ +void ixgbe_dcb_unpack_pfc(struct ixgbe_dcb_config *cfg, u8 *pfc_en); +void ixgbe_dcb_unpack_refill(struct ixgbe_dcb_config *, int, u16 *); +void ixgbe_dcb_unpack_max(struct ixgbe_dcb_config *, u16 *); +void ixgbe_dcb_unpack_bwgid(struct ixgbe_dcb_config *, int, u8 *); +void ixgbe_dcb_unpack_prio(struct ixgbe_dcb_config *, int, u8 *); /* DCB credits calculation */ +s32 ixgbe_ieee_credits(__u8 *bw, __u16 *refill, __u16 *max, int max_frame); s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_hw *, struct ixgbe_dcb_config *, int, u8); /* DCB hw initialization */ +s32 ixgbe_dcb_hw_ets_config(struct ixgbe_hw *hw, + u16 *refill, u16 *max, u8 *bwg_id, u8 *prio_type); +s32 ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en); s32 ixgbe_dcb_hw_config(struct ixgbe_hw *, struct ixgbe_dcb_config *); /* DCB definitions for credit calculation */ diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ixgbe/ixgbe_dcb_82598.c index 9a5e89c12e05..2965edcdac7b 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82598.c +++ b/drivers/net/ixgbe/ixgbe_dcb_82598.c @@ -38,15 +38,14 @@ * * Configure packet buffers for DCB mode. */ -static s32 ixgbe_dcb_config_packet_buffers_82598(struct ixgbe_hw *hw, - struct ixgbe_dcb_config *dcb_config) +static s32 ixgbe_dcb_config_packet_buffers_82598(struct ixgbe_hw *hw, u8 rx_pba) { s32 ret_val = 0; u32 value = IXGBE_RXPBSIZE_64KB; u8 i = 0; /* Setup Rx packet buffer sizes */ - switch (dcb_config->rx_pba_cfg) { + switch (rx_pba) { case pba_80_48: /* Setup the first four at 80KB */ value = IXGBE_RXPBSIZE_80KB; @@ -78,10 +77,11 @@ static s32 ixgbe_dcb_config_packet_buffers_82598(struct ixgbe_hw *hw, * * Configure Rx Data Arbiter and credits for each traffic class. */ -static s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw, - struct ixgbe_dcb_config *dcb_config) +s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw, + u16 *refill, + u16 *max, + u8 *prio_type) { - struct tc_bw_alloc *p; u32 reg = 0; u32 credit_refill = 0; u32 credit_max = 0; @@ -102,13 +102,12 @@ static s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw, /* Configure traffic class credits and priority */ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { - p = &dcb_config->tc_config[i].path[DCB_RX_CONFIG]; - credit_refill = p->data_credits_refill; - credit_max = p->data_credits_max; + credit_refill = refill[i]; + credit_max = max[i]; reg = credit_refill | (credit_max << IXGBE_RT2CR_MCL_SHIFT); - if (p->prio_type == prio_link) + if (prio_type[i] == prio_link) reg |= IXGBE_RT2CR_LSP; IXGBE_WRITE_REG(hw, IXGBE_RT2CR(i), reg); @@ -135,10 +134,12 @@ static s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw, * * Configure Tx Descriptor Arbiter and credits for each traffic class. */ -static s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw, - struct ixgbe_dcb_config *dcb_config) +s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw, + u16 *refill, + u16 *max, + u8 *bwg_id, + u8 *prio_type) { - struct tc_bw_alloc *p; u32 reg, max_credits; u8 i; @@ -146,10 +147,8 @@ static s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw, /* Enable arbiter */ reg &= ~IXGBE_DPMCS_ARBDIS; - if (!(dcb_config->round_robin_enable)) { - /* Enable DFP and Recycle mode */ - reg |= (IXGBE_DPMCS_TDPAC | IXGBE_DPMCS_TRM); - } + /* Enable DFP and Recycle mode */ + reg |= (IXGBE_DPMCS_TDPAC | IXGBE_DPMCS_TRM); reg |= IXGBE_DPMCS_TSOEF; /* Configure Max TSO packet size 34KB including payload and headers */ reg |= (0x4 << IXGBE_DPMCS_MTSOS_SHIFT); @@ -158,16 +157,15 @@ static s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw, /* Configure traffic class credits and priority */ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { - p = &dcb_config->tc_config[i].path[DCB_TX_CONFIG]; - max_credits = dcb_config->tc_config[i].desc_credits_max; + max_credits = max[i]; reg = max_credits << IXGBE_TDTQ2TCCR_MCL_SHIFT; - reg |= p->data_credits_refill; - reg |= (u32)(p->bwg_id) << IXGBE_TDTQ2TCCR_BWG_SHIFT; + reg |= refill[i]; + reg |= (u32)(bwg_id[i]) << IXGBE_TDTQ2TCCR_BWG_SHIFT; - if (p->prio_type == prio_group) + if (prio_type[i] == prio_group) reg |= IXGBE_TDTQ2TCCR_GSP; - if (p->prio_type == prio_link) + if (prio_type[i] == prio_link) reg |= IXGBE_TDTQ2TCCR_LSP; IXGBE_WRITE_REG(hw, IXGBE_TDTQ2TCCR(i), reg); @@ -183,10 +181,12 @@ static s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw, * * Configure Tx Data Arbiter and credits for each traffic class. */ -static s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw, - struct ixgbe_dcb_config *dcb_config) +s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw, + u16 *refill, + u16 *max, + u8 *bwg_id, + u8 *prio_type) { - struct tc_bw_alloc *p; u32 reg; u8 i; @@ -200,15 +200,14 @@ static s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw, /* Configure traffic class credits and priority */ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { - p = &dcb_config->tc_config[i].path[DCB_TX_CONFIG]; - reg = p->data_credits_refill; - reg |= (u32)(p->data_credits_max) << IXGBE_TDPT2TCCR_MCL_SHIFT; - reg |= (u32)(p->bwg_id) << IXGBE_TDPT2TCCR_BWG_SHIFT; + reg = refill[i]; + reg |= (u32)(max[i]) << IXGBE_TDPT2TCCR_MCL_SHIFT; + reg |= (u32)(bwg_id[i]) << IXGBE_TDPT2TCCR_BWG_SHIFT; - if (p->prio_type == prio_group) + if (prio_type[i] == prio_group) reg |= IXGBE_TDPT2TCCR_GSP; - if (p->prio_type == prio_link) + if (prio_type[i] == prio_link) reg |= IXGBE_TDPT2TCCR_LSP; IXGBE_WRITE_REG(hw, IXGBE_TDPT2TCCR(i), reg); @@ -229,13 +228,12 @@ static s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw, * * Configure Priority Flow Control for each traffic class. */ -s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, - struct ixgbe_dcb_config *dcb_config) +s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u8 pfc_en) { u32 reg, rx_pba_size; u8 i; - if (!dcb_config->pfc_mode_enable) + if (!pfc_en) goto out; /* Enable Transmit Priority Flow Control */ @@ -256,19 +254,20 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, * for each traffic class. */ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + int enabled = pfc_en & (1 << i); rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i)); rx_pba_size >>= IXGBE_RXPBSIZE_SHIFT; reg = (rx_pba_size - hw->fc.low_water) << 10; - if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx || - dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full) + if (enabled == pfc_enabled_tx || + enabled == pfc_enabled_full) reg |= IXGBE_FCRTL_XONE; IXGBE_WRITE_REG(hw, IXGBE_FCRTL(i), reg); reg = (rx_pba_size - hw->fc.high_water) << 10; - if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx || - dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full) + if (enabled == pfc_enabled_tx || + enabled == pfc_enabled_full) reg |= IXGBE_FCRTH_FCEN; IXGBE_WRITE_REG(hw, IXGBE_FCRTH(i), reg); @@ -292,7 +291,7 @@ out: * Configure queue statistics registers, all queues belonging to same traffic * class uses a single set of queue statistics counters. */ -static s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw) +s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw) { u32 reg = 0; u8 i = 0; @@ -325,13 +324,16 @@ static s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw) * Configure dcb settings and enable dcb mode. */ s32 ixgbe_dcb_hw_config_82598(struct ixgbe_hw *hw, - struct ixgbe_dcb_config *dcb_config) + u8 rx_pba, u8 pfc_en, u16 *refill, + u16 *max, u8 *bwg_id, u8 *prio_type) { - ixgbe_dcb_config_packet_buffers_82598(hw, dcb_config); - ixgbe_dcb_config_rx_arbiter_82598(hw, dcb_config); - ixgbe_dcb_config_tx_desc_arbiter_82598(hw, dcb_config); - ixgbe_dcb_config_tx_data_arbiter_82598(hw, dcb_config); - ixgbe_dcb_config_pfc_82598(hw, dcb_config); + ixgbe_dcb_config_packet_buffers_82598(hw, rx_pba); + ixgbe_dcb_config_rx_arbiter_82598(hw, refill, max, prio_type); + ixgbe_dcb_config_tx_desc_arbiter_82598(hw, refill, max, + bwg_id, prio_type); + ixgbe_dcb_config_tx_data_arbiter_82598(hw, refill, max, + bwg_id, prio_type); + ixgbe_dcb_config_pfc_82598(hw, pfc_en); ixgbe_dcb_config_tc_stats_82598(hw); return 0; diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.h b/drivers/net/ixgbe/ixgbe_dcb_82598.h index abc03ccfa088..0d2a758effce 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82598.h +++ b/drivers/net/ixgbe/ixgbe_dcb_82598.h @@ -71,9 +71,28 @@ /* DCB hardware-specific driver APIs */ /* DCB PFC functions */ -s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *, struct ixgbe_dcb_config *); +s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *, u8 pfc_en); /* DCB hw initialization */ -s32 ixgbe_dcb_hw_config_82598(struct ixgbe_hw *, struct ixgbe_dcb_config *); +s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw, + u16 *refill, + u16 *max, + u8 *prio_type); + +s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw, + u16 *refill, + u16 *max, + u8 *bwg_id, + u8 *prio_type); + +s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw, + u16 *refill, + u16 *max, + u8 *bwg_id, + u8 *prio_type); + +s32 ixgbe_dcb_hw_config_82598(struct ixgbe_hw *hw, + u8 rx_pba, u8 pfc_en, u16 *refill, + u16 *max, u8 *bwg_id, u8 *prio_type); #endif /* _DCB_82598_CONFIG_H */ diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ixgbe/ixgbe_dcb_82599.c index 374e1f74d0f5..b0d97a98c84d 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82599.c +++ b/drivers/net/ixgbe/ixgbe_dcb_82599.c @@ -33,19 +33,18 @@ /** * ixgbe_dcb_config_packet_buffers_82599 - Configure DCB packet buffers * @hw: pointer to hardware structure - * @dcb_config: pointer to ixgbe_dcb_config structure + * @rx_pba: method to distribute packet buffer * * Configure packet buffers for DCB mode. */ -static s32 ixgbe_dcb_config_packet_buffers_82599(struct ixgbe_hw *hw, - struct ixgbe_dcb_config *dcb_config) +static s32 ixgbe_dcb_config_packet_buffers_82599(struct ixgbe_hw *hw, u8 rx_pba) { s32 ret_val = 0; u32 value = IXGBE_RXPBSIZE_64KB; u8 i = 0; /* Setup Rx packet buffer sizes */ - switch (dcb_config->rx_pba_cfg) { + switch (rx_pba) { case pba_80_48: /* Setup the first four at 80KB */ value = IXGBE_RXPBSIZE_80KB; @@ -75,14 +74,19 @@ static s32 ixgbe_dcb_config_packet_buffers_82599(struct ixgbe_hw *hw, /** * ixgbe_dcb_config_rx_arbiter_82599 - Config Rx Data arbiter * @hw: pointer to hardware structure - * @dcb_config: pointer to ixgbe_dcb_config structure + * @refill: refill credits index by traffic class + * @max: max credits index by traffic class + * @bwg_id: bandwidth grouping indexed by traffic class + * @prio_type: priority type indexed by traffic class * * Configure Rx Packet Arbiter and credits for each traffic class. */ -static s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw, - struct ixgbe_dcb_config *dcb_config) +s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw, + u16 *refill, + u16 *max, + u8 *bwg_id, + u8 *prio_type) { - struct tc_bw_alloc *p; u32 reg = 0; u32 credit_refill = 0; u32 credit_max = 0; @@ -103,15 +107,13 @@ static s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw, /* Configure traffic class credits and priority */ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { - p = &dcb_config->tc_config[i].path[DCB_RX_CONFIG]; - - credit_refill = p->data_credits_refill; - credit_max = p->data_credits_max; + credit_refill = refill[i]; + credit_max = max[i]; reg = credit_refill | (credit_max << IXGBE_RTRPT4C_MCL_SHIFT); - reg |= (u32)(p->bwg_id) << IXGBE_RTRPT4C_BWG_SHIFT; + reg |= (u32)(bwg_id[i]) << IXGBE_RTRPT4C_BWG_SHIFT; - if (p->prio_type == prio_link) + if (prio_type[i] == prio_link) reg |= IXGBE_RTRPT4C_LSP; IXGBE_WRITE_REG(hw, IXGBE_RTRPT4C(i), reg); @@ -130,14 +132,19 @@ static s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw, /** * ixgbe_dcb_config_tx_desc_arbiter_82599 - Config Tx Desc. arbiter * @hw: pointer to hardware structure - * @dcb_config: pointer to ixgbe_dcb_config structure + * @refill: refill credits index by traffic class + * @max: max credits index by traffic class + * @bwg_id: bandwidth grouping indexed by traffic class + * @prio_type: priority type indexed by traffic class * * Configure Tx Descriptor Arbiter and credits for each traffic class. */ -static s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw, - struct ixgbe_dcb_config *dcb_config) +s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw, + u16 *refill, + u16 *max, + u8 *bwg_id, + u8 *prio_type) { - struct tc_bw_alloc *p; u32 reg, max_credits; u8 i; @@ -149,16 +156,15 @@ static s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw, /* Configure traffic class credits and priority */ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { - p = &dcb_config->tc_config[i].path[DCB_TX_CONFIG]; - max_credits = dcb_config->tc_config[i].desc_credits_max; + max_credits = max[i]; reg = max_credits << IXGBE_RTTDT2C_MCL_SHIFT; - reg |= p->data_credits_refill; - reg |= (u32)(p->bwg_id) << IXGBE_RTTDT2C_BWG_SHIFT; + reg |= refill[i]; + reg |= (u32)(bwg_id[i]) << IXGBE_RTTDT2C_BWG_SHIFT; - if (p->prio_type == prio_group) + if (prio_type[i] == prio_group) reg |= IXGBE_RTTDT2C_GSP; - if (p->prio_type == prio_link) + if (prio_type[i] == prio_link) reg |= IXGBE_RTTDT2C_LSP; IXGBE_WRITE_REG(hw, IXGBE_RTTDT2C(i), reg); @@ -177,14 +183,19 @@ static s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw, /** * ixgbe_dcb_config_tx_data_arbiter_82599 - Config Tx Data arbiter * @hw: pointer to hardware structure - * @dcb_config: pointer to ixgbe_dcb_config structure + * @refill: refill credits index by traffic class + * @max: max credits index by traffic class + * @bwg_id: bandwidth grouping indexed by traffic class + * @prio_type: priority type indexed by traffic class * * Configure Tx Packet Arbiter and credits for each traffic class. */ -static s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw, - struct ixgbe_dcb_config *dcb_config) +s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw, + u16 *refill, + u16 *max, + u8 *bwg_id, + u8 *prio_type) { - struct tc_bw_alloc *p; u32 reg; u8 i; @@ -205,15 +216,14 @@ static s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw, /* Configure traffic class credits and priority */ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { - p = &dcb_config->tc_config[i].path[DCB_TX_CONFIG]; - reg = p->data_credits_refill; - reg |= (u32)(p->data_credits_max) << IXGBE_RTTPT2C_MCL_SHIFT; - reg |= (u32)(p->bwg_id) << IXGBE_RTTPT2C_BWG_SHIFT; + reg = refill[i]; + reg |= (u32)(max[i]) << IXGBE_RTTPT2C_MCL_SHIFT; + reg |= (u32)(bwg_id[i]) << IXGBE_RTTPT2C_BWG_SHIFT; - if (p->prio_type == prio_group) + if (prio_type[i] == prio_group) reg |= IXGBE_RTTPT2C_GSP; - if (p->prio_type == prio_link) + if (prio_type[i] == prio_link) reg |= IXGBE_RTTPT2C_LSP; IXGBE_WRITE_REG(hw, IXGBE_RTTPT2C(i), reg); @@ -233,17 +243,16 @@ static s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw, /** * ixgbe_dcb_config_pfc_82599 - Configure priority flow control * @hw: pointer to hardware structure - * @dcb_config: pointer to ixgbe_dcb_config structure + * @pfc_en: enabled pfc bitmask * * Configure Priority Flow Control (PFC) for each traffic class. */ -s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, - struct ixgbe_dcb_config *dcb_config) +s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en) { u32 i, reg, rx_pba_size; /* If PFC is disabled globally then fall back to LFC. */ - if (!dcb_config->pfc_mode_enable) { + if (!pfc_en) { for (i = 0; i < MAX_TRAFFIC_CLASS; i++) hw->mac.ops.fc_enable(hw, i); goto out; @@ -251,19 +260,18 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, /* Configure PFC Tx thresholds per TC */ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + int enabled = pfc_en & (1 << i); rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i)); rx_pba_size >>= IXGBE_RXPBSIZE_SHIFT; reg = (rx_pba_size - hw->fc.low_water) << 10; - if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full || - dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx) + if (enabled) reg |= IXGBE_FCRTL_XONE; IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), reg); reg = (rx_pba_size - hw->fc.high_water) << 10; - if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full || - dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx) + if (enabled) reg |= IXGBE_FCRTH_FCEN; IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(i), reg); } @@ -349,7 +357,6 @@ static s32 ixgbe_dcb_config_tc_stats_82599(struct ixgbe_hw *hw) /** * ixgbe_dcb_config_82599 - Configure general DCB parameters * @hw: pointer to hardware structure - * @dcb_config: pointer to ixgbe_dcb_config structure * * Configure general DCB parameters. */ @@ -406,19 +413,27 @@ static s32 ixgbe_dcb_config_82599(struct ixgbe_hw *hw) /** * ixgbe_dcb_hw_config_82599 - Configure and enable DCB * @hw: pointer to hardware structure - * @dcb_config: pointer to ixgbe_dcb_config structure + * @rx_pba: method to distribute packet buffer + * @refill: refill credits index by traffic class + * @max: max credits index by traffic class + * @bwg_id: bandwidth grouping indexed by traffic class + * @prio_type: priority type indexed by traffic class + * @pfc_en: enabled pfc bitmask * * Configure dcb settings and enable dcb mode. */ s32 ixgbe_dcb_hw_config_82599(struct ixgbe_hw *hw, - struct ixgbe_dcb_config *dcb_config) + u8 rx_pba, u8 pfc_en, u16 *refill, + u16 *max, u8 *bwg_id, u8 *prio_type) { - ixgbe_dcb_config_packet_buffers_82599(hw, dcb_config); + ixgbe_dcb_config_packet_buffers_82599(hw, rx_pba); ixgbe_dcb_config_82599(hw); - ixgbe_dcb_config_rx_arbiter_82599(hw, dcb_config); - ixgbe_dcb_config_tx_desc_arbiter_82599(hw, dcb_config); - ixgbe_dcb_config_tx_data_arbiter_82599(hw, dcb_config); - ixgbe_dcb_config_pfc_82599(hw, dcb_config); + ixgbe_dcb_config_rx_arbiter_82599(hw, refill, max, bwg_id, prio_type); + ixgbe_dcb_config_tx_desc_arbiter_82599(hw, refill, max, + bwg_id, prio_type); + ixgbe_dcb_config_tx_data_arbiter_82599(hw, refill, max, + bwg_id, prio_type); + ixgbe_dcb_config_pfc_82599(hw, pfc_en); ixgbe_dcb_config_tc_stats_82599(hw); return 0; diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.h b/drivers/net/ixgbe/ixgbe_dcb_82599.h index 3841649fb954..5b0ca85614d1 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82599.h +++ b/drivers/net/ixgbe/ixgbe_dcb_82599.h @@ -102,11 +102,29 @@ /* DCB hardware-specific driver APIs */ /* DCB PFC functions */ -s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, - struct ixgbe_dcb_config *dcb_config); +s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en); /* DCB hw initialization */ +s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw, + u16 *refill, + u16 *max, + u8 *bwg_id, + u8 *prio_type); + +s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw, + u16 *refill, + u16 *max, + u8 *bwg_id, + u8 *prio_type); + +s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw, + u16 *refill, + u16 *max, + u8 *bwg_id, + u8 *prio_type); + s32 ixgbe_dcb_hw_config_82599(struct ixgbe_hw *hw, - struct ixgbe_dcb_config *config); + u8 rx_pba, u8 pfc_en, u16 *refill, + u16 *max, u8 *bwg_id, u8 *prio_type); #endif /* _DCB_82599_CONFIG_H */ diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index bf566e8a455e..a977df3fe81b 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -37,7 +37,6 @@ #define BIT_PG_RX 0x04 #define BIT_PG_TX 0x08 #define BIT_APP_UPCHG 0x10 -#define BIT_RESETLINK 0x40 #define BIT_LINKSPEED 0x80 /* Responses for the DCB_C_SET_ALL command */ @@ -225,10 +224,8 @@ static void ixgbe_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc, (adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_percent != adapter->dcb_cfg.tc_config[tc].path[0].bwg_percent) || (adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap != - adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap)) { + adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap)) adapter->dcb_set_bitmap |= BIT_PG_TX; - adapter->dcb_set_bitmap |= BIT_RESETLINK; - } } static void ixgbe_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id, @@ -239,10 +236,8 @@ static void ixgbe_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id, adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] = bw_pct; if (adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] != - adapter->dcb_cfg.bw_percentage[0][bwg_id]) { + adapter->dcb_cfg.bw_percentage[0][bwg_id]) adapter->dcb_set_bitmap |= BIT_PG_TX; - adapter->dcb_set_bitmap |= BIT_RESETLINK; - } } static void ixgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc, @@ -269,10 +264,8 @@ static void ixgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc, (adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_percent != adapter->dcb_cfg.tc_config[tc].path[1].bwg_percent) || (adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap != - adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap)) { + adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap)) adapter->dcb_set_bitmap |= BIT_PG_RX; - adapter->dcb_set_bitmap |= BIT_RESETLINK; - } } static void ixgbe_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id, @@ -283,10 +276,8 @@ static void ixgbe_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id, adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] = bw_pct; if (adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] != - adapter->dcb_cfg.bw_percentage[1][bwg_id]) { + adapter->dcb_cfg.bw_percentage[1][bwg_id]) adapter->dcb_set_bitmap |= BIT_PG_RX; - adapter->dcb_set_bitmap |= BIT_RESETLINK; - } } static void ixgbe_dcbnl_get_pg_tc_cfg_tx(struct net_device *netdev, int tc, @@ -365,21 +356,17 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) return DCB_NO_HW_CHG; /* - * Only take down the adapter if the configuration change - * requires a reset. + * Only take down the adapter if an app change occured. FCoE + * may shuffle tx rings in this case and this can not be done + * without a reset currently. */ - if (adapter->dcb_set_bitmap & BIT_RESETLINK) { + if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) { while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) msleep(1); - if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) { - if (netif_running(netdev)) - netdev->netdev_ops->ndo_stop(netdev); - ixgbe_clear_interrupt_scheme(adapter); - } else { - if (netif_running(netdev)) - ixgbe_down(adapter); - } + if (netif_running(netdev)) + netdev->netdev_ops->ndo_stop(netdev); + ixgbe_clear_interrupt_scheme(adapter); } if (adapter->dcb_cfg.pfc_mode_enable) { @@ -408,29 +395,51 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) } } - if (adapter->dcb_set_bitmap & BIT_RESETLINK) { - if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) { - ixgbe_init_interrupt_scheme(adapter); - if (netif_running(netdev)) - netdev->netdev_ops->ndo_open(netdev); - } else { - if (netif_running(netdev)) - ixgbe_up(adapter); - } + if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) { + ixgbe_init_interrupt_scheme(adapter); + if (netif_running(netdev)) + netdev->netdev_ops->ndo_open(netdev); ret = DCB_HW_CHG_RST; - } else if (adapter->dcb_set_bitmap & BIT_PFC) { - if (adapter->hw.mac.type == ixgbe_mac_82598EB) - ixgbe_dcb_config_pfc_82598(&adapter->hw, - &adapter->dcb_cfg); - else if (adapter->hw.mac.type == ixgbe_mac_82599EB) - ixgbe_dcb_config_pfc_82599(&adapter->hw, - &adapter->dcb_cfg); + } + + if (adapter->dcb_set_bitmap & BIT_PFC) { + u8 pfc_en; + ixgbe_dcb_unpack_pfc(&adapter->dcb_cfg, &pfc_en); + ixgbe_dcb_hw_pfc_config(&adapter->hw, pfc_en); ret = DCB_HW_CHG; } + + if (adapter->dcb_set_bitmap & (BIT_PG_TX|BIT_PG_RX)) { + u16 refill[MAX_TRAFFIC_CLASS], max[MAX_TRAFFIC_CLASS]; + u8 bwg_id[MAX_TRAFFIC_CLASS], prio_type[MAX_TRAFFIC_CLASS]; + int max_frame = adapter->netdev->mtu + ETH_HLEN + ETH_FCS_LEN; + +#ifdef CONFIG_FCOE + if (adapter->netdev->features & NETIF_F_FCOE_MTU) + max_frame = max(max_frame, IXGBE_FCOE_JUMBO_FRAME_SIZE); +#endif + + ixgbe_dcb_calculate_tc_credits(&adapter->hw, &adapter->dcb_cfg, + max_frame, DCB_TX_CONFIG); + ixgbe_dcb_calculate_tc_credits(&adapter->hw, &adapter->dcb_cfg, + max_frame, DCB_RX_CONFIG); + + ixgbe_dcb_unpack_refill(&adapter->dcb_cfg, + DCB_TX_CONFIG, refill); + ixgbe_dcb_unpack_max(&adapter->dcb_cfg, max); + ixgbe_dcb_unpack_bwgid(&adapter->dcb_cfg, + DCB_TX_CONFIG, bwg_id); + ixgbe_dcb_unpack_prio(&adapter->dcb_cfg, + DCB_TX_CONFIG, prio_type); + + ixgbe_dcb_hw_ets_config(&adapter->hw, refill, max, + bwg_id, prio_type); + } + if (adapter->dcb_cfg.pfc_mode_enable) adapter->hw.fc.current_mode = ixgbe_fc_pfc; - if (adapter->dcb_set_bitmap & BIT_RESETLINK) + if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) clear_bit(__IXGBE_RESETTING, &adapter->state); adapter->dcb_set_bitmap = 0x00; return ret; @@ -568,18 +577,29 @@ static u8 ixgbe_dcbnl_setapp(struct net_device *netdev, case DCB_APP_IDTYPE_ETHTYPE: #ifdef IXGBE_FCOE if (id == ETH_P_FCOE) { - u8 tc; - struct ixgbe_adapter *adapter; + u8 old_tc; + struct ixgbe_adapter *adapter = netdev_priv(netdev); - adapter = netdev_priv(netdev); - tc = adapter->fcoe.tc; + /* Get current programmed tc */ + old_tc = adapter->fcoe.tc; rval = ixgbe_fcoe_setapp(adapter, up); - if ((!rval) && (tc != adapter->fcoe.tc) && - (adapter->flags & IXGBE_FLAG_DCB_ENABLED) && - (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) { + + if (rval || + !(adapter->flags & IXGBE_FLAG_DCB_ENABLED) || + !(adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) + break; + + /* The FCoE application priority may be changed multiple + * times in quick sucession with switches that build up + * TLVs. To avoid creating uneeded device resets this + * checks the actual HW configuration and clears + * BIT_APP_UPCHG if a HW configuration change is not + * need + */ + if (old_tc == adapter->fcoe.tc) + adapter->dcb_set_bitmap &= ~BIT_APP_UPCHG; + else adapter->dcb_set_bitmap |= BIT_APP_UPCHG; - adapter->dcb_set_bitmap |= BIT_RESETLINK; - } } #endif break; @@ -591,7 +611,98 @@ static u8 ixgbe_dcbnl_setapp(struct net_device *netdev, return rval; } +static int ixgbe_dcbnl_ieee_getets(struct net_device *dev, + struct ieee_ets *ets) +{ + struct ixgbe_adapter *adapter = netdev_priv(dev); + struct ieee_ets *my_ets = adapter->ixgbe_ieee_ets; + + /* No IEEE PFC settings available */ + if (!my_ets) + return -EINVAL; + + ets->ets_cap = MAX_TRAFFIC_CLASS; + ets->cbs = my_ets->cbs; + memcpy(ets->tc_tx_bw, my_ets->tc_tx_bw, sizeof(ets->tc_tx_bw)); + memcpy(ets->tc_rx_bw, my_ets->tc_rx_bw, sizeof(ets->tc_rx_bw)); + memcpy(ets->tc_tsa, my_ets->tc_tsa, sizeof(ets->tc_tsa)); + memcpy(ets->prio_tc, my_ets->prio_tc, sizeof(ets->prio_tc)); + return 0; +} + +static int ixgbe_dcbnl_ieee_setets(struct net_device *dev, + struct ieee_ets *ets) +{ + struct ixgbe_adapter *adapter = netdev_priv(dev); + __u16 refill[IEEE_8021QAZ_MAX_TCS], max[IEEE_8021QAZ_MAX_TCS]; + int max_frame = dev->mtu + ETH_HLEN + ETH_FCS_LEN; + int err; + /* naively give each TC a bwg to map onto CEE hardware */ + __u8 bwg_id[IEEE_8021QAZ_MAX_TCS] = {0, 1, 2, 3, 4, 5, 6, 7}; + + if (!adapter->ixgbe_ieee_ets) { + adapter->ixgbe_ieee_ets = kmalloc(sizeof(struct ieee_ets), + GFP_KERNEL); + if (!adapter->ixgbe_ieee_ets) + return -ENOMEM; + } + + + memcpy(adapter->ixgbe_ieee_ets, ets, sizeof(*adapter->ixgbe_ieee_ets)); + + ixgbe_ieee_credits(ets->tc_tx_bw, refill, max, max_frame); + err = ixgbe_dcb_hw_ets_config(&adapter->hw, refill, max, + bwg_id, ets->tc_tsa); + return err; +} + +static int ixgbe_dcbnl_ieee_getpfc(struct net_device *dev, + struct ieee_pfc *pfc) +{ + struct ixgbe_adapter *adapter = netdev_priv(dev); + struct ieee_pfc *my_pfc = adapter->ixgbe_ieee_pfc; + int i; + + /* No IEEE PFC settings available */ + if (!my_pfc) + return -EINVAL; + + pfc->pfc_cap = MAX_TRAFFIC_CLASS; + pfc->pfc_en = my_pfc->pfc_en; + pfc->mbc = my_pfc->mbc; + pfc->delay = my_pfc->delay; + + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + pfc->requests[i] = adapter->stats.pxoffrxc[i]; + pfc->indications[i] = adapter->stats.pxofftxc[i]; + } + + return 0; +} + +static int ixgbe_dcbnl_ieee_setpfc(struct net_device *dev, + struct ieee_pfc *pfc) +{ + struct ixgbe_adapter *adapter = netdev_priv(dev); + int err; + + if (!adapter->ixgbe_ieee_pfc) { + adapter->ixgbe_ieee_pfc = kmalloc(sizeof(struct ieee_pfc), + GFP_KERNEL); + if (!adapter->ixgbe_ieee_pfc) + return -ENOMEM; + } + + memcpy(adapter->ixgbe_ieee_pfc, pfc, sizeof(*adapter->ixgbe_ieee_pfc)); + err = ixgbe_dcb_hw_pfc_config(&adapter->hw, pfc->pfc_en); + return err; +} + const struct dcbnl_rtnl_ops dcbnl_ops = { + .ieee_getets = ixgbe_dcbnl_ieee_getets, + .ieee_setets = ixgbe_dcbnl_ieee_setets, + .ieee_getpfc = ixgbe_dcbnl_ieee_getpfc, + .ieee_setpfc = ixgbe_dcbnl_ieee_setpfc, .getstate = ixgbe_dcbnl_get_state, .setstate = ixgbe_dcbnl_set_state, .getpermhwaddr = ixgbe_dcbnl_get_perm_hw_addr, diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 2002ea88ca2a..309272f8f103 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -152,7 +152,17 @@ static int ixgbe_get_settings(struct net_device *netdev, ecmd->supported |= (SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg); + switch (hw->mac.type) { + case ixgbe_mac_X540: + ecmd->supported |= SUPPORTED_100baseT_Full; + break; + default: + break; + } + ecmd->advertising = ADVERTISED_Autoneg; + if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) + ecmd->advertising |= ADVERTISED_100baseT_Full; if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) ecmd->advertising |= ADVERTISED_10000baseT_Full; if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) @@ -167,6 +177,15 @@ static int ixgbe_get_settings(struct net_device *netdev, ecmd->advertising |= (ADVERTISED_10000baseT_Full | ADVERTISED_1000baseT_Full); + switch (hw->mac.type) { + case ixgbe_mac_X540: + if (!(ecmd->advertising & ADVERTISED_100baseT_Full)) + ecmd->advertising |= (ADVERTISED_100baseT_Full); + break; + default: + break; + } + if (hw->phy.media_type == ixgbe_media_type_copper) { ecmd->supported |= SUPPORTED_TP; ecmd->advertising |= ADVERTISED_TP; @@ -271,8 +290,19 @@ static int ixgbe_get_settings(struct net_device *netdev, hw->mac.ops.check_link(hw, &link_speed, &link_up, false); if (link_up) { - ecmd->speed = (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ? - SPEED_10000 : SPEED_1000; + switch (link_speed) { + case IXGBE_LINK_SPEED_10GB_FULL: + ecmd->speed = SPEED_10000; + break; + case IXGBE_LINK_SPEED_1GB_FULL: + ecmd->speed = SPEED_1000; + break; + case IXGBE_LINK_SPEED_100_FULL: + ecmd->speed = SPEED_100; + break; + default: + break; + } ecmd->duplex = DUPLEX_FULL; } else { ecmd->speed = -1; diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index 8753980668c7..c54a88274d51 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -159,7 +159,7 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, struct scatterlist *sg; unsigned int i, j, dmacount; unsigned int len; - static const unsigned int bufflen = 4096; + static const unsigned int bufflen = IXGBE_FCBUFF_MIN; unsigned int firstoff = 0; unsigned int lastsize; unsigned int thisoff = 0; @@ -254,6 +254,24 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, /* only the last buffer may have non-full bufflen */ lastsize = thisoff + thislen; + /* + * lastsize can not be buffer len. + * If it is then adding another buffer with lastsize = 1. + */ + if (lastsize == bufflen) { + if (j >= IXGBE_BUFFCNT_MAX) { + e_err(drv, "xid=%x:%d,%d,%d:addr=%llx " + "not enough user buffers. We need an extra " + "buffer because lastsize is bufflen.\n", + xid, i, j, dmacount, (u64)addr); + goto out_noddp_free; + } + + ddp->udl[j] = (u64)(fcoe->extra_ddp_buffer_dma); + j++; + lastsize = 1; + } + fcbuff = (IXGBE_FCBUFF_4KB << IXGBE_FCBUFF_BUFFSIZE_SHIFT); fcbuff |= ((j & 0xff) << IXGBE_FCBUFF_BUFFCNT_SHIFT); fcbuff |= (firstoff << IXGBE_FCBUFF_OFFSET_SHIFT); @@ -532,6 +550,24 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) e_err(drv, "failed to allocated FCoE DDP pool\n"); spin_lock_init(&fcoe->lock); + + /* Extra buffer to be shared by all DDPs for HW work around */ + fcoe->extra_ddp_buffer = kmalloc(IXGBE_FCBUFF_MIN, GFP_ATOMIC); + if (fcoe->extra_ddp_buffer == NULL) { + e_err(drv, "failed to allocated extra DDP buffer\n"); + goto out_extra_ddp_buffer_alloc; + } + + fcoe->extra_ddp_buffer_dma = + dma_map_single(&adapter->pdev->dev, + fcoe->extra_ddp_buffer, + IXGBE_FCBUFF_MIN, + DMA_FROM_DEVICE); + if (dma_mapping_error(&adapter->pdev->dev, + fcoe->extra_ddp_buffer_dma)) { + e_err(drv, "failed to map extra DDP buffer\n"); + goto out_extra_ddp_buffer_dma; + } } /* Enable L2 eth type filter for FCoE */ @@ -581,6 +617,14 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) } } #endif + + return; + +out_extra_ddp_buffer_dma: + kfree(fcoe->extra_ddp_buffer); +out_extra_ddp_buffer_alloc: + pci_pool_destroy(fcoe->pool); + fcoe->pool = NULL; } /** @@ -600,6 +644,11 @@ void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter) if (fcoe->pool) { for (i = 0; i < IXGBE_FCOE_DDP_MAX; i++) ixgbe_fcoe_ddp_put(adapter->netdev, i); + dma_unmap_single(&adapter->pdev->dev, + fcoe->extra_ddp_buffer_dma, + IXGBE_FCBUFF_MIN, + DMA_FROM_DEVICE); + kfree(fcoe->extra_ddp_buffer); pci_pool_destroy(fcoe->pool); fcoe->pool = NULL; } diff --git a/drivers/net/ixgbe/ixgbe_fcoe.h b/drivers/net/ixgbe/ixgbe_fcoe.h index 4bc2c551c8db..65cc8fb14fe7 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.h +++ b/drivers/net/ixgbe/ixgbe_fcoe.h @@ -70,6 +70,8 @@ struct ixgbe_fcoe { spinlock_t lock; struct pci_pool *pool; struct ixgbe_fcoe_ddp ddp[IXGBE_FCOE_DDP_MAX]; + unsigned char *extra_ddp_buffer; + dma_addr_t extra_ddp_buffer_dma; }; #endif /* _IXGBE_FCOE_H */ diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index fbae703b46d7..eca762d954c6 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -648,7 +648,7 @@ void ixgbe_unmap_and_free_tx_resource(struct ixgbe_ring *tx_ring, * * Returns : a tc index for use in range 0-7, or 0-3 */ -u8 ixgbe_dcb_txq_to_tc(struct ixgbe_adapter *adapter, u8 reg_idx) +static u8 ixgbe_dcb_txq_to_tc(struct ixgbe_adapter *adapter, u8 reg_idx) { int tc = -1; int dcb_i = adapter->ring_feature[RING_F_DCB].indices; @@ -3728,7 +3728,8 @@ static void ixgbe_sfp_link_config(struct ixgbe_adapter *adapter) * We need to try and force an autonegotiation * session, then bring up link. */ - hw->mac.ops.setup_sfp(hw); + if (hw->mac.ops.setup_sfp) + hw->mac.ops.setup_sfp(hw); if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK)) schedule_work(&adapter->multispeed_fiber_task); } else { @@ -5173,7 +5174,6 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) adapter->dcb_cfg.bw_percentage[DCB_RX_CONFIG][0] = 100; adapter->dcb_cfg.rx_pba_cfg = pba_equal; adapter->dcb_cfg.pfc_mode_enable = false; - adapter->dcb_cfg.round_robin_enable = false; adapter->dcb_set_bitmap = 0x00; ixgbe_copy_dcb_cfg(&adapter->dcb_cfg, &adapter->temp_dcb_cfg, adapter->ring_feature[RING_F_DCB].indices); @@ -5610,6 +5610,10 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake) } ixgbe_clear_interrupt_scheme(adapter); +#ifdef CONFIG_DCB + kfree(adapter->ixgbe_ieee_pfc); + kfree(adapter->ixgbe_ieee_ets); +#endif #ifdef CONFIG_PM retval = pci_save_state(pdev); @@ -5968,7 +5972,8 @@ static void ixgbe_sfp_config_module_task(struct work_struct *work) unregister_netdev(adapter->netdev); return; } - hw->mac.ops.setup_sfp(hw); + if (hw->mac.ops.setup_sfp) + hw->mac.ops.setup_sfp(hw); if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK)) /* This will also work for DA Twinax connections */ @@ -6099,7 +6104,10 @@ static void ixgbe_watchdog_task(struct work_struct *work) (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? "10 Gbps" : (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? - "1 Gbps" : "unknown speed")), + "1 Gbps" : + (link_speed == IXGBE_LINK_SPEED_100_FULL ? + "100 Mbps" : + "unknown speed"))), ((flow_rx && flow_tx) ? "RX/TX" : (flow_rx ? "RX" : (flow_tx ? "TX" : "None")))); @@ -7704,16 +7712,6 @@ static int ixgbe_notify_dca(struct notifier_block *nb, unsigned long event, #endif /* CONFIG_IXGBE_DCA */ -/** - * ixgbe_get_hw_dev return device - * used by hardware layer to print debugging information - **/ -struct net_device *ixgbe_get_hw_dev(struct ixgbe_hw *hw) -{ - struct ixgbe_adapter *adapter = hw->back; - return adapter->netdev; -} - module_exit(ixgbe_exit_module); /* ixgbe_main.c */ diff --git a/drivers/net/ixgbe/ixgbe_mbx.c b/drivers/net/ixgbe/ixgbe_mbx.c index ea82c5a1cd3e..f215c4c296c4 100644 --- a/drivers/net/ixgbe/ixgbe_mbx.c +++ b/drivers/net/ixgbe/ixgbe_mbx.c @@ -437,6 +437,7 @@ out_no_read: return ret_val; } +#ifdef CONFIG_PCI_IOV /** * ixgbe_init_mbx_params_pf - set initial values for pf mailbox * @hw: pointer to the HW structure @@ -465,6 +466,7 @@ void ixgbe_init_mbx_params_pf(struct ixgbe_hw *hw) break; } } +#endif /* CONFIG_PCI_IOV */ struct ixgbe_mbx_operations mbx_ops_generic = { .read = ixgbe_read_mbx_pf, diff --git a/drivers/net/ixgbe/ixgbe_mbx.h b/drivers/net/ixgbe/ixgbe_mbx.h index 3df9b1590218..ada0ce32a7a6 100644 --- a/drivers/net/ixgbe/ixgbe_mbx.h +++ b/drivers/net/ixgbe/ixgbe_mbx.h @@ -86,7 +86,9 @@ s32 ixgbe_write_mbx(struct ixgbe_hw *, u32 *, u16, u16); s32 ixgbe_check_for_msg(struct ixgbe_hw *, u16); s32 ixgbe_check_for_ack(struct ixgbe_hw *, u16); s32 ixgbe_check_for_rst(struct ixgbe_hw *, u16); +#ifdef CONFIG_PCI_IOV void ixgbe_init_mbx_params_pf(struct ixgbe_hw *); +#endif /* CONFIG_PCI_IOV */ extern struct ixgbe_mbx_operations mbx_ops_generic; diff --git a/drivers/net/jme.c b/drivers/net/jme.c index e97ebef3cf47..5b441b75e138 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -161,6 +161,67 @@ jme_setup_wakeup_frame(struct jme_adapter *jme, } static inline void +jme_mac_rxclk_off(struct jme_adapter *jme) +{ + jme->reg_gpreg1 |= GPREG1_RXCLKOFF; + jwrite32f(jme, JME_GPREG1, jme->reg_gpreg1); +} + +static inline void +jme_mac_rxclk_on(struct jme_adapter *jme) +{ + jme->reg_gpreg1 &= ~GPREG1_RXCLKOFF; + jwrite32f(jme, JME_GPREG1, jme->reg_gpreg1); +} + +static inline void +jme_mac_txclk_off(struct jme_adapter *jme) +{ + jme->reg_ghc &= ~(GHC_TO_CLK_SRC | GHC_TXMAC_CLK_SRC); + jwrite32f(jme, JME_GHC, jme->reg_ghc); +} + +static inline void +jme_mac_txclk_on(struct jme_adapter *jme) +{ + u32 speed = jme->reg_ghc & GHC_SPEED; + if (speed == GHC_SPEED_1000M) + jme->reg_ghc |= GHC_TO_CLK_GPHY | GHC_TXMAC_CLK_GPHY; + else + jme->reg_ghc |= GHC_TO_CLK_PCIE | GHC_TXMAC_CLK_PCIE; + jwrite32f(jme, JME_GHC, jme->reg_ghc); +} + +static inline void +jme_reset_ghc_speed(struct jme_adapter *jme) +{ + jme->reg_ghc &= ~(GHC_SPEED | GHC_DPX); + jwrite32f(jme, JME_GHC, jme->reg_ghc); +} + +static inline void +jme_reset_250A2_workaround(struct jme_adapter *jme) +{ + jme->reg_gpreg1 &= ~(GPREG1_HALFMODEPATCH | + GPREG1_RSSPATCH); + jwrite32(jme, JME_GPREG1, jme->reg_gpreg1); +} + +static inline void +jme_assert_ghc_reset(struct jme_adapter *jme) +{ + jme->reg_ghc |= GHC_SWRST; + jwrite32f(jme, JME_GHC, jme->reg_ghc); +} + +static inline void +jme_clear_ghc_reset(struct jme_adapter *jme) +{ + jme->reg_ghc &= ~GHC_SWRST; + jwrite32f(jme, JME_GHC, jme->reg_ghc); +} + +static inline void jme_reset_mac_processor(struct jme_adapter *jme) { static const u32 mask[WAKEUP_FRAME_MASK_DWNR] = {0, 0, 0, 0}; @@ -168,9 +229,24 @@ jme_reset_mac_processor(struct jme_adapter *jme) u32 gpreg0; int i; - jwrite32(jme, JME_GHC, jme->reg_ghc | GHC_SWRST); - udelay(2); - jwrite32(jme, JME_GHC, jme->reg_ghc); + jme_reset_ghc_speed(jme); + jme_reset_250A2_workaround(jme); + + jme_mac_rxclk_on(jme); + jme_mac_txclk_on(jme); + udelay(1); + jme_assert_ghc_reset(jme); + udelay(1); + jme_mac_rxclk_off(jme); + jme_mac_txclk_off(jme); + udelay(1); + jme_clear_ghc_reset(jme); + udelay(1); + jme_mac_rxclk_on(jme); + jme_mac_txclk_on(jme); + udelay(1); + jme_mac_rxclk_off(jme); + jme_mac_txclk_off(jme); jwrite32(jme, JME_RXDBA_LO, 0x00000000); jwrite32(jme, JME_RXDBA_HI, 0x00000000); @@ -190,14 +266,6 @@ jme_reset_mac_processor(struct jme_adapter *jme) else gpreg0 = GPREG0_DEFAULT; jwrite32(jme, JME_GPREG0, gpreg0); - jwrite32(jme, JME_GPREG1, GPREG1_DEFAULT); -} - -static inline void -jme_reset_ghc_speed(struct jme_adapter *jme) -{ - jme->reg_ghc &= ~(GHC_SPEED_1000M | GHC_DPX); - jwrite32(jme, JME_GHC, jme->reg_ghc); } static inline void @@ -336,13 +404,13 @@ jme_linkstat_from_phy(struct jme_adapter *jme) } static inline void -jme_set_phyfifoa(struct jme_adapter *jme) +jme_set_phyfifo_5level(struct jme_adapter *jme) { jme_mdio_write(jme->dev, jme->mii_if.phy_id, 27, 0x0004); } static inline void -jme_set_phyfifob(struct jme_adapter *jme) +jme_set_phyfifo_8level(struct jme_adapter *jme) { jme_mdio_write(jme->dev, jme->mii_if.phy_id, 27, 0x0000); } @@ -351,7 +419,7 @@ static int jme_check_link(struct net_device *netdev, int testonly) { struct jme_adapter *jme = netdev_priv(netdev); - u32 phylink, ghc, cnt = JME_SPDRSV_TIMEOUT, bmcr, gpreg1; + u32 phylink, cnt = JME_SPDRSV_TIMEOUT, bmcr; char linkmsg[64]; int rc = 0; @@ -414,23 +482,21 @@ jme_check_link(struct net_device *netdev, int testonly) jme->phylink = phylink; - ghc = jme->reg_ghc & ~(GHC_SPEED | GHC_DPX | - GHC_TO_CLK_PCIE | GHC_TXMAC_CLK_PCIE | - GHC_TO_CLK_GPHY | GHC_TXMAC_CLK_GPHY); + /* + * The speed/duplex setting of jme->reg_ghc already cleared + * by jme_reset_mac_processor() + */ switch (phylink & PHY_LINK_SPEED_MASK) { case PHY_LINK_SPEED_10M: - ghc |= GHC_SPEED_10M | - GHC_TO_CLK_PCIE | GHC_TXMAC_CLK_PCIE; + jme->reg_ghc |= GHC_SPEED_10M; strcat(linkmsg, "10 Mbps, "); break; case PHY_LINK_SPEED_100M: - ghc |= GHC_SPEED_100M | - GHC_TO_CLK_PCIE | GHC_TXMAC_CLK_PCIE; + jme->reg_ghc |= GHC_SPEED_100M; strcat(linkmsg, "100 Mbps, "); break; case PHY_LINK_SPEED_1000M: - ghc |= GHC_SPEED_1000M | - GHC_TO_CLK_GPHY | GHC_TXMAC_CLK_GPHY; + jme->reg_ghc |= GHC_SPEED_1000M; strcat(linkmsg, "1000 Mbps, "); break; default: @@ -439,42 +505,40 @@ jme_check_link(struct net_device *netdev, int testonly) if (phylink & PHY_LINK_DUPLEX) { jwrite32(jme, JME_TXMCS, TXMCS_DEFAULT); - ghc |= GHC_DPX; + jwrite32(jme, JME_TXTRHD, TXTRHD_FULLDUPLEX); + jme->reg_ghc |= GHC_DPX; } else { jwrite32(jme, JME_TXMCS, TXMCS_DEFAULT | TXMCS_BACKOFF | TXMCS_CARRIERSENSE | TXMCS_COLLISION); - jwrite32(jme, JME_TXTRHD, TXTRHD_TXPEN | - ((0x2000 << TXTRHD_TXP_SHIFT) & TXTRHD_TXP) | - TXTRHD_TXREN | - ((8 << TXTRHD_TXRL_SHIFT) & TXTRHD_TXRL)); + jwrite32(jme, JME_TXTRHD, TXTRHD_HALFDUPLEX); } - gpreg1 = GPREG1_DEFAULT; + jwrite32(jme, JME_GHC, jme->reg_ghc); + if (is_buggy250(jme->pdev->device, jme->chiprev)) { + jme->reg_gpreg1 &= ~(GPREG1_HALFMODEPATCH | + GPREG1_RSSPATCH); if (!(phylink & PHY_LINK_DUPLEX)) - gpreg1 |= GPREG1_HALFMODEPATCH; + jme->reg_gpreg1 |= GPREG1_HALFMODEPATCH; switch (phylink & PHY_LINK_SPEED_MASK) { case PHY_LINK_SPEED_10M: - jme_set_phyfifoa(jme); - gpreg1 |= GPREG1_RSSPATCH; + jme_set_phyfifo_8level(jme); + jme->reg_gpreg1 |= GPREG1_RSSPATCH; break; case PHY_LINK_SPEED_100M: - jme_set_phyfifob(jme); - gpreg1 |= GPREG1_RSSPATCH; + jme_set_phyfifo_5level(jme); + jme->reg_gpreg1 |= GPREG1_RSSPATCH; break; case PHY_LINK_SPEED_1000M: - jme_set_phyfifoa(jme); + jme_set_phyfifo_8level(jme); break; default: break; } } - - jwrite32(jme, JME_GPREG1, gpreg1); - jwrite32(jme, JME_GHC, ghc); - jme->reg_ghc = ghc; + jwrite32(jme, JME_GPREG1, jme->reg_gpreg1); strcat(linkmsg, (phylink & PHY_LINK_DUPLEX) ? "Full-Duplex, " : @@ -613,10 +677,14 @@ jme_enable_tx_engine(struct jme_adapter *jme) * Enable TX Engine */ wmb(); - jwrite32(jme, JME_TXCS, jme->reg_txcs | + jwrite32f(jme, JME_TXCS, jme->reg_txcs | TXCS_SELECT_QUEUE0 | TXCS_ENABLE); + /* + * Start clock for TX MAC Processor + */ + jme_mac_txclk_on(jme); } static inline void @@ -651,6 +719,11 @@ jme_disable_tx_engine(struct jme_adapter *jme) if (!i) pr_err("Disable TX engine timeout\n"); + + /* + * Stop clock for TX MAC Processor + */ + jme_mac_txclk_off(jme); } static void @@ -825,16 +898,22 @@ jme_enable_rx_engine(struct jme_adapter *jme) /* * Setup Unicast Filter */ + jme_set_unicastaddr(jme->dev); jme_set_multi(jme->dev); /* * Enable RX Engine */ wmb(); - jwrite32(jme, JME_RXCS, jme->reg_rxcs | + jwrite32f(jme, JME_RXCS, jme->reg_rxcs | RXCS_QUEUESEL_Q0 | RXCS_ENABLE | RXCS_QST); + + /* + * Start clock for RX MAC Processor + */ + jme_mac_rxclk_on(jme); } static inline void @@ -871,10 +950,40 @@ jme_disable_rx_engine(struct jme_adapter *jme) if (!i) pr_err("Disable RX engine timeout\n"); + /* + * Stop clock for RX MAC Processor + */ + jme_mac_rxclk_off(jme); +} + +static u16 +jme_udpsum(struct sk_buff *skb) +{ + u16 csum = 0xFFFFu; + + if (skb->len < (ETH_HLEN + sizeof(struct iphdr))) + return csum; + if (skb->protocol != htons(ETH_P_IP)) + return csum; + skb_set_network_header(skb, ETH_HLEN); + if ((ip_hdr(skb)->protocol != IPPROTO_UDP) || + (skb->len < (ETH_HLEN + + (ip_hdr(skb)->ihl << 2) + + sizeof(struct udphdr)))) { + skb_reset_network_header(skb); + return csum; + } + skb_set_transport_header(skb, + ETH_HLEN + (ip_hdr(skb)->ihl << 2)); + csum = udp_hdr(skb)->check; + skb_reset_transport_header(skb); + skb_reset_network_header(skb); + + return csum; } static int -jme_rxsum_ok(struct jme_adapter *jme, u16 flags) +jme_rxsum_ok(struct jme_adapter *jme, u16 flags, struct sk_buff *skb) { if (!(flags & (RXWBFLAG_TCPON | RXWBFLAG_UDPON | RXWBFLAG_IPV4))) return false; @@ -887,7 +996,7 @@ jme_rxsum_ok(struct jme_adapter *jme, u16 flags) } if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_UDPON | RXWBFLAG_UDPCS)) - == RXWBFLAG_UDPON)) { + == RXWBFLAG_UDPON) && jme_udpsum(skb)) { if (flags & RXWBFLAG_IPV4) netif_err(jme, rx_err, jme->dev, "UDP Checksum error\n"); return false; @@ -935,7 +1044,7 @@ jme_alloc_and_feed_skb(struct jme_adapter *jme, int idx) skb_put(skb, framesize); skb->protocol = eth_type_trans(skb, jme->dev); - if (jme_rxsum_ok(jme, le16_to_cpu(rxdesc->descwb.flags))) + if (jme_rxsum_ok(jme, le16_to_cpu(rxdesc->descwb.flags), skb)) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb_checksum_none_assert(skb); @@ -1207,7 +1316,6 @@ jme_link_change_tasklet(unsigned long arg) tasklet_disable(&jme->rxempty_task); if (netif_carrier_ok(netdev)) { - jme_reset_ghc_speed(jme); jme_disable_rx_engine(jme); jme_disable_tx_engine(jme); jme_reset_mac_processor(jme); @@ -1577,6 +1685,38 @@ jme_free_irq(struct jme_adapter *jme) } static inline void +jme_new_phy_on(struct jme_adapter *jme) +{ + u32 reg; + + reg = jread32(jme, JME_PHY_PWR); + reg &= ~(PHY_PWR_DWN1SEL | PHY_PWR_DWN1SW | + PHY_PWR_DWN2 | PHY_PWR_CLKSEL); + jwrite32(jme, JME_PHY_PWR, reg); + + pci_read_config_dword(jme->pdev, PCI_PRIV_PE1, ®); + reg &= ~PE1_GPREG0_PBG; + reg |= PE1_GPREG0_ENBG; + pci_write_config_dword(jme->pdev, PCI_PRIV_PE1, reg); +} + +static inline void +jme_new_phy_off(struct jme_adapter *jme) +{ + u32 reg; + + reg = jread32(jme, JME_PHY_PWR); + reg |= PHY_PWR_DWN1SEL | PHY_PWR_DWN1SW | + PHY_PWR_DWN2 | PHY_PWR_CLKSEL; + jwrite32(jme, JME_PHY_PWR, reg); + + pci_read_config_dword(jme->pdev, PCI_PRIV_PE1, ®); + reg &= ~PE1_GPREG0_PBG; + reg |= PE1_GPREG0_PDD3COLD; + pci_write_config_dword(jme->pdev, PCI_PRIV_PE1, reg); +} + +static inline void jme_phy_on(struct jme_adapter *jme) { u32 bmcr; @@ -1584,6 +1724,22 @@ jme_phy_on(struct jme_adapter *jme) bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR); bmcr &= ~BMCR_PDOWN; jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, bmcr); + + if (new_phy_power_ctrl(jme->chip_main_rev)) + jme_new_phy_on(jme); +} + +static inline void +jme_phy_off(struct jme_adapter *jme) +{ + u32 bmcr; + + bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR); + bmcr |= BMCR_PDOWN; + jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, bmcr); + + if (new_phy_power_ctrl(jme->chip_main_rev)) + jme_new_phy_off(jme); } static int @@ -1606,12 +1762,11 @@ jme_open(struct net_device *netdev) jme_start_irq(jme); - if (test_bit(JME_FLAG_SSET, &jme->flags)) { - jme_phy_on(jme); + jme_phy_on(jme); + if (test_bit(JME_FLAG_SSET, &jme->flags)) jme_set_settings(netdev, &jme->old_ecmd); - } else { + else jme_reset_phy_processor(jme); - } jme_reset_link(jme); @@ -1657,12 +1812,6 @@ jme_wait_link(struct jme_adapter *jme) } } -static inline void -jme_phy_off(struct jme_adapter *jme) -{ - jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, BMCR_PDOWN); -} - static void jme_powersave_phy(struct jme_adapter *jme) { @@ -1696,7 +1845,6 @@ jme_close(struct net_device *netdev) tasklet_disable(&jme->rxclean_task); tasklet_disable(&jme->rxempty_task); - jme_reset_ghc_speed(jme); jme_disable_rx_engine(jme); jme_disable_tx_engine(jme); jme_reset_mac_processor(jme); @@ -1993,27 +2141,34 @@ jme_start_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; } +static void +jme_set_unicastaddr(struct net_device *netdev) +{ + struct jme_adapter *jme = netdev_priv(netdev); + u32 val; + + val = (netdev->dev_addr[3] & 0xff) << 24 | + (netdev->dev_addr[2] & 0xff) << 16 | + (netdev->dev_addr[1] & 0xff) << 8 | + (netdev->dev_addr[0] & 0xff); + jwrite32(jme, JME_RXUMA_LO, val); + val = (netdev->dev_addr[5] & 0xff) << 8 | + (netdev->dev_addr[4] & 0xff); + jwrite32(jme, JME_RXUMA_HI, val); +} + static int jme_set_macaddr(struct net_device *netdev, void *p) { struct jme_adapter *jme = netdev_priv(netdev); struct sockaddr *addr = p; - u32 val; if (netif_running(netdev)) return -EBUSY; spin_lock_bh(&jme->macaddr_lock); memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); - - val = (addr->sa_data[3] & 0xff) << 24 | - (addr->sa_data[2] & 0xff) << 16 | - (addr->sa_data[1] & 0xff) << 8 | - (addr->sa_data[0] & 0xff); - jwrite32(jme, JME_RXUMA_LO, val); - val = (addr->sa_data[5] & 0xff) << 8 | - (addr->sa_data[4] & 0xff); - jwrite32(jme, JME_RXUMA_HI, val); + jme_set_unicastaddr(netdev); spin_unlock_bh(&jme->macaddr_lock); return 0; @@ -2731,6 +2886,8 @@ jme_check_hw_ver(struct jme_adapter *jme) jme->fpgaver = (chipmode & CM_FPGAVER_MASK) >> CM_FPGAVER_SHIFT; jme->chiprev = (chipmode & CM_CHIPREV_MASK) >> CM_CHIPREV_SHIFT; + jme->chip_main_rev = jme->chiprev & 0xF; + jme->chip_sub_rev = (jme->chiprev >> 4) & 0xF; } static const struct net_device_ops jme_netdev_ops = { @@ -2880,6 +3037,7 @@ jme_init_one(struct pci_dev *pdev, jme->reg_rxmcs = RXMCS_DEFAULT; jme->reg_txpfc = 0; jme->reg_pmcs = PMCS_MFEN; + jme->reg_gpreg1 = GPREG1_DEFAULT; set_bit(JME_FLAG_TXCSUM, &jme->flags); set_bit(JME_FLAG_TSO, &jme->flags); @@ -2936,8 +3094,8 @@ jme_init_one(struct pci_dev *pdev, jme->mii_if.mdio_write = jme_mdio_write; jme_clear_pm(jme); - jme_set_phyfifoa(jme); - pci_read_config_byte(pdev, PCI_REVISION_ID, &jme->rev); + jme_set_phyfifo_5level(jme); + pci_read_config_byte(pdev, PCI_REVISION_ID, &jme->pcirev); if (!jme->fpgaver) jme_phy_init(jme); jme_phy_off(jme); @@ -2964,14 +3122,14 @@ jme_init_one(struct pci_dev *pdev, goto err_out_unmap; } - netif_info(jme, probe, jme->dev, "%s%s ver:%x rev:%x macaddr:%pM\n", + netif_info(jme, probe, jme->dev, "%s%s chiprev:%x pcirev:%x macaddr:%pM\n", (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC250) ? "JMC250 Gigabit Ethernet" : (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC260) ? "JMC260 Fast Ethernet" : "Unknown", (jme->fpgaver != 0) ? " (FPGA)" : "", (jme->fpgaver != 0) ? jme->fpgaver : jme->chiprev, - jme->rev, netdev->dev_addr); + jme->pcirev, netdev->dev_addr); return 0; @@ -3035,7 +3193,6 @@ jme_suspend(struct pci_dev *pdev, pm_message_t state) jme_polling_mode(jme); jme_stop_pcc_timer(jme); - jme_reset_ghc_speed(jme); jme_disable_rx_engine(jme); jme_disable_tx_engine(jme); jme_reset_mac_processor(jme); @@ -3066,12 +3223,11 @@ jme_resume(struct pci_dev *pdev) jme_clear_pm(jme); pci_restore_state(pdev); - if (test_bit(JME_FLAG_SSET, &jme->flags)) { - jme_phy_on(jme); + jme_phy_on(jme); + if (test_bit(JME_FLAG_SSET, &jme->flags)) jme_set_settings(netdev, &jme->old_ecmd); - } else { + else jme_reset_phy_processor(jme); - } jme_start_irq(jme); netif_device_attach(netdev); diff --git a/drivers/net/jme.h b/drivers/net/jme.h index eac09264bf2a..8bf30451e821 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -26,7 +26,7 @@ #define __JME_H_INCLUDED__ #define DRV_NAME "jme" -#define DRV_VERSION "1.0.7" +#define DRV_VERSION "1.0.8" #define PFX DRV_NAME ": " #define PCI_DEVICE_ID_JMICRON_JMC250 0x0250 @@ -103,6 +103,37 @@ enum jme_spi_op_bits { #define HALF_US 500 /* 500 ns */ #define JMESPIIOCTL SIOCDEVPRIVATE +#define PCI_PRIV_PE1 0xE4 + +enum pci_priv_pe1_bit_masks { + PE1_ASPMSUPRT = 0x00000003, /* + * RW: + * Aspm_support[1:0] + * (R/W Port of 5C[11:10]) + */ + PE1_MULTIFUN = 0x00000004, /* RW: Multi_fun_bit */ + PE1_RDYDMA = 0x00000008, /* RO: ~link.rdy_for_dma */ + PE1_ASPMOPTL = 0x00000030, /* RW: link.rx10s_option[1:0] */ + PE1_ASPMOPTH = 0x000000C0, /* RW: 10_req=[3]?HW:[2] */ + PE1_GPREG0 = 0x0000FF00, /* + * SRW: + * Cfg_gp_reg0 + * [7:6] phy_giga BG control + * [5] CREQ_N as CREQ_N1 (CPPE# as CREQ#) + * [4:0] Reserved + */ + PE1_GPREG0_PBG = 0x0000C000, /* phy_giga BG control */ + PE1_GPREG1 = 0x00FF0000, /* RW: Cfg_gp_reg1 */ + PE1_REVID = 0xFF000000, /* RO: Rev ID */ +}; + +enum pci_priv_pe1_values { + PE1_GPREG0_ENBG = 0x00000000, /* en BG */ + PE1_GPREG0_PDD3COLD = 0x00004000, /* giga_PD + d3cold */ + PE1_GPREG0_PDPCIESD = 0x00008000, /* giga_PD + pcie_shutdown */ + PE1_GPREG0_PDPCIEIDDQ = 0x0000C000, /* giga_PD + pcie_iddq */ +}; + /* * Dynamic(adaptive)/Static PCC values */ @@ -403,6 +434,7 @@ struct jme_adapter { u32 reg_rxmcs; u32 reg_ghc; u32 reg_pmcs; + u32 reg_gpreg1; u32 phylink; u32 tx_ring_size; u32 tx_ring_mask; @@ -411,8 +443,10 @@ struct jme_adapter { u32 rx_ring_mask; u8 mrrs; unsigned int fpgaver; - unsigned int chiprev; - u8 rev; + u8 chiprev; + u8 chip_main_rev; + u8 chip_sub_rev; + u8 pcirev; u32 msg_enable; struct ethtool_cmd old_ecmd; unsigned int old_mtu; @@ -497,6 +531,7 @@ enum jme_iomap_regs { JME_PMCS = JME_MAC | 0x60, /* Power Management Control/Stat */ + JME_PHY_PWR = JME_PHY | 0x24, /* New PHY Power Ctrl Register */ JME_PHY_CS = JME_PHY | 0x28, /* PHY Ctrl and Status Register */ JME_PHY_LINK = JME_PHY | 0x30, /* PHY Link Status Register */ JME_SMBCSR = JME_PHY | 0x40, /* SMB Control and Status */ @@ -624,6 +659,14 @@ enum jme_txtrhd_shifts { TXTRHD_TXRL_SHIFT = 0, }; +enum jme_txtrhd_values { + TXTRHD_FULLDUPLEX = 0x00000000, + TXTRHD_HALFDUPLEX = TXTRHD_TXPEN | + ((0x2000 << TXTRHD_TXP_SHIFT) & TXTRHD_TXP) | + TXTRHD_TXREN | + ((8 << TXTRHD_TXRL_SHIFT) & TXTRHD_TXRL), +}; + /* * RX Control/Status Bits */ @@ -779,6 +822,8 @@ static inline u32 smi_phy_addr(int x) */ enum jme_ghc_bit_mask { GHC_SWRST = 0x40000000, + GHC_TO_CLK_SRC = 0x00C00000, + GHC_TXMAC_CLK_SRC = 0x00300000, GHC_DPX = 0x00000040, GHC_SPEED = 0x00000030, GHC_LINK_POLL = 0x00000001, @@ -833,6 +878,21 @@ enum jme_pmcs_bit_masks { }; /* + * New PHY Power Control Register + */ +enum jme_phy_pwr_bit_masks { + PHY_PWR_DWN1SEL = 0x01000000, /* Phy_giga.p_PWR_DOWN1_SEL */ + PHY_PWR_DWN1SW = 0x02000000, /* Phy_giga.p_PWR_DOWN1_SW */ + PHY_PWR_DWN2 = 0x04000000, /* Phy_giga.p_PWR_DOWN2 */ + PHY_PWR_CLKSEL = 0x08000000, /* + * XTL_OUT Clock select + * (an internal free-running clock) + * 0: xtl_out = phy_giga.A_XTL25_O + * 1: xtl_out = phy_giga.PD_OSC + */ +}; + +/* * Giga PHY Status Registers */ enum jme_phy_link_bit_mask { @@ -942,18 +1002,17 @@ enum jme_gpreg0_vals { /* * General Purpose REG-1 - * Note: All theses bits defined here are for - * Chip mode revision 0x11 only */ -enum jme_gpreg1_masks { +enum jme_gpreg1_bit_masks { + GPREG1_RXCLKOFF = 0x04000000, + GPREG1_PCREQN = 0x00020000, + GPREG1_HALFMODEPATCH = 0x00000040, /* For Chip revision 0x11 only */ + GPREG1_RSSPATCH = 0x00000020, /* For Chip revision 0x11 only */ GPREG1_INTRDELAYUNIT = 0x00000018, GPREG1_INTRDELAYENABLE = 0x00000007, }; enum jme_gpreg1_vals { - GPREG1_RSSPATCH = 0x00000040, - GPREG1_HALFMODEPATCH = 0x00000020, - GPREG1_INTDLYUNIT_16NS = 0x00000000, GPREG1_INTDLYUNIT_256NS = 0x00000008, GPREG1_INTDLYUNIT_1US = 0x00000010, @@ -967,7 +1026,7 @@ enum jme_gpreg1_vals { GPREG1_INTDLYEN_6U = 0x00000006, GPREG1_INTDLYEN_7U = 0x00000007, - GPREG1_DEFAULT = 0x00000000, + GPREG1_DEFAULT = GPREG1_PCREQN, }; /* @@ -1184,16 +1243,22 @@ enum jme_phy_reg17_vals { /* * Workaround */ -static inline int is_buggy250(unsigned short device, unsigned int chiprev) +static inline int is_buggy250(unsigned short device, u8 chiprev) { return device == PCI_DEVICE_ID_JMICRON_JMC250 && chiprev == 0x11; } +static inline int new_phy_power_ctrl(u8 chip_main_rev) +{ + return chip_main_rev >= 5; +} + /* * Function prototypes */ static int jme_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd); +static void jme_set_unicastaddr(struct net_device *netdev); static void jme_set_multi(struct net_device *netdev); #endif diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 2d9663a1c54d..ea0dc451da9c 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -129,10 +129,6 @@ static u32 always_on(struct net_device *dev) static const struct ethtool_ops loopback_ethtool_ops = { .get_link = always_on, - .set_tso = ethtool_op_set_tso, - .get_tx_csum = always_on, - .get_sg = always_on, - .get_rx_csum = always_on, }; static int loopback_dev_init(struct net_device *dev) @@ -169,9 +165,12 @@ static void loopback_setup(struct net_device *dev) dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ dev->flags = IFF_LOOPBACK; dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; + dev->hw_features = NETIF_F_ALL_TSO | NETIF_F_UFO; dev->features = NETIF_F_SG | NETIF_F_FRAGLIST - | NETIF_F_TSO + | NETIF_F_ALL_TSO + | NETIF_F_UFO | NETIF_F_NO_CSUM + | NETIF_F_RXCSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL; diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 5933621ac3ff..2300e4599520 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -39,7 +39,7 @@ struct macvtap_queue { struct socket sock; struct socket_wq wq; int vnet_hdr_sz; - struct macvlan_dev *vlan; + struct macvlan_dev __rcu *vlan; struct file *file; unsigned int flags; }; @@ -141,7 +141,8 @@ static void macvtap_put_queue(struct macvtap_queue *q) struct macvlan_dev *vlan; spin_lock(&macvtap_lock); - vlan = rcu_dereference(q->vlan); + vlan = rcu_dereference_protected(q->vlan, + lockdep_is_held(&macvtap_lock)); if (vlan) { int index = get_slot(vlan, q); @@ -219,7 +220,8 @@ static void macvtap_del_queues(struct net_device *dev) /* macvtap_put_queue can free some slots, so go through all slots */ spin_lock(&macvtap_lock); for (i = 0; i < MAX_MACVTAP_QUEUES && vlan->numvtaps; i++) { - q = rcu_dereference(vlan->taps[i]); + q = rcu_dereference_protected(vlan->taps[i], + lockdep_is_held(&macvtap_lock)); if (q) { qlist[j++] = q; rcu_assign_pointer(vlan->taps[i], NULL); @@ -569,7 +571,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, } rcu_read_lock_bh(); - vlan = rcu_dereference(q->vlan); + vlan = rcu_dereference_bh(q->vlan); if (vlan) macvlan_start_xmit(skb, vlan->dev); else @@ -583,7 +585,7 @@ err_kfree: err: rcu_read_lock_bh(); - vlan = rcu_dereference(q->vlan); + vlan = rcu_dereference_bh(q->vlan); if (vlan) vlan->dev->stats.tx_dropped++; rcu_read_unlock_bh(); @@ -631,7 +633,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, ret = skb_copy_datagram_const_iovec(skb, 0, iv, vnet_hdr_len, len); rcu_read_lock_bh(); - vlan = rcu_dereference(q->vlan); + vlan = rcu_dereference_bh(q->vlan); if (vlan) macvlan_count_rx(vlan, len, ret == 0, 0); rcu_read_unlock_bh(); @@ -727,7 +729,7 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, case TUNGETIFF: rcu_read_lock_bh(); - vlan = rcu_dereference(q->vlan); + vlan = rcu_dereference_bh(q->vlan); if (vlan) dev_hold(vlan->dev); rcu_read_unlock_bh(); @@ -736,7 +738,7 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, return -ENOLINK; ret = 0; - if (copy_to_user(&ifr->ifr_name, q->vlan->dev->name, IFNAMSIZ) || + if (copy_to_user(&ifr->ifr_name, vlan->dev->name, IFNAMSIZ) || put_user(q->flags, &ifr->ifr_flags)) ret = -EFAULT; dev_put(vlan->dev); diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 4ffdc18fcb8a..2765a3ce9c24 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -1286,6 +1286,21 @@ static DEFINE_PCI_DEVICE_TABLE(mlx4_pci_table) = { { PCI_VDEVICE(MELLANOX, 0x6764) }, /* MT26468 ConnectX EN 10GigE PCIe gen2*/ { PCI_VDEVICE(MELLANOX, 0x6746) }, /* MT26438 ConnectX EN 40GigE PCIe gen2 5GT/s */ { PCI_VDEVICE(MELLANOX, 0x676e) }, /* MT26478 ConnectX2 40GigE PCIe gen2 */ + { PCI_VDEVICE(MELLANOX, 0x1002) }, /* MT25400 Family [ConnectX-2 Virtual Function] */ + { PCI_VDEVICE(MELLANOX, 0x1003) }, /* MT27500 Family [ConnectX-3] */ + { PCI_VDEVICE(MELLANOX, 0x1004) }, /* MT27500 Family [ConnectX-3 Virtual Function] */ + { PCI_VDEVICE(MELLANOX, 0x1005) }, /* MT27510 Family */ + { PCI_VDEVICE(MELLANOX, 0x1006) }, /* MT27511 Family */ + { PCI_VDEVICE(MELLANOX, 0x1007) }, /* MT27520 Family */ + { PCI_VDEVICE(MELLANOX, 0x1008) }, /* MT27521 Family */ + { PCI_VDEVICE(MELLANOX, 0x1009) }, /* MT27530 Family */ + { PCI_VDEVICE(MELLANOX, 0x100a) }, /* MT27531 Family */ + { PCI_VDEVICE(MELLANOX, 0x100b) }, /* MT27540 Family */ + { PCI_VDEVICE(MELLANOX, 0x100c) }, /* MT27541 Family */ + { PCI_VDEVICE(MELLANOX, 0x100d) }, /* MT27550 Family */ + { PCI_VDEVICE(MELLANOX, 0x100e) }, /* MT27551 Family */ + { PCI_VDEVICE(MELLANOX, 0x100f) }, /* MT27560 Family */ + { PCI_VDEVICE(MELLANOX, 0x1010) }, /* MT27561 Family */ { 0, } }; diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index ea5cfe2c3a04..a7f2eed9a08a 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -253,7 +253,7 @@ struct myri10ge_priv { unsigned long serial_number; int vendor_specific_offset; int fw_multicast_support; - unsigned long features; + u32 features; u32 max_tso6; u32 read_dma; u32 write_dma; @@ -1776,7 +1776,7 @@ static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled) static int myri10ge_set_tso(struct net_device *netdev, u32 tso_enabled) { struct myri10ge_priv *mgp = netdev_priv(netdev); - unsigned long flags = mgp->features & (NETIF_F_TSO6 | NETIF_F_TSO); + u32 flags = mgp->features & (NETIF_F_TSO6 | NETIF_F_TSO); if (tso_enabled) netdev->features |= flags; diff --git a/drivers/net/pch_gbe/pch_gbe.h b/drivers/net/pch_gbe/pch_gbe.h index a0c26a99520f..e1e33c80fb25 100644 --- a/drivers/net/pch_gbe/pch_gbe.h +++ b/drivers/net/pch_gbe/pch_gbe.h @@ -73,7 +73,7 @@ struct pch_gbe_regs { struct pch_gbe_regs_mac_adr mac_adr[16]; u32 ADDR_MASK; u32 MIIM; - u32 reserve2; + u32 MAC_ADDR_LOAD; u32 RGMII_ST; u32 RGMII_CTRL; u32 reserve3[3]; diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index 1bf12339441b..b99e90aca37d 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c @@ -29,6 +29,7 @@ const char pch_driver_version[] = DRV_VERSION; #define PCH_GBE_SHORT_PKT 64 #define DSC_INIT16 0xC000 #define PCH_GBE_DMA_ALIGN 0 +#define PCH_GBE_DMA_PADDING 2 #define PCH_GBE_WATCHDOG_PERIOD (1 * HZ) /* watchdog time */ #define PCH_GBE_COPYBREAK_DEFAULT 256 #define PCH_GBE_PCI_BAR 1 @@ -88,6 +89,12 @@ static unsigned int copybreak __read_mostly = PCH_GBE_COPYBREAK_DEFAULT; static int pch_gbe_mdio_read(struct net_device *netdev, int addr, int reg); static void pch_gbe_mdio_write(struct net_device *netdev, int addr, int reg, int data); + +inline void pch_gbe_mac_load_mac_addr(struct pch_gbe_hw *hw) +{ + iowrite32(0x01, &hw->reg->MAC_ADDR_LOAD); +} + /** * pch_gbe_mac_read_mac_addr - Read MAC address * @hw: Pointer to the HW structure @@ -519,7 +526,9 @@ static void pch_gbe_reset_task(struct work_struct *work) struct pch_gbe_adapter *adapter; adapter = container_of(work, struct pch_gbe_adapter, reset_task); + rtnl_lock(); pch_gbe_reinit_locked(adapter); + rtnl_unlock(); } /** @@ -528,14 +537,8 @@ static void pch_gbe_reset_task(struct work_struct *work) */ void pch_gbe_reinit_locked(struct pch_gbe_adapter *adapter) { - struct net_device *netdev = adapter->netdev; - - rtnl_lock(); - if (netif_running(netdev)) { - pch_gbe_down(adapter); - pch_gbe_up(adapter); - } - rtnl_unlock(); + pch_gbe_down(adapter); + pch_gbe_up(adapter); } /** @@ -1369,16 +1372,13 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter, struct pch_gbe_buffer *buffer_info; struct pch_gbe_rx_desc *rx_desc; u32 length; - unsigned char tmp_packet[ETH_HLEN]; unsigned int i; unsigned int cleaned_count = 0; bool cleaned = false; - struct sk_buff *skb; + struct sk_buff *skb, *new_skb; u8 dma_status; u16 gbec_status; u32 tcp_ip_status; - u8 skb_copy_flag = 0; - u8 skb_padding_flag = 0; i = rx_ring->next_to_clean; @@ -1422,55 +1422,70 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter, pr_err("Receive CRC Error\n"); } else { /* get receive length */ - /* length convert[-3], padding[-2] */ - length = (rx_desc->rx_words_eob) - 3 - 2; + /* length convert[-3] */ + length = (rx_desc->rx_words_eob) - 3; /* Decide the data conversion method */ if (!adapter->rx_csum) { /* [Header:14][payload] */ - skb_padding_flag = 0; - skb_copy_flag = 1; + if (NET_IP_ALIGN) { + /* Because alignment differs, + * the new_skb is newly allocated, + * and data is copied to new_skb.*/ + new_skb = netdev_alloc_skb(netdev, + length + NET_IP_ALIGN); + if (!new_skb) { + /* dorrop error */ + pr_err("New skb allocation " + "Error\n"); + goto dorrop; + } + skb_reserve(new_skb, NET_IP_ALIGN); + memcpy(new_skb->data, skb->data, + length); + skb = new_skb; + } else { + /* DMA buffer is used as SKB as it is.*/ + buffer_info->skb = NULL; + } } else { /* [Header:14][padding:2][payload] */ - skb_padding_flag = 1; - if (length < copybreak) - skb_copy_flag = 1; - else - skb_copy_flag = 0; - } - - /* Data conversion */ - if (skb_copy_flag) { /* recycle skb */ - struct sk_buff *new_skb; - new_skb = - netdev_alloc_skb(netdev, - length + NET_IP_ALIGN); - if (new_skb) { - if (!skb_padding_flag) { - skb_reserve(new_skb, - NET_IP_ALIGN); + /* The length includes padding length */ + length = length - PCH_GBE_DMA_PADDING; + if ((length < copybreak) || + (NET_IP_ALIGN != PCH_GBE_DMA_PADDING)) { + /* Because alignment differs, + * the new_skb is newly allocated, + * and data is copied to new_skb. + * Padding data is deleted + * at the time of a copy.*/ + new_skb = netdev_alloc_skb(netdev, + length + NET_IP_ALIGN); + if (!new_skb) { + /* dorrop error */ + pr_err("New skb allocation " + "Error\n"); + goto dorrop; } + skb_reserve(new_skb, NET_IP_ALIGN); memcpy(new_skb->data, skb->data, - length); - /* save the skb - * in buffer_info as good */ + ETH_HLEN); + memcpy(&new_skb->data[ETH_HLEN], + &skb->data[ETH_HLEN + + PCH_GBE_DMA_PADDING], + length - ETH_HLEN); skb = new_skb; - } else if (!skb_padding_flag) { - /* dorrop error */ - pr_err("New skb allocation Error\n"); - goto dorrop; + } else { + /* Padding data is deleted + * by moving header data.*/ + memmove(&skb->data[PCH_GBE_DMA_PADDING], + &skb->data[0], ETH_HLEN); + skb_reserve(skb, NET_IP_ALIGN); + buffer_info->skb = NULL; } - } else { - buffer_info->skb = NULL; } - if (skb_padding_flag) { - memcpy(&tmp_packet[0], &skb->data[0], ETH_HLEN); - memcpy(&skb->data[NET_IP_ALIGN], &tmp_packet[0], - ETH_HLEN); - skb_reserve(skb, NET_IP_ALIGN); - - } - + /* The length includes FCS length */ + length = length - ETH_FCS_LEN; /* update status of driver */ adapter->stats.rx_bytes += length; adapter->stats.rx_packets++; @@ -2322,6 +2337,7 @@ static int pch_gbe_probe(struct pci_dev *pdev, netdev->features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_GRO; pch_gbe_set_ethtool_ops(netdev); + pch_gbe_mac_load_mac_addr(&adapter->hw); pch_gbe_mac_reset_hw(&adapter->hw); /* setup the private structure */ diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 35fda5ac8120..392a6c4b72e5 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -77,7 +77,6 @@ config NATIONAL_PHY Currently supports the DP83865 PHY. config STE10XP - depends on PHYLIB tristate "Driver for STMicroelectronics STe10Xp PHYs" ---help--- This is the driver for the STe100p and STe101p PHYs. diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 0fd1678bc5a9..590f902deb6b 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -19,13 +19,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/phy.h> - -#define PHY_ID_KSZ9021 0x00221611 -#define PHY_ID_KS8737 0x00221720 -#define PHY_ID_KS8041 0x00221510 -#define PHY_ID_KS8051 0x00221550 -/* both for ks8001 Rev. A/B, and for ks8721 Rev 3. */ -#define PHY_ID_KS8001 0x0022161A +#include <linux/micrel_phy.h> /* general Interrupt control/status reg in vendor specific block. */ #define MII_KSZPHY_INTCS 0x1B @@ -46,6 +40,7 @@ #define KSZPHY_CTRL_INT_ACTIVE_HIGH (1 << 9) #define KSZ9021_CTRL_INT_ACTIVE_HIGH (1 << 14) #define KS8737_CTRL_INT_ACTIVE_HIGH (1 << 14) +#define KSZ8051_RMII_50MHZ_CLK (1 << 7) static int kszphy_ack_interrupt(struct phy_device *phydev) { @@ -106,6 +101,19 @@ static int kszphy_config_init(struct phy_device *phydev) return 0; } +static int ks8051_config_init(struct phy_device *phydev) +{ + int regval; + + if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) { + regval = phy_read(phydev, MII_KSZPHY_CTRL); + regval |= KSZ8051_RMII_50MHZ_CLK; + phy_write(phydev, MII_KSZPHY_CTRL, regval); + } + + return 0; +} + static struct phy_driver ks8737_driver = { .phy_id = PHY_ID_KS8737, .phy_id_mask = 0x00fffff0, @@ -142,7 +150,7 @@ static struct phy_driver ks8051_driver = { .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause | SUPPORTED_Asym_Pause), .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, - .config_init = kszphy_config_init, + .config_init = ks8051_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index c7a6c4466978..9f6d670748d1 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -592,8 +592,8 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ppp_release(NULL, file); err = 0; } else - printk(KERN_DEBUG "PPPIOCDETACH file->f_count=%ld\n", - atomic_long_read(&file->f_count)); + pr_warn("PPPIOCDETACH file->f_count=%ld\n", + atomic_long_read(&file->f_count)); mutex_unlock(&ppp_mutex); return err; } @@ -630,7 +630,7 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (pf->kind != INTERFACE) { /* can't happen */ - printk(KERN_ERR "PPP: not interface or channel??\n"); + pr_err("PPP: not interface or channel??\n"); return -EINVAL; } @@ -704,7 +704,8 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } vj = slhc_init(val2+1, val+1); if (!vj) { - printk(KERN_ERR "PPP: no memory (VJ compressor)\n"); + netdev_err(ppp->dev, + "PPP: no memory (VJ compressor)\n"); err = -ENOMEM; break; } @@ -898,17 +899,17 @@ static int __init ppp_init(void) { int err; - printk(KERN_INFO "PPP generic driver version " PPP_VERSION "\n"); + pr_info("PPP generic driver version " PPP_VERSION "\n"); err = register_pernet_device(&ppp_net_ops); if (err) { - printk(KERN_ERR "failed to register PPP pernet device (%d)\n", err); + pr_err("failed to register PPP pernet device (%d)\n", err); goto out; } err = register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops); if (err) { - printk(KERN_ERR "failed to register PPP device (%d)\n", err); + pr_err("failed to register PPP device (%d)\n", err); goto out_net; } @@ -1078,7 +1079,7 @@ pad_compress_skb(struct ppp *ppp, struct sk_buff *skb) new_skb = alloc_skb(new_skb_size, GFP_ATOMIC); if (!new_skb) { if (net_ratelimit()) - printk(KERN_ERR "PPP: no memory (comp pkt)\n"); + netdev_err(ppp->dev, "PPP: no memory (comp pkt)\n"); return NULL; } if (ppp->dev->hard_header_len > PPP_HDRLEN) @@ -1108,7 +1109,7 @@ pad_compress_skb(struct ppp *ppp, struct sk_buff *skb) * the same number. */ if (net_ratelimit()) - printk(KERN_ERR "ppp: compressor dropped pkt\n"); + netdev_err(ppp->dev, "ppp: compressor dropped pkt\n"); kfree_skb(skb); kfree_skb(new_skb); new_skb = NULL; @@ -1138,7 +1139,9 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) if (ppp->pass_filter && sk_run_filter(skb, ppp->pass_filter) == 0) { if (ppp->debug & 1) - printk(KERN_DEBUG "PPP: outbound frame not passed\n"); + netdev_printk(KERN_DEBUG, ppp->dev, + "PPP: outbound frame " + "not passed\n"); kfree_skb(skb); return; } @@ -1164,7 +1167,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) new_skb = alloc_skb(skb->len + ppp->dev->hard_header_len - 2, GFP_ATOMIC); if (!new_skb) { - printk(KERN_ERR "PPP: no memory (VJ comp pkt)\n"); + netdev_err(ppp->dev, "PPP: no memory (VJ comp pkt)\n"); goto drop; } skb_reserve(new_skb, ppp->dev->hard_header_len - 2); @@ -1202,7 +1205,9 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) proto != PPP_LCP && proto != PPP_CCP) { if (!(ppp->flags & SC_CCP_UP) && (ppp->flags & SC_MUST_COMP)) { if (net_ratelimit()) - printk(KERN_ERR "ppp: compression required but down - pkt dropped.\n"); + netdev_err(ppp->dev, + "ppp: compression required but " + "down - pkt dropped.\n"); goto drop; } skb = pad_compress_skb(ppp, skb); @@ -1505,7 +1510,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) noskb: spin_unlock_bh(&pch->downl); if (ppp->debug & 1) - printk(KERN_ERR "PPP: no memory (fragment)\n"); + netdev_err(ppp->dev, "PPP: no memory (fragment)\n"); ++ppp->dev->stats.tx_errors; ++ppp->nxseq; return 1; /* abandon the frame */ @@ -1686,7 +1691,8 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) /* copy to a new sk_buff with more tailroom */ ns = dev_alloc_skb(skb->len + 128); if (!ns) { - printk(KERN_ERR"PPP: no memory (VJ decomp)\n"); + netdev_err(ppp->dev, "PPP: no memory " + "(VJ decomp)\n"); goto err; } skb_reserve(ns, 2); @@ -1699,7 +1705,8 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) len = slhc_uncompress(ppp->vj, skb->data + 2, skb->len - 2); if (len <= 0) { - printk(KERN_DEBUG "PPP: VJ decompression error\n"); + netdev_printk(KERN_DEBUG, ppp->dev, + "PPP: VJ decompression error\n"); goto err; } len += 2; @@ -1721,7 +1728,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) goto err; if (slhc_remember(ppp->vj, skb->data + 2, skb->len - 2) <= 0) { - printk(KERN_ERR "PPP: VJ uncompressed error\n"); + netdev_err(ppp->dev, "PPP: VJ uncompressed error\n"); goto err; } proto = PPP_IP; @@ -1762,8 +1769,9 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) if (ppp->pass_filter && sk_run_filter(skb, ppp->pass_filter) == 0) { if (ppp->debug & 1) - printk(KERN_DEBUG "PPP: inbound frame " - "not passed\n"); + netdev_printk(KERN_DEBUG, ppp->dev, + "PPP: inbound frame " + "not passed\n"); kfree_skb(skb); return; } @@ -1821,7 +1829,8 @@ ppp_decompress_frame(struct ppp *ppp, struct sk_buff *skb) ns = dev_alloc_skb(obuff_size); if (!ns) { - printk(KERN_ERR "ppp_decompress_frame: no memory\n"); + netdev_err(ppp->dev, "ppp_decompress_frame: " + "no memory\n"); goto err; } /* the decompressor still expects the A/C bytes in the hdr */ @@ -1989,7 +1998,7 @@ ppp_mp_reconstruct(struct ppp *ppp) u32 seq = ppp->nextseq; u32 minseq = ppp->minseq; struct sk_buff_head *list = &ppp->mrq; - struct sk_buff *p, *next; + struct sk_buff *p, *tmp; struct sk_buff *head, *tail; struct sk_buff *skb = NULL; int lost = 0, len = 0; @@ -1998,13 +2007,15 @@ ppp_mp_reconstruct(struct ppp *ppp) return NULL; head = list->next; tail = NULL; - for (p = head; p != (struct sk_buff *) list; p = next) { - next = p->next; + skb_queue_walk_safe(list, p, tmp) { + again: if (seq_before(PPP_MP_CB(p)->sequence, seq)) { /* this can't happen, anyway ignore the skb */ - printk(KERN_ERR "ppp_mp_reconstruct bad seq %u < %u\n", - PPP_MP_CB(p)->sequence, seq); - head = next; + netdev_err(ppp->dev, "ppp_mp_reconstruct bad " + "seq %u < %u\n", + PPP_MP_CB(p)->sequence, seq); + __skb_unlink(p, list); + kfree_skb(p); continue; } if (PPP_MP_CB(p)->sequence != seq) { @@ -2016,8 +2027,7 @@ ppp_mp_reconstruct(struct ppp *ppp) lost = 1; seq = seq_before(minseq, PPP_MP_CB(p)->sequence)? minseq + 1: PPP_MP_CB(p)->sequence; - next = p; - continue; + goto again; } /* @@ -2042,17 +2052,9 @@ ppp_mp_reconstruct(struct ppp *ppp) (PPP_MP_CB(head)->BEbits & B)) { if (len > ppp->mrru + 2) { ++ppp->dev->stats.rx_length_errors; - printk(KERN_DEBUG "PPP: reconstructed packet" - " is too long (%d)\n", len); - } else if (p == head) { - /* fragment is complete packet - reuse skb */ - tail = p; - skb = skb_get(p); - break; - } else if ((skb = dev_alloc_skb(len)) == NULL) { - ++ppp->dev->stats.rx_missed_errors; - printk(KERN_DEBUG "PPP: no memory for " - "reconstructed packet"); + netdev_printk(KERN_DEBUG, ppp->dev, + "PPP: reconstructed packet" + " is too long (%d)\n", len); } else { tail = p; break; @@ -2065,9 +2067,17 @@ ppp_mp_reconstruct(struct ppp *ppp) * and we haven't found a complete valid packet yet, * we can discard up to and including this fragment. */ - if (PPP_MP_CB(p)->BEbits & E) - head = next; + if (PPP_MP_CB(p)->BEbits & E) { + struct sk_buff *tmp2; + skb_queue_reverse_walk_from_safe(list, p, tmp2) { + __skb_unlink(p, list); + kfree_skb(p); + } + head = skb_peek(list); + if (!head) + break; + } ++seq; } @@ -2077,26 +2087,37 @@ ppp_mp_reconstruct(struct ppp *ppp) signal a receive error. */ if (PPP_MP_CB(head)->sequence != ppp->nextseq) { if (ppp->debug & 1) - printk(KERN_DEBUG " missed pkts %u..%u\n", - ppp->nextseq, - PPP_MP_CB(head)->sequence-1); + netdev_printk(KERN_DEBUG, ppp->dev, + " missed pkts %u..%u\n", + ppp->nextseq, + PPP_MP_CB(head)->sequence-1); ++ppp->dev->stats.rx_dropped; ppp_receive_error(ppp); } - if (head != tail) - /* copy to a single skb */ - for (p = head; p != tail->next; p = p->next) - skb_copy_bits(p, 0, skb_put(skb, p->len), p->len); - ppp->nextseq = PPP_MP_CB(tail)->sequence + 1; - head = tail->next; - } + skb = head; + if (head != tail) { + struct sk_buff **fragpp = &skb_shinfo(skb)->frag_list; + p = skb_queue_next(list, head); + __skb_unlink(skb, list); + skb_queue_walk_from_safe(list, p, tmp) { + __skb_unlink(p, list); + *fragpp = p; + p->next = NULL; + fragpp = &p->next; + + skb->len += p->len; + skb->data_len += p->len; + skb->truesize += p->len; + + if (p == tail) + break; + } + } else { + __skb_unlink(skb, list); + } - /* Discard all the skbuffs that we have copied the data out of - or that we can't use. */ - while ((p = list->next) != head) { - __skb_unlink(p, list); - kfree_skb(p); + ppp->nextseq = PPP_MP_CB(tail)->sequence + 1; } return skb; @@ -2617,8 +2638,8 @@ ppp_create_interface(struct net *net, int unit, int *retp) ret = register_netdev(dev); if (ret != 0) { unit_put(&pn->units_idr, unit); - printk(KERN_ERR "PPP: couldn't register device %s (%d)\n", - dev->name, ret); + netdev_err(ppp->dev, "PPP: couldn't register device %s (%d)\n", + dev->name, ret); goto out2; } @@ -2690,9 +2711,9 @@ static void ppp_destroy_interface(struct ppp *ppp) if (!ppp->file.dead || ppp->n_channels) { /* "can't happen" */ - printk(KERN_ERR "ppp: destroying ppp struct %p but dead=%d " - "n_channels=%d !\n", ppp, ppp->file.dead, - ppp->n_channels); + netdev_err(ppp->dev, "ppp: destroying ppp struct %p " + "but dead=%d n_channels=%d !\n", + ppp, ppp->file.dead, ppp->n_channels); return; } @@ -2834,8 +2855,7 @@ static void ppp_destroy_channel(struct channel *pch) if (!pch->file.dead) { /* "can't happen" */ - printk(KERN_ERR "ppp: destroying undead channel %p !\n", - pch); + pr_err("ppp: destroying undead channel %p !\n", pch); return; } skb_queue_purge(&pch->file.xq); @@ -2847,7 +2867,7 @@ static void __exit ppp_cleanup(void) { /* should never happen */ if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count)) - printk(KERN_ERR "PPP: removing module but units remain!\n"); + pr_err("PPP: removing module but units remain!\n"); unregister_chrdev(PPP_MAJOR, "ppp"); device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); class_destroy(ppp_class); @@ -2865,7 +2885,7 @@ static int __unit_alloc(struct idr *p, void *ptr, int n) again: if (!idr_pre_get(p, GFP_KERNEL)) { - printk(KERN_ERR "PPP: No free memory for idr\n"); + pr_err("PPP: No free memory for idr\n"); return -ENOMEM; } diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 59ccf0c5c610..469ab0b7ce31 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -3190,6 +3190,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (pci_dev_run_wake(pdev)) pm_runtime_put_noidle(&pdev->dev); + netif_carrier_off(dev); + out: return rc; diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 002bac743843..d4e04256730b 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -673,7 +673,7 @@ static void efx_fini_channels(struct efx_nic *efx) efx_for_each_channel_rx_queue(rx_queue, channel) efx_fini_rx_queue(rx_queue); - efx_for_each_channel_tx_queue(tx_queue, channel) + efx_for_each_possible_channel_tx_queue(tx_queue, channel) efx_fini_tx_queue(tx_queue); efx_fini_eventq(channel); } @@ -689,7 +689,7 @@ static void efx_remove_channel(struct efx_channel *channel) efx_for_each_channel_rx_queue(rx_queue, channel) efx_remove_rx_queue(rx_queue); - efx_for_each_channel_tx_queue(tx_queue, channel) + efx_for_each_possible_channel_tx_queue(tx_queue, channel) efx_remove_tx_queue(tx_queue); efx_remove_eventq(channel); } @@ -1271,21 +1271,8 @@ static void efx_remove_interrupts(struct efx_nic *efx) static void efx_set_channels(struct efx_nic *efx) { - struct efx_channel *channel; - struct efx_tx_queue *tx_queue; - efx->tx_channel_offset = separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0; - - /* Channel pointers were set in efx_init_struct() but we now - * need to clear them for TX queues in any RX-only channels. */ - efx_for_each_channel(channel, efx) { - if (channel->channel - efx->tx_channel_offset >= - efx->n_tx_channels) { - efx_for_each_channel_tx_queue(tx_queue, channel) - tx_queue->channel = NULL; - } - } } static int efx_probe_nic(struct efx_nic *efx) @@ -1531,9 +1518,9 @@ void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs, efx->irq_rx_adaptive = rx_adaptive; efx->irq_rx_moderation = rx_ticks; efx_for_each_channel(channel, efx) { - if (efx_channel_get_rx_queue(channel)) + if (efx_channel_has_rx_queue(channel)) channel->irq_moderation = rx_ticks; - else if (efx_channel_get_tx_queue(channel, 0)) + else if (efx_channel_has_tx_queues(channel)) channel->irq_moderation = tx_ticks; } } @@ -1849,6 +1836,7 @@ static const struct net_device_ops efx_netdev_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = efx_netpoll, #endif + .ndo_setup_tc = efx_setup_tc, }; static void efx_update_name(struct efx_nic *efx) @@ -1910,10 +1898,8 @@ static int efx_register_netdev(struct efx_nic *efx) efx_for_each_channel(channel, efx) { struct efx_tx_queue *tx_queue; - efx_for_each_channel_tx_queue(tx_queue, channel) { - tx_queue->core_txq = netdev_get_tx_queue( - efx->net_dev, tx_queue->queue / EFX_TXQ_TYPES); - } + efx_for_each_channel_tx_queue(tx_queue, channel) + efx_init_tx_queue_core_txq(tx_queue); } /* Always start with carrier off; PHY events will detect the link */ @@ -2401,7 +2387,8 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, int i, rc; /* Allocate and initialise a struct net_device and struct efx_nic */ - net_dev = alloc_etherdev_mq(sizeof(*efx), EFX_MAX_CORE_TX_QUEUES); + net_dev = alloc_etherdev_mqs(sizeof(*efx), EFX_MAX_CORE_TX_QUEUES, + EFX_MAX_RX_QUEUES); if (!net_dev) return -ENOMEM; net_dev->features |= (type->offload_features | NETIF_F_SG | diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index d43a7e5212b1..0cb198a64a63 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -29,6 +29,7 @@ extern int efx_probe_tx_queue(struct efx_tx_queue *tx_queue); extern void efx_remove_tx_queue(struct efx_tx_queue *tx_queue); extern void efx_init_tx_queue(struct efx_tx_queue *tx_queue); +extern void efx_init_tx_queue_core_txq(struct efx_tx_queue *tx_queue); extern void efx_fini_tx_queue(struct efx_tx_queue *tx_queue); extern void efx_release_tx_buffers(struct efx_tx_queue *tx_queue); extern netdev_tx_t @@ -36,6 +37,7 @@ efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev); extern netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb); extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index); +extern int efx_setup_tc(struct net_device *net_dev, u8 num_tc); /* RX */ extern int efx_probe_rx_queue(struct efx_rx_queue *rx_queue); diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 0e8bb19ed60d..272cfe724e1b 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -502,7 +502,7 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable) { struct efx_nic *efx __attribute__ ((unused)) = netdev_priv(net_dev); - unsigned long features; + u32 features; features = NETIF_F_TSO; if (efx->type->offload_features & NETIF_F_V6_CSUM) @@ -519,7 +519,7 @@ static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable) static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable) { struct efx_nic *efx = netdev_priv(net_dev); - unsigned long features = efx->type->offload_features & NETIF_F_ALL_CSUM; + u32 features = efx->type->offload_features & NETIF_F_ALL_CSUM; if (enable) net_dev->features |= features; @@ -631,7 +631,7 @@ static int efx_ethtool_get_coalesce(struct net_device *net_dev, /* Find lowest IRQ moderation across all used TX queues */ coalesce->tx_coalesce_usecs_irq = ~((u32) 0); efx_for_each_channel(channel, efx) { - if (!efx_channel_get_tx_queue(channel, 0)) + if (!efx_channel_has_tx_queues(channel)) continue; if (channel->irq_moderation < coalesce->tx_coalesce_usecs_irq) { if (channel->channel < efx->n_rx_channels) @@ -676,8 +676,8 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev, /* If the channel is shared only allow RX parameters to be set */ efx_for_each_channel(channel, efx) { - if (efx_channel_get_rx_queue(channel) && - efx_channel_get_tx_queue(channel, 0) && + if (efx_channel_has_rx_queue(channel) && + efx_channel_has_tx_queues(channel) && tx_usecs) { netif_err(efx, drv, efx->net_dev, "Channel is shared. " "Only RX coalescing may be set\n"); diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 28df8665256a..96e22ad34970 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -63,10 +63,12 @@ /* Checksum generation is a per-queue option in hardware, so each * queue visible to the networking core is backed by two hardware TX * queues. */ -#define EFX_MAX_CORE_TX_QUEUES EFX_MAX_CHANNELS -#define EFX_TXQ_TYPE_OFFLOAD 1 -#define EFX_TXQ_TYPES 2 -#define EFX_MAX_TX_QUEUES (EFX_TXQ_TYPES * EFX_MAX_CORE_TX_QUEUES) +#define EFX_MAX_TX_TC 2 +#define EFX_MAX_CORE_TX_QUEUES (EFX_MAX_TX_TC * EFX_MAX_CHANNELS) +#define EFX_TXQ_TYPE_OFFLOAD 1 /* flag */ +#define EFX_TXQ_TYPE_HIGHPRI 2 /* flag */ +#define EFX_TXQ_TYPES 4 +#define EFX_MAX_TX_QUEUES (EFX_TXQ_TYPES * EFX_MAX_CHANNELS) /** * struct efx_special_buffer - An Efx special buffer @@ -140,6 +142,7 @@ struct efx_tx_buffer { * @buffer: The software buffer ring * @txd: The hardware descriptor ring * @ptr_mask: The size of the ring minus 1. + * @initialised: Has hardware queue been initialised? * @flushed: Used when handling queue flushing * @read_count: Current read pointer. * This is the number of buffers that have been removed from both rings. @@ -182,6 +185,7 @@ struct efx_tx_queue { struct efx_tx_buffer *buffer; struct efx_special_buffer txd; unsigned int ptr_mask; + bool initialised; enum efx_flush_state flushed; /* Members used mainly on the completion path */ @@ -377,7 +381,7 @@ struct efx_channel { bool rx_pkt_csummed; struct efx_rx_queue rx_queue; - struct efx_tx_queue tx_queue[2]; + struct efx_tx_queue tx_queue[EFX_TXQ_TYPES]; }; enum efx_led_mode { @@ -906,7 +910,7 @@ struct efx_nic_type { unsigned int phys_addr_channels; unsigned int tx_dc_base; unsigned int rx_dc_base; - unsigned long offload_features; + u32 offload_features; u32 reset_world_flags; }; @@ -938,18 +942,40 @@ efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type) return &efx->channel[efx->tx_channel_offset + index]->tx_queue[type]; } +static inline bool efx_channel_has_tx_queues(struct efx_channel *channel) +{ + return channel->channel - channel->efx->tx_channel_offset < + channel->efx->n_tx_channels; +} + static inline struct efx_tx_queue * efx_channel_get_tx_queue(struct efx_channel *channel, unsigned type) { - struct efx_tx_queue *tx_queue = channel->tx_queue; - EFX_BUG_ON_PARANOID(type >= EFX_TXQ_TYPES); - return tx_queue->channel ? tx_queue + type : NULL; + EFX_BUG_ON_PARANOID(!efx_channel_has_tx_queues(channel) || + type >= EFX_TXQ_TYPES); + return &channel->tx_queue[type]; +} + +static inline bool efx_tx_queue_used(struct efx_tx_queue *tx_queue) +{ + return !(tx_queue->efx->net_dev->num_tc < 2 && + tx_queue->queue & EFX_TXQ_TYPE_HIGHPRI); } /* Iterate over all TX queues belonging to a channel */ #define efx_for_each_channel_tx_queue(_tx_queue, _channel) \ - for (_tx_queue = efx_channel_get_tx_queue(channel, 0); \ - _tx_queue && _tx_queue < (_channel)->tx_queue + EFX_TXQ_TYPES; \ + if (!efx_channel_has_tx_queues(_channel)) \ + ; \ + else \ + for (_tx_queue = (_channel)->tx_queue; \ + _tx_queue < (_channel)->tx_queue + EFX_TXQ_TYPES && \ + efx_tx_queue_used(_tx_queue); \ + _tx_queue++) + +/* Iterate over all possible TX queues belonging to a channel */ +#define efx_for_each_possible_channel_tx_queue(_tx_queue, _channel) \ + for (_tx_queue = (_channel)->tx_queue; \ + _tx_queue < (_channel)->tx_queue + EFX_TXQ_TYPES; \ _tx_queue++) static inline struct efx_rx_queue * @@ -959,18 +985,26 @@ efx_get_rx_queue(struct efx_nic *efx, unsigned index) return &efx->channel[index]->rx_queue; } +static inline bool efx_channel_has_rx_queue(struct efx_channel *channel) +{ + return channel->channel < channel->efx->n_rx_channels; +} + static inline struct efx_rx_queue * efx_channel_get_rx_queue(struct efx_channel *channel) { - return channel->channel < channel->efx->n_rx_channels ? - &channel->rx_queue : NULL; + EFX_BUG_ON_PARANOID(!efx_channel_has_rx_queue(channel)); + return &channel->rx_queue; } /* Iterate over all RX queues belonging to a channel */ #define efx_for_each_channel_rx_queue(_rx_queue, _channel) \ - for (_rx_queue = efx_channel_get_rx_queue(channel); \ - _rx_queue; \ - _rx_queue = NULL) + if (!efx_channel_has_rx_queue(_channel)) \ + ; \ + else \ + for (_rx_queue = &(_channel)->rx_queue; \ + _rx_queue; \ + _rx_queue = NULL) static inline struct efx_channel * efx_rx_queue_channel(struct efx_rx_queue *rx_queue) diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index da386599ab68..1d0b8b6f25c4 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -445,8 +445,8 @@ int efx_nic_probe_tx(struct efx_tx_queue *tx_queue) void efx_nic_init_tx(struct efx_tx_queue *tx_queue) { - efx_oword_t tx_desc_ptr; struct efx_nic *efx = tx_queue->efx; + efx_oword_t reg; tx_queue->flushed = FLUSH_NONE; @@ -454,7 +454,7 @@ void efx_nic_init_tx(struct efx_tx_queue *tx_queue) efx_init_special_buffer(efx, &tx_queue->txd); /* Push TX descriptor ring to card */ - EFX_POPULATE_OWORD_10(tx_desc_ptr, + EFX_POPULATE_OWORD_10(reg, FRF_AZ_TX_DESCQ_EN, 1, FRF_AZ_TX_ISCSI_DDIG_EN, 0, FRF_AZ_TX_ISCSI_HDIG_EN, 0, @@ -470,17 +470,15 @@ void efx_nic_init_tx(struct efx_tx_queue *tx_queue) if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { int csum = tx_queue->queue & EFX_TXQ_TYPE_OFFLOAD; - EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_IP_CHKSM_DIS, !csum); - EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_TCP_CHKSM_DIS, + EFX_SET_OWORD_FIELD(reg, FRF_BZ_TX_IP_CHKSM_DIS, !csum); + EFX_SET_OWORD_FIELD(reg, FRF_BZ_TX_TCP_CHKSM_DIS, !csum); } - efx_writeo_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base, + efx_writeo_table(efx, ®, efx->type->txd_ptr_tbl_base, tx_queue->queue); if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) { - efx_oword_t reg; - /* Only 128 bits in this register */ BUILD_BUG_ON(EFX_MAX_TX_QUEUES > 128); @@ -491,6 +489,16 @@ void efx_nic_init_tx(struct efx_tx_queue *tx_queue) set_bit_le(tx_queue->queue, (void *)®); efx_writeo(efx, ®, FR_AA_TX_CHKSM_CFG); } + + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { + EFX_POPULATE_OWORD_1(reg, + FRF_BZ_TX_PACE, + (tx_queue->queue & EFX_TXQ_TYPE_HIGHPRI) ? + FFE_BZ_TX_PACE_OFF : + FFE_BZ_TX_PACE_RESERVED); + efx_writeo_table(efx, ®, FR_BZ_TX_PACE_TBL, + tx_queue->queue); + } } static void efx_flush_tx_queue(struct efx_tx_queue *tx_queue) @@ -1238,8 +1246,10 @@ int efx_nic_flush_queues(struct efx_nic *efx) /* Flush all tx queues in parallel */ efx_for_each_channel(channel, efx) { - efx_for_each_channel_tx_queue(tx_queue, channel) - efx_flush_tx_queue(tx_queue); + efx_for_each_possible_channel_tx_queue(tx_queue, channel) { + if (tx_queue->initialised) + efx_flush_tx_queue(tx_queue); + } } /* The hardware supports four concurrent rx flushes, each of which may @@ -1262,8 +1272,9 @@ int efx_nic_flush_queues(struct efx_nic *efx) ++rx_pending; } } - efx_for_each_channel_tx_queue(tx_queue, channel) { - if (tx_queue->flushed != FLUSH_DONE) + efx_for_each_possible_channel_tx_queue(tx_queue, channel) { + if (tx_queue->initialised && + tx_queue->flushed != FLUSH_DONE) ++tx_pending; } } @@ -1278,8 +1289,9 @@ int efx_nic_flush_queues(struct efx_nic *efx) /* Mark the queues as all flushed. We're going to return failure * leading to a reset, or fake up success anyway */ efx_for_each_channel(channel, efx) { - efx_for_each_channel_tx_queue(tx_queue, channel) { - if (tx_queue->flushed != FLUSH_DONE) + efx_for_each_possible_channel_tx_queue(tx_queue, channel) { + if (tx_queue->initialised && + tx_queue->flushed != FLUSH_DONE) netif_err(efx, hw, efx->net_dev, "tx queue %d flush command timed out\n", tx_queue->queue); @@ -1682,6 +1694,19 @@ void efx_nic_init_common(struct efx_nic *efx) if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1); efx_writeo(efx, &temp, FR_AZ_TX_RESERVED); + + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { + EFX_POPULATE_OWORD_4(temp, + /* Default values */ + FRF_BZ_TX_PACE_SB_NOT_AF, 0x15, + FRF_BZ_TX_PACE_SB_AF, 0xb, + FRF_BZ_TX_PACE_FB_BASE, 0, + /* Allow large pace values in the + * fast bin. */ + FRF_BZ_TX_PACE_BIN_TH, + FFE_BZ_TX_PACE_RESERVED); + efx_writeo(efx, &temp, FR_BZ_TX_PACE); + } } /* Register dump */ diff --git a/drivers/net/sfc/regs.h b/drivers/net/sfc/regs.h index 96430ed81c36..8227de62014f 100644 --- a/drivers/net/sfc/regs.h +++ b/drivers/net/sfc/regs.h @@ -2907,6 +2907,12 @@ #define FRF_CZ_TMFT_SRC_MAC_HI_LBN 44 #define FRF_CZ_TMFT_SRC_MAC_HI_WIDTH 16 +/* TX_PACE_TBL */ +/* Values >20 are documented as reserved, but will result in a queue going + * into the fast bin with a pace value of zero. */ +#define FFE_BZ_TX_PACE_OFF 0 +#define FFE_BZ_TX_PACE_RESERVED 21 + /* DRIVER_EV */ /* Sub-fields of an RX flush completion event */ #define FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL_LBN 12 diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 0ebfb99f1299..f936892aa423 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -644,7 +644,7 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, goto out; } - /* Test both types of TX queue */ + /* Test all enabled types of TX queue */ efx_for_each_channel_tx_queue(tx_queue, channel) { state->offload_csum = (tx_queue->queue & EFX_TXQ_TYPE_OFFLOAD); diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index 2f5e9da657bf..1a51653bb92b 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -336,17 +336,91 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, { struct efx_nic *efx = netdev_priv(net_dev); struct efx_tx_queue *tx_queue; + unsigned index, type; if (unlikely(efx->port_inhibited)) return NETDEV_TX_BUSY; - tx_queue = efx_get_tx_queue(efx, skb_get_queue_mapping(skb), - skb->ip_summed == CHECKSUM_PARTIAL ? - EFX_TXQ_TYPE_OFFLOAD : 0); + index = skb_get_queue_mapping(skb); + type = skb->ip_summed == CHECKSUM_PARTIAL ? EFX_TXQ_TYPE_OFFLOAD : 0; + if (index >= efx->n_tx_channels) { + index -= efx->n_tx_channels; + type |= EFX_TXQ_TYPE_HIGHPRI; + } + tx_queue = efx_get_tx_queue(efx, index, type); return efx_enqueue_skb(tx_queue, skb); } +void efx_init_tx_queue_core_txq(struct efx_tx_queue *tx_queue) +{ + struct efx_nic *efx = tx_queue->efx; + + /* Must be inverse of queue lookup in efx_hard_start_xmit() */ + tx_queue->core_txq = + netdev_get_tx_queue(efx->net_dev, + tx_queue->queue / EFX_TXQ_TYPES + + ((tx_queue->queue & EFX_TXQ_TYPE_HIGHPRI) ? + efx->n_tx_channels : 0)); +} + +int efx_setup_tc(struct net_device *net_dev, u8 num_tc) +{ + struct efx_nic *efx = netdev_priv(net_dev); + struct efx_channel *channel; + struct efx_tx_queue *tx_queue; + unsigned tc; + int rc; + + if (efx_nic_rev(efx) < EFX_REV_FALCON_B0 || num_tc > EFX_MAX_TX_TC) + return -EINVAL; + + if (num_tc == net_dev->num_tc) + return 0; + + for (tc = 0; tc < num_tc; tc++) { + net_dev->tc_to_txq[tc].offset = tc * efx->n_tx_channels; + net_dev->tc_to_txq[tc].count = efx->n_tx_channels; + } + + if (num_tc > net_dev->num_tc) { + /* Initialise high-priority queues as necessary */ + efx_for_each_channel(channel, efx) { + efx_for_each_possible_channel_tx_queue(tx_queue, + channel) { + if (!(tx_queue->queue & EFX_TXQ_TYPE_HIGHPRI)) + continue; + if (!tx_queue->buffer) { + rc = efx_probe_tx_queue(tx_queue); + if (rc) + return rc; + } + if (!tx_queue->initialised) + efx_init_tx_queue(tx_queue); + efx_init_tx_queue_core_txq(tx_queue); + } + } + } else { + /* Reduce number of classes before number of queues */ + net_dev->num_tc = num_tc; + } + + rc = netif_set_real_num_tx_queues(net_dev, + max_t(int, num_tc, 1) * + efx->n_tx_channels); + if (rc) + return rc; + + /* Do not destroy high-priority queues when they become + * unused. We would have to flush them first, and it is + * fairly difficult to flush a subset of TX queues. Leave + * it to efx_fini_channels(). + */ + + net_dev->num_tc = num_tc; + return 0; +} + void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) { unsigned fill_level; @@ -430,6 +504,8 @@ void efx_init_tx_queue(struct efx_tx_queue *tx_queue) /* Set up TX descriptor ring */ efx_nic_init_tx(tx_queue); + + tx_queue->initialised = true; } void efx_release_tx_buffers(struct efx_tx_queue *tx_queue) @@ -452,9 +528,14 @@ void efx_release_tx_buffers(struct efx_tx_queue *tx_queue) void efx_fini_tx_queue(struct efx_tx_queue *tx_queue) { + if (!tx_queue->initialised) + return; + netif_dbg(tx_queue->efx, drv, tx_queue->efx->net_dev, "shutting down TX queue %d\n", tx_queue->queue); + tx_queue->initialised = false; + /* Flush TX queue, remove descriptor ring */ efx_nic_fini_tx(tx_queue); @@ -466,6 +547,9 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue) void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) { + if (!tx_queue->buffer) + return; + netif_dbg(tx_queue->efx, drv, tx_queue->efx->net_dev, "destroying TX queue %d\n", tx_queue->queue); efx_nic_remove_tx(tx_queue); diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 819c1750e2ab..095e52580884 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -32,10 +32,17 @@ #include <linux/io.h> #include <linux/pm_runtime.h> #include <linux/slab.h> +#include <linux/ethtool.h> #include <asm/cacheflush.h> #include "sh_eth.h" +#define SH_ETH_DEF_MSG_ENABLE \ + (NETIF_MSG_LINK | \ + NETIF_MSG_TIMER | \ + NETIF_MSG_RX_ERR| \ + NETIF_MSG_TX_ERR) + /* There is CPU dependent code */ #if defined(CONFIG_CPU_SUBTYPE_SH7724) #define SH_ETH_RESET_DEFAULT 1 @@ -817,6 +824,20 @@ static int sh_eth_rx(struct net_device *ndev) return 0; } +static void sh_eth_rcv_snd_disable(u32 ioaddr) +{ + /* disable tx and rx */ + writel(readl(ioaddr + ECMR) & + ~(ECMR_RE | ECMR_TE), ioaddr + ECMR); +} + +static void sh_eth_rcv_snd_enable(u32 ioaddr) +{ + /* enable tx and rx */ + writel(readl(ioaddr + ECMR) | + (ECMR_RE | ECMR_TE), ioaddr + ECMR); +} + /* error control function */ static void sh_eth_error(struct net_device *ndev, int intr_status) { @@ -843,11 +864,9 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) if (mdp->ether_link_active_low) link_stat = ~link_stat; } - if (!(link_stat & PHY_ST_LINK)) { - /* Link Down : disable tx and rx */ - writel(readl(ioaddr + ECMR) & - ~(ECMR_RE | ECMR_TE), ioaddr + ECMR); - } else { + if (!(link_stat & PHY_ST_LINK)) + sh_eth_rcv_snd_disable(ioaddr); + else { /* Link Up */ writel(readl(ioaddr + EESIPR) & ~DMAC_M_ECI, ioaddr + EESIPR); @@ -857,8 +876,7 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) writel(readl(ioaddr + EESIPR) | DMAC_M_ECI, ioaddr + EESIPR); /* enable tx and rx */ - writel(readl(ioaddr + ECMR) | - (ECMR_RE | ECMR_TE), ioaddr + ECMR); + sh_eth_rcv_snd_enable(ioaddr); } } } @@ -867,6 +885,8 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) /* Write buck end. unused write back interrupt */ if (intr_status & EESR_TABT) /* Transmit Abort int */ mdp->stats.tx_aborted_errors++; + if (netif_msg_tx_err(mdp)) + dev_err(&ndev->dev, "Transmit Abort\n"); } if (intr_status & EESR_RABT) { @@ -874,14 +894,23 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) if (intr_status & EESR_RFRMER) { /* Receive Frame Overflow int */ mdp->stats.rx_frame_errors++; - dev_err(&ndev->dev, "Receive Frame Overflow\n"); + if (netif_msg_rx_err(mdp)) + dev_err(&ndev->dev, "Receive Abort\n"); } } - if (!mdp->cd->no_ade) { - if (intr_status & EESR_ADE && intr_status & EESR_TDE && - intr_status & EESR_TFE) - mdp->stats.tx_fifo_errors++; + if (intr_status & EESR_TDE) { + /* Transmit Descriptor Empty int */ + mdp->stats.tx_fifo_errors++; + if (netif_msg_tx_err(mdp)) + dev_err(&ndev->dev, "Transmit Descriptor Empty\n"); + } + + if (intr_status & EESR_TFE) { + /* FIFO under flow */ + mdp->stats.tx_fifo_errors++; + if (netif_msg_tx_err(mdp)) + dev_err(&ndev->dev, "Transmit FIFO Under flow\n"); } if (intr_status & EESR_RDE) { @@ -890,12 +919,22 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) if (readl(ioaddr + EDRRR) ^ EDRRR_R) writel(EDRRR_R, ioaddr + EDRRR); - dev_err(&ndev->dev, "Receive Descriptor Empty\n"); + if (netif_msg_rx_err(mdp)) + dev_err(&ndev->dev, "Receive Descriptor Empty\n"); } + if (intr_status & EESR_RFE) { /* Receive FIFO Overflow int */ mdp->stats.rx_fifo_errors++; - dev_err(&ndev->dev, "Receive FIFO Overflow\n"); + if (netif_msg_rx_err(mdp)) + dev_err(&ndev->dev, "Receive FIFO Overflow\n"); + } + + if (!mdp->cd->no_ade && (intr_status & EESR_ADE)) { + /* Address Error */ + mdp->stats.tx_fifo_errors++; + if (netif_msg_tx_err(mdp)) + dev_err(&ndev->dev, "Address Error\n"); } mask = EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE; @@ -1012,7 +1051,7 @@ static void sh_eth_adjust_link(struct net_device *ndev) mdp->duplex = -1; } - if (new_state) + if (new_state && netif_msg_link(mdp)) phy_print_status(phydev); } @@ -1063,6 +1102,132 @@ static int sh_eth_phy_start(struct net_device *ndev) return 0; } +static int sh_eth_get_settings(struct net_device *ndev, + struct ethtool_cmd *ecmd) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + unsigned long flags; + int ret; + + spin_lock_irqsave(&mdp->lock, flags); + ret = phy_ethtool_gset(mdp->phydev, ecmd); + spin_unlock_irqrestore(&mdp->lock, flags); + + return ret; +} + +static int sh_eth_set_settings(struct net_device *ndev, + struct ethtool_cmd *ecmd) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + unsigned long flags; + int ret; + u32 ioaddr = ndev->base_addr; + + spin_lock_irqsave(&mdp->lock, flags); + + /* disable tx and rx */ + sh_eth_rcv_snd_disable(ioaddr); + + ret = phy_ethtool_sset(mdp->phydev, ecmd); + if (ret) + goto error_exit; + + if (ecmd->duplex == DUPLEX_FULL) + mdp->duplex = 1; + else + mdp->duplex = 0; + + if (mdp->cd->set_duplex) + mdp->cd->set_duplex(ndev); + +error_exit: + mdelay(1); + + /* enable tx and rx */ + sh_eth_rcv_snd_enable(ioaddr); + + spin_unlock_irqrestore(&mdp->lock, flags); + + return ret; +} + +static int sh_eth_nway_reset(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + unsigned long flags; + int ret; + + spin_lock_irqsave(&mdp->lock, flags); + ret = phy_start_aneg(mdp->phydev); + spin_unlock_irqrestore(&mdp->lock, flags); + + return ret; +} + +static u32 sh_eth_get_msglevel(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + return mdp->msg_enable; +} + +static void sh_eth_set_msglevel(struct net_device *ndev, u32 value) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + mdp->msg_enable = value; +} + +static const char sh_eth_gstrings_stats[][ETH_GSTRING_LEN] = { + "rx_current", "tx_current", + "rx_dirty", "tx_dirty", +}; +#define SH_ETH_STATS_LEN ARRAY_SIZE(sh_eth_gstrings_stats) + +static int sh_eth_get_sset_count(struct net_device *netdev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return SH_ETH_STATS_LEN; + default: + return -EOPNOTSUPP; + } +} + +static void sh_eth_get_ethtool_stats(struct net_device *ndev, + struct ethtool_stats *stats, u64 *data) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + int i = 0; + + /* device-specific stats */ + data[i++] = mdp->cur_rx; + data[i++] = mdp->cur_tx; + data[i++] = mdp->dirty_rx; + data[i++] = mdp->dirty_tx; +} + +static void sh_eth_get_strings(struct net_device *ndev, u32 stringset, u8 *data) +{ + switch (stringset) { + case ETH_SS_STATS: + memcpy(data, *sh_eth_gstrings_stats, + sizeof(sh_eth_gstrings_stats)); + break; + } +} + +static struct ethtool_ops sh_eth_ethtool_ops = { + .get_settings = sh_eth_get_settings, + .set_settings = sh_eth_set_settings, + .nway_reset = sh_eth_nway_reset, + .get_msglevel = sh_eth_get_msglevel, + .set_msglevel = sh_eth_set_msglevel, + .get_link = ethtool_op_get_link, + .get_strings = sh_eth_get_strings, + .get_ethtool_stats = sh_eth_get_ethtool_stats, + .get_sset_count = sh_eth_get_sset_count, +}; + /* network device open function */ static int sh_eth_open(struct net_device *ndev) { @@ -1073,8 +1238,8 @@ static int sh_eth_open(struct net_device *ndev) ret = request_irq(ndev->irq, sh_eth_interrupt, #if defined(CONFIG_CPU_SUBTYPE_SH7763) || \ - defined(CONFIG_CPU_SUBTYPE_SH7764) || \ - defined(CONFIG_CPU_SUBTYPE_SH7757) + defined(CONFIG_CPU_SUBTYPE_SH7764) || \ + defined(CONFIG_CPU_SUBTYPE_SH7757) IRQF_SHARED, #else 0, @@ -1123,8 +1288,8 @@ static void sh_eth_tx_timeout(struct net_device *ndev) netif_stop_queue(ndev); - /* worning message out. */ - printk(KERN_WARNING "%s: transmit timed out, status %8.8x," + if (netif_msg_timer(mdp)) + dev_err(&ndev->dev, "%s: transmit timed out, status %8.8x," " resetting...\n", ndev->name, (int)readl(ioaddr + EESR)); /* tx_errors count up */ @@ -1167,6 +1332,8 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) spin_lock_irqsave(&mdp->lock, flags); if ((mdp->cur_tx - mdp->dirty_tx) >= (TX_RING_SIZE - 4)) { if (!sh_eth_txfree(ndev)) { + if (netif_msg_tx_queued(mdp)) + dev_warn(&ndev->dev, "TxFD exhausted.\n"); netif_stop_queue(ndev); spin_unlock_irqrestore(&mdp->lock, flags); return NETDEV_TX_BUSY; @@ -1497,8 +1664,11 @@ static int sh_eth_drv_probe(struct platform_device *pdev) /* set function */ ndev->netdev_ops = &sh_eth_netdev_ops; + SET_ETHTOOL_OPS(ndev, &sh_eth_ethtool_ops); ndev->watchdog_timeo = TX_TIMEOUT; + /* debug message level */ + mdp->msg_enable = SH_ETH_DEF_MSG_ENABLE; mdp->post_rx = POST_RX >> (devno << 1); mdp->post_fw = POST_FW >> (devno << 1); diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 726df611ee17..43654a3bb0ec 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -81,6 +81,7 @@ static const char version[] = #include <linux/ethtool.h> #include <linux/mii.h> #include <linux/workqueue.h> +#include <linux/of.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -2394,6 +2395,15 @@ static int smc_drv_resume(struct device *dev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id smc91x_match[] = { + { .compatible = "smsc,lan91c94", }, + { .compatible = "smsc,lan91c111", }, + {}, +} +MODULE_DEVICE_TABLE(of, smc91x_match); +#endif + static struct dev_pm_ops smc_drv_pm_ops = { .suspend = smc_drv_suspend, .resume = smc_drv_resume, @@ -2406,6 +2416,9 @@ static struct platform_driver smc_driver = { .name = CARDNAME, .owner = THIS_MODULE, .pm = &smc_drv_pm_ops, +#ifdef CONFIG_OF + .of_match_table = smc91x_match, +#endif }, }; diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index 34a0af3837f9..0e5f03135b50 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -1560,8 +1560,10 @@ static int stmmac_mac_device_setup(struct net_device *dev) priv->hw = device; - if (device_can_wakeup(priv->device)) + if (device_can_wakeup(priv->device)) { priv->wolopts = WAKE_MAGIC; /* Magic Frame as default */ + enable_irq_wake(dev->irq); + } return 0; } diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 1c5408f83937..c1a344829b54 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -320,28 +320,28 @@ static int gem_txmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_s if (txmac_stat & MAC_TXSTAT_URUN) { netdev_err(dev, "TX MAC xmit underrun\n"); - gp->net_stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; } if (txmac_stat & MAC_TXSTAT_MPE) { netdev_err(dev, "TX MAC max packet size error\n"); - gp->net_stats.tx_errors++; + dev->stats.tx_errors++; } /* The rest are all cases of one of the 16-bit TX * counters expiring. */ if (txmac_stat & MAC_TXSTAT_NCE) - gp->net_stats.collisions += 0x10000; + dev->stats.collisions += 0x10000; if (txmac_stat & MAC_TXSTAT_ECE) { - gp->net_stats.tx_aborted_errors += 0x10000; - gp->net_stats.collisions += 0x10000; + dev->stats.tx_aborted_errors += 0x10000; + dev->stats.collisions += 0x10000; } if (txmac_stat & MAC_TXSTAT_LCE) { - gp->net_stats.tx_aborted_errors += 0x10000; - gp->net_stats.collisions += 0x10000; + dev->stats.tx_aborted_errors += 0x10000; + dev->stats.collisions += 0x10000; } /* We do not keep track of MAC_TXSTAT_FCE and @@ -469,20 +469,20 @@ static int gem_rxmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_s u32 smac = readl(gp->regs + MAC_SMACHINE); netdev_err(dev, "RX MAC fifo overflow smac[%08x]\n", smac); - gp->net_stats.rx_over_errors++; - gp->net_stats.rx_fifo_errors++; + dev->stats.rx_over_errors++; + dev->stats.rx_fifo_errors++; ret = gem_rxmac_reset(gp); } if (rxmac_stat & MAC_RXSTAT_ACE) - gp->net_stats.rx_frame_errors += 0x10000; + dev->stats.rx_frame_errors += 0x10000; if (rxmac_stat & MAC_RXSTAT_CCE) - gp->net_stats.rx_crc_errors += 0x10000; + dev->stats.rx_crc_errors += 0x10000; if (rxmac_stat & MAC_RXSTAT_LCE) - gp->net_stats.rx_length_errors += 0x10000; + dev->stats.rx_length_errors += 0x10000; /* We do not track MAC_RXSTAT_FCE and MAC_RXSTAT_VCE * events. @@ -594,7 +594,7 @@ static int gem_abnormal_irq(struct net_device *dev, struct gem *gp, u32 gem_stat if (netif_msg_rx_err(gp)) printk(KERN_DEBUG "%s: no buffer for rx frame\n", gp->dev->name); - gp->net_stats.rx_dropped++; + dev->stats.rx_dropped++; } if (gem_status & GREG_STAT_RXTAGERR) { @@ -602,7 +602,7 @@ static int gem_abnormal_irq(struct net_device *dev, struct gem *gp, u32 gem_stat if (netif_msg_rx_err(gp)) printk(KERN_DEBUG "%s: corrupt rx tag framing\n", gp->dev->name); - gp->net_stats.rx_errors++; + dev->stats.rx_errors++; goto do_reset; } @@ -684,7 +684,7 @@ static __inline__ void gem_tx(struct net_device *dev, struct gem *gp, u32 gem_st break; } gp->tx_skbs[entry] = NULL; - gp->net_stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) { txd = &gp->init_block->txd[entry]; @@ -696,7 +696,7 @@ static __inline__ void gem_tx(struct net_device *dev, struct gem *gp, u32 gem_st entry = NEXT_TX(entry); } - gp->net_stats.tx_packets++; + dev->stats.tx_packets++; dev_kfree_skb_irq(skb); } gp->tx_old = entry; @@ -738,6 +738,7 @@ static __inline__ void gem_post_rxds(struct gem *gp, int limit) static int gem_rx(struct gem *gp, int work_to_do) { + struct net_device *dev = gp->dev; int entry, drops, work_done = 0; u32 done; __sum16 csum; @@ -782,15 +783,15 @@ static int gem_rx(struct gem *gp, int work_to_do) len = (status & RXDCTRL_BUFSZ) >> 16; if ((len < ETH_ZLEN) || (status & RXDCTRL_BAD)) { - gp->net_stats.rx_errors++; + dev->stats.rx_errors++; if (len < ETH_ZLEN) - gp->net_stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (len & RXDCTRL_BAD) - gp->net_stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; /* We'll just return it to GEM. */ drop_it: - gp->net_stats.rx_dropped++; + dev->stats.rx_dropped++; goto next; } @@ -843,8 +844,8 @@ static int gem_rx(struct gem *gp, int work_to_do) netif_receive_skb(skb); - gp->net_stats.rx_packets++; - gp->net_stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; next: entry = NEXT_RX(entry); @@ -2472,7 +2473,6 @@ static int gem_resume(struct pci_dev *pdev) static struct net_device_stats *gem_get_stats(struct net_device *dev) { struct gem *gp = netdev_priv(dev); - struct net_device_stats *stats = &gp->net_stats; spin_lock_irq(&gp->lock); spin_lock(&gp->tx_lock); @@ -2481,17 +2481,17 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev) * so we shield against this */ if (gp->running) { - stats->rx_crc_errors += readl(gp->regs + MAC_FCSERR); + dev->stats.rx_crc_errors += readl(gp->regs + MAC_FCSERR); writel(0, gp->regs + MAC_FCSERR); - stats->rx_frame_errors += readl(gp->regs + MAC_AERR); + dev->stats.rx_frame_errors += readl(gp->regs + MAC_AERR); writel(0, gp->regs + MAC_AERR); - stats->rx_length_errors += readl(gp->regs + MAC_LERR); + dev->stats.rx_length_errors += readl(gp->regs + MAC_LERR); writel(0, gp->regs + MAC_LERR); - stats->tx_aborted_errors += readl(gp->regs + MAC_ECOLL); - stats->collisions += + dev->stats.tx_aborted_errors += readl(gp->regs + MAC_ECOLL); + dev->stats.collisions += (readl(gp->regs + MAC_ECOLL) + readl(gp->regs + MAC_LCOLL)); writel(0, gp->regs + MAC_ECOLL); @@ -2501,7 +2501,7 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev) spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); - return &gp->net_stats; + return &dev->stats; } static int gem_set_mac_address(struct net_device *dev, void *addr) diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h index 19905460def6..ede017872367 100644 --- a/drivers/net/sungem.h +++ b/drivers/net/sungem.h @@ -994,7 +994,6 @@ struct gem { u32 status; struct napi_struct napi; - struct net_device_stats net_stats; int tx_fifo_sz; int rx_fifo_sz; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 93b32d366611..6be418591df9 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4,7 +4,7 @@ * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com) * Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com) * Copyright (C) 2004 Sun Microsystems Inc. - * Copyright (C) 2005-2010 Broadcom Corporation. + * Copyright (C) 2005-2011 Broadcom Corporation. * * Firmware is: * Derived from proprietary unpublished source code, @@ -64,10 +64,10 @@ #define DRV_MODULE_NAME "tg3" #define TG3_MAJ_NUM 3 -#define TG3_MIN_NUM 116 +#define TG3_MIN_NUM 117 #define DRV_MODULE_VERSION \ __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM) -#define DRV_MODULE_RELDATE "December 3, 2010" +#define DRV_MODULE_RELDATE "January 25, 2011" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -1776,9 +1776,29 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up) tg3_phy_cl45_read(tp, MDIO_MMD_AN, TG3_CL45_D7_EEERES_STAT, &val); - if (val == TG3_CL45_D7_EEERES_STAT_LP_1000T || - val == TG3_CL45_D7_EEERES_STAT_LP_100TX) + switch (val) { + case TG3_CL45_D7_EEERES_STAT_LP_1000T: + switch (GET_ASIC_REV(tp->pci_chip_rev_id)) { + case ASIC_REV_5717: + case ASIC_REV_5719: + case ASIC_REV_57765: + /* Enable SM_DSP clock and tx 6dB coding. */ + val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL | + MII_TG3_AUXCTL_ACTL_SMDSP_ENA | + MII_TG3_AUXCTL_ACTL_TX_6DB; + tg3_writephy(tp, MII_TG3_AUX_CTRL, val); + + tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, 0x0000); + + /* Turn off SM_DSP clock. */ + val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL | + MII_TG3_AUXCTL_ACTL_TX_6DB; + tg3_writephy(tp, MII_TG3_AUX_CTRL, val); + } + /* Fallthrough */ + case TG3_CL45_D7_EEERES_STAT_LP_100TX: tp->setlpicnt = 2; + } } if (!tp->setlpicnt) { @@ -2968,11 +2988,19 @@ static void tg3_phy_copper_begin(struct tg3 *tp) MII_TG3_AUXCTL_ACTL_TX_6DB; tg3_writephy(tp, MII_TG3_AUX_CTRL, val); - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) && - !tg3_phydsp_read(tp, MII_TG3_DSP_CH34TP2, &val)) - tg3_phydsp_write(tp, MII_TG3_DSP_CH34TP2, - val | MII_TG3_DSP_CH34TP2_HIBW01); + switch (GET_ASIC_REV(tp->pci_chip_rev_id)) { + case ASIC_REV_5717: + case ASIC_REV_57765: + if (!tg3_phydsp_read(tp, MII_TG3_DSP_CH34TP2, &val)) + tg3_phydsp_write(tp, MII_TG3_DSP_CH34TP2, val | + MII_TG3_DSP_CH34TP2_HIBW01); + /* Fall through */ + case ASIC_REV_5719: + val = MII_TG3_DSP_TAP26_ALNOKO | + MII_TG3_DSP_TAP26_RMRXSTO | + MII_TG3_DSP_TAP26_OPCSINPT; + tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, val); + } val = 0; if (tp->link_config.autoneg == AUTONEG_ENABLE) { @@ -7801,7 +7829,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) TG3_CPMU_DBTMR1_LNKIDLE_2047US); tw32_f(TG3_CPMU_EEE_DBTMR2, - TG3_CPMU_DBTMR1_APE_TX_2047US | + TG3_CPMU_DBTMR2_APE_TX_2047US | TG3_CPMU_DBTMR2_TXIDXEQ_2047US); } @@ -8075,8 +8103,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) /* Program the jumbo buffer descriptor ring control * blocks on those devices that have them. */ - if ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) && - !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0 || + ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) && + !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))) { /* Setup replenish threshold. */ tw32(RCVBDI_JUMBO_THRESH, tp->rx_jumbo_pending / 8); @@ -8194,8 +8223,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) { val = tr32(TG3_RDMA_RSRVCTRL_REG); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) { - val &= ~TG3_RDMA_RSRVCTRL_TXMRGN_MASK; - val |= TG3_RDMA_RSRVCTRL_TXMRGN_320B; + val &= ~(TG3_RDMA_RSRVCTRL_TXMRGN_MASK | + TG3_RDMA_RSRVCTRL_FIFO_LWM_MASK | + TG3_RDMA_RSRVCTRL_FIFO_HWM_MASK); + val |= TG3_RDMA_RSRVCTRL_TXMRGN_320B | + TG3_RDMA_RSRVCTRL_FIFO_LWM_1_5K | + TG3_RDMA_RSRVCTRL_FIFO_HWM_1_5K; } tw32(TG3_RDMA_RSRVCTRL_REG, val | TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX); @@ -8317,7 +8350,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); udelay(100); - if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) { + if ((tp->tg3_flags2 & TG3_FLG2_USING_MSIX) && + tp->irq_cnt > 1) { val = tr32(MSGINT_MODE); val |= MSGINT_MODE_MULTIVEC_EN | MSGINT_MODE_ENABLE; tw32(MSGINT_MODE, val); @@ -9057,7 +9091,8 @@ static void tg3_ints_init(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_USING_MSI_OR_MSIX) { u32 msi_mode = tr32(MSGINT_MODE); - if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) + if ((tp->tg3_flags2 & TG3_FLG2_USING_MSIX) && + tp->irq_cnt > 1) msi_mode |= MSGINT_MODE_MULTIVEC_EN; tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE); } @@ -10833,13 +10868,16 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) if (loopback_mode == TG3_MAC_LOOPBACK) { /* HW errata - mac loopback fails in some cases on 5780. * Normal traffic and PHY loopback are not affected by - * errata. + * errata. Also, the MAC loopback test is deprecated for + * all newer ASIC revisions. */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 || + (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT)) return 0; - mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) | - MAC_MODE_PORT_INT_LPBACK; + mac_mode = tp->mac_mode & + ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX); + mac_mode |= MAC_MODE_PORT_INT_LPBACK; if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) mac_mode |= MAC_MODE_LINK_POLARITY; if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY) @@ -10861,7 +10899,8 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) tg3_writephy(tp, MII_BMCR, val); udelay(40); - mac_mode = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK; + mac_mode = tp->mac_mode & + ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX); if (tp->phy_flags & TG3_PHYFLG_IS_FET) { tg3_writephy(tp, MII_TG3_FET_PTEST, MII_TG3_FET_PTEST_FRC_TX_LINK | @@ -10889,6 +10928,13 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) MII_TG3_EXT_CTRL_LNK3_LED_MODE); } tw32(MAC_MODE, mac_mode); + + /* Wait for link */ + for (i = 0; i < 100; i++) { + if (tr32(MAC_TX_STATUS) & TX_STATUS_LINK_UP) + break; + mdelay(1); + } } else { return -EINVAL; } @@ -10995,14 +11041,19 @@ out: static int tg3_test_loopback(struct tg3 *tp) { int err = 0; - u32 cpmuctrl = 0; + u32 eee_cap, cpmuctrl = 0; if (!netif_running(tp->dev)) return TG3_LOOPBACK_FAILED; + eee_cap = tp->phy_flags & TG3_PHYFLG_EEE_CAP; + tp->phy_flags &= ~TG3_PHYFLG_EEE_CAP; + err = tg3_reset_hw(tp, 1); - if (err) - return TG3_LOOPBACK_FAILED; + if (err) { + err = TG3_LOOPBACK_FAILED; + goto done; + } /* Turn off gphy autopowerdown. */ if (tp->phy_flags & TG3_PHYFLG_ENABLE_APD) @@ -11022,8 +11073,10 @@ static int tg3_test_loopback(struct tg3 *tp) udelay(10); } - if (status != CPMU_MUTEX_GNT_DRIVER) - return TG3_LOOPBACK_FAILED; + if (status != CPMU_MUTEX_GNT_DRIVER) { + err = TG3_LOOPBACK_FAILED; + goto done; + } /* Turn off link-based power management. */ cpmuctrl = tr32(TG3_CPMU_CTRL); @@ -11052,6 +11105,9 @@ static int tg3_test_loopback(struct tg3 *tp) if (tp->phy_flags & TG3_PHYFLG_ENABLE_APD) tg3_phy_toggle_apd(tp, true); +done: + tp->phy_flags |= eee_cap; + return err; } @@ -11158,7 +11214,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) break; /* We have no PHY */ - if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) + if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) || + ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) && + !netif_running(dev))) return -EAGAIN; spin_lock_bh(&tp->lock); @@ -11174,7 +11232,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) break; /* We have no PHY */ - if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) + if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) || + ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) && + !netif_running(dev))) return -EAGAIN; spin_lock_bh(&tp->lock); @@ -12403,9 +12463,11 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_TX_EN; } done: - device_init_wakeup(&tp->pdev->dev, tp->tg3_flags & TG3_FLAG_WOL_CAP); - device_set_wakeup_enable(&tp->pdev->dev, + if (tp->tg3_flags & TG3_FLAG_WOL_CAP) + device_set_wakeup_enable(&tp->pdev->dev, tp->tg3_flags & TG3_FLAG_WOL_ENABLE); + else + device_set_wakeup_capable(&tp->pdev->dev, false); } static int __devinit tg3_issue_otp_command(struct tg3 *tp, u32 cmd) @@ -13258,7 +13320,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } /* Determine TSO capabilities */ - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + ; /* Do nothing. HW bug. */ + else if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) tp->tg3_flags2 |= TG3_FLG2_HW_TSO_3; else if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) @@ -13309,7 +13373,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags3 |= TG3_FLG3_40BIT_DMA_LIMIT_BUG; } - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) + if ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719) tp->tg3_flags3 |= TG3_FLG3_USE_JUMBO_BDFLAG; if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || @@ -13327,42 +13392,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS; tp->pcie_readrq = 4096; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) { - u16 word; - - pci_read_config_word(tp->pdev, - tp->pcie_cap + PCI_EXP_LNKSTA, - &word); - switch (word & PCI_EXP_LNKSTA_CLS) { - case PCI_EXP_LNKSTA_CLS_2_5GB: - word &= PCI_EXP_LNKSTA_NLW; - word >>= PCI_EXP_LNKSTA_NLW_SHIFT; - switch (word) { - case 2: - tp->pcie_readrq = 2048; - break; - case 4: - tp->pcie_readrq = 1024; - break; - } - break; - - case PCI_EXP_LNKSTA_CLS_5_0GB: - word &= PCI_EXP_LNKSTA_NLW; - word >>= PCI_EXP_LNKSTA_NLW_SHIFT; - switch (word) { - case 1: - tp->pcie_readrq = 2048; - break; - case 2: - tp->pcie_readrq = 1024; - break; - case 4: - tp->pcie_readrq = 512; - break; - } - } - } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + tp->pcie_readrq = 2048; pcie_set_readrq(tp->pdev, tp->pcie_readrq); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index f528243e1a4f..73884b69b749 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -4,7 +4,7 @@ * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com) * Copyright (C) 2001 Jeff Garzik (jgarzik@pobox.com) * Copyright (C) 2004 Sun Microsystems Inc. - * Copyright (C) 2007-2010 Broadcom Corporation. + * Copyright (C) 2007-2011 Broadcom Corporation. */ #ifndef _T3_H @@ -141,6 +141,7 @@ #define CHIPREV_ID_57780_A1 0x57780001 #define CHIPREV_ID_5717_A0 0x05717000 #define CHIPREV_ID_57765_A0 0x57785000 +#define CHIPREV_ID_5719_A0 0x05719000 #define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) #define ASIC_REV_5700 0x07 #define ASIC_REV_5701 0x00 @@ -1105,7 +1106,7 @@ #define TG3_CPMU_DBTMR1_PCIEXIT_2047US 0x07ff0000 #define TG3_CPMU_DBTMR1_LNKIDLE_2047US 0x000070ff #define TG3_CPMU_EEE_DBTMR2 0x000036b8 -#define TG3_CPMU_DBTMR1_APE_TX_2047US 0x07ff0000 +#define TG3_CPMU_DBTMR2_APE_TX_2047US 0x07ff0000 #define TG3_CPMU_DBTMR2_TXIDXEQ_2047US 0x000070ff #define TG3_CPMU_EEE_LNKIDL_CTRL 0x000036bc #define TG3_CPMU_EEE_LNKIDL_PCIE_NL0 0x01000000 @@ -1333,6 +1334,10 @@ #define TG3_RDMA_RSRVCTRL_REG 0x00004900 #define TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX 0x00000004 +#define TG3_RDMA_RSRVCTRL_FIFO_LWM_1_5K 0x00000c00 +#define TG3_RDMA_RSRVCTRL_FIFO_LWM_MASK 0x00000ff0 +#define TG3_RDMA_RSRVCTRL_FIFO_HWM_1_5K 0x000c0000 +#define TG3_RDMA_RSRVCTRL_FIFO_HWM_MASK 0x000ff000 #define TG3_RDMA_RSRVCTRL_TXMRGN_320B 0x28000000 #define TG3_RDMA_RSRVCTRL_TXMRGN_MASK 0xffe00000 /* 0x4904 --> 0x4910 unused */ @@ -2108,6 +2113,10 @@ #define MII_TG3_DSP_TAP1 0x0001 #define MII_TG3_DSP_TAP1_AGCTGT_DFLT 0x0007 +#define MII_TG3_DSP_TAP26 0x001a +#define MII_TG3_DSP_TAP26_ALNOKO 0x0001 +#define MII_TG3_DSP_TAP26_RMRXSTO 0x0002 +#define MII_TG3_DSP_TAP26_OPCSINPT 0x0004 #define MII_TG3_DSP_AADJ1CH0 0x001f #define MII_TG3_DSP_CH34TP2 0x4022 #define MII_TG3_DSP_CH34TP2_HIBW01 0x0010 diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index f8e463cd8ecc..e48a80885343 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -63,45 +63,45 @@ * - Other minor stuff * * v1.4 Feb 10, 2000 - Updated with more changes required after Dave's - * network cleanup in 2.3.43pre7 (Tigran & myself) - * - Minor stuff. + * network cleanup in 2.3.43pre7 (Tigran & myself) + * - Minor stuff. * - * v1.5 March 22, 2000 - Fixed another timer bug that would hang the driver - * if no cable/link were present. + * v1.5 March 22, 2000 - Fixed another timer bug that would hang the + * driver if no cable/link were present. * - Cosmetic changes. * - TODO: Port completely to new PCI/DMA API - * Auto-Neg fallback. - * - * v1.6 April 04, 2000 - Fixed driver support for kernel-parameters. Haven't - * tested it though, as the kernel support is currently - * broken (2.3.99p4p3). - * - Updated tlan.txt accordingly. - * - Adjusted minimum/maximum frame length. - * - There is now a TLAN website up at - * http://hp.sourceforge.net/ - * - * v1.7 April 07, 2000 - Started to implement custom ioctls. Driver now - * reports PHY information when used with Donald - * Beckers userspace MII diagnostics utility. - * - * v1.8 April 23, 2000 - Fixed support for forced speed/duplex settings. - * - Added link information to Auto-Neg and forced - * modes. When NIC operates with auto-neg the driver - * will report Link speed & duplex modes as well as - * link partner abilities. When forced link is used, - * the driver will report status of the established - * link. - * Please read tlan.txt for additional information. - * - Removed call to check_region(), and used - * return value of request_region() instead. + * Auto-Neg fallback. + * + * v1.6 April 04, 2000 - Fixed driver support for kernel-parameters. + * Haven't tested it though, as the kernel support + * is currently broken (2.3.99p4p3). + * - Updated tlan.txt accordingly. + * - Adjusted minimum/maximum frame length. + * - There is now a TLAN website up at + * http://hp.sourceforge.net/ + * + * v1.7 April 07, 2000 - Started to implement custom ioctls. Driver now + * reports PHY information when used with Donald + * Beckers userspace MII diagnostics utility. + * + * v1.8 April 23, 2000 - Fixed support for forced speed/duplex settings. + * - Added link information to Auto-Neg and forced + * modes. When NIC operates with auto-neg the driver + * will report Link speed & duplex modes as well as + * link partner abilities. When forced link is used, + * the driver will report status of the established + * link. + * Please read tlan.txt for additional information. + * - Removed call to check_region(), and used + * return value of request_region() instead. * * v1.8a May 28, 2000 - Minor updates. * * v1.9 July 25, 2000 - Fixed a few remaining Full-Duplex issues. - * - Updated with timer fixes from Andrew Morton. - * - Fixed module race in TLan_Open. - * - Added routine to monitor PHY status. - * - Added activity led support for Proliant devices. + * - Updated with timer fixes from Andrew Morton. + * - Fixed module race in TLan_Open. + * - Added routine to monitor PHY status. + * - Added activity led support for Proliant devices. * * v1.10 Aug 30, 2000 - Added support for EISA based tlan controllers * like the Compaq NetFlex3/E. @@ -111,8 +111,8 @@ * hardware probe is done with kernel API and * TLan_EisaProbe. * - Adjusted debug information for probing. - * - Fixed bug that would cause general debug information - * to be printed after driver removal. + * - Fixed bug that would cause general debug + * information to be printed after driver removal. * - Added transmit timeout handling. * - Fixed OOM return values in tlan_probe. * - Fixed possible mem leak in tlan_exit @@ -136,8 +136,8 @@ * * v1.12 Oct 12, 2000 - Minor fixes (memleak, init, etc.) * - * v1.13 Nov 28, 2000 - Stop flooding console with auto-neg issues - * when link can't be established. + * v1.13 Nov 28, 2000 - Stop flooding console with auto-neg issues + * when link can't be established. * - Added the bbuf option as a kernel parameter. * - Fixed ioaddr probe bug. * - Fixed stupid deadlock with MII interrupts. @@ -147,28 +147,30 @@ * TLAN v1.0 silicon. This needs to be investigated * further. * - * v1.14 Dec 16, 2000 - Added support for servicing multiple frames per. - * interrupt. Thanks goes to - * Adam Keys <adam@ti.com> - * Denis Beaudoin <dbeaudoin@ti.com> - * for providing the patch. - * - Fixed auto-neg output when using multiple - * adapters. - * - Converted to use new taskq interface. + * v1.14 Dec 16, 2000 - Added support for servicing multiple frames per. + * interrupt. Thanks goes to + * Adam Keys <adam@ti.com> + * Denis Beaudoin <dbeaudoin@ti.com> + * for providing the patch. + * - Fixed auto-neg output when using multiple + * adapters. + * - Converted to use new taskq interface. * - * v1.14a Jan 6, 2001 - Minor adjustments (spinlocks, etc.) + * v1.14a Jan 6, 2001 - Minor adjustments (spinlocks, etc.) * * Samuel Chessman <chessman@tux.org> New Maintainer! * * v1.15 Apr 4, 2002 - Correct operation when aui=1 to be - * 10T half duplex no loopback - * Thanks to Gunnar Eikman + * 10T half duplex no loopback + * Thanks to Gunnar Eikman * * Sakari Ailus <sakari.ailus@iki.fi>: * * v1.15a Dec 15 2008 - Remove bbuf support, it doesn't work anyway. + * v1.16 Jan 6 2011 - Make checkpatch.pl happy. + * v1.17 Jan 6 2011 - Add suspend/resume support. * - *******************************************************************************/ + ******************************************************************************/ #include <linux/module.h> #include <linux/init.h> @@ -185,13 +187,11 @@ #include "tlan.h" -typedef u32 (TLanIntVectorFunc)( struct net_device *, u16 ); - /* For removing EISA devices */ -static struct net_device *TLan_Eisa_Devices; +static struct net_device *tlan_eisa_devices; -static int TLanDevicesInstalled; +static int tlan_devices_installed; /* Set speed, duplex and aui settings */ static int aui[MAX_TLAN_BOARDS]; @@ -202,7 +202,8 @@ module_param_array(aui, int, NULL, 0); module_param_array(duplex, int, NULL, 0); module_param_array(speed, int, NULL, 0); MODULE_PARM_DESC(aui, "ThunderLAN use AUI port(s) (0-1)"); -MODULE_PARM_DESC(duplex, "ThunderLAN duplex setting(s) (0-default, 1-half, 2-full)"); +MODULE_PARM_DESC(duplex, + "ThunderLAN duplex setting(s) (0-default, 1-half, 2-full)"); MODULE_PARM_DESC(speed, "ThunderLAN port speen setting(s) (0,10,100)"); MODULE_AUTHOR("Maintainer: Samuel Chessman <chessman@tux.org>"); @@ -218,139 +219,144 @@ static int debug; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "ThunderLAN debug mask"); -static const char TLanSignature[] = "TLAN"; -static const char tlan_banner[] = "ThunderLAN driver v1.15a\n"; +static const char tlan_signature[] = "TLAN"; +static const char tlan_banner[] = "ThunderLAN driver v1.17\n"; static int tlan_have_pci; static int tlan_have_eisa; -static const char *media[] = { - "10BaseT-HD ", "10BaseT-FD ","100baseTx-HD ", - "100baseTx-FD", "100baseT4", NULL +static const char * const media[] = { + "10BaseT-HD", "10BaseT-FD", "100baseTx-HD", + "100BaseTx-FD", "100BaseT4", NULL }; static struct board { - const char *deviceLabel; - u32 flags; - u16 addrOfs; + const char *device_label; + u32 flags; + u16 addr_ofs; } board_info[] = { { "Compaq Netelligent 10 T PCI UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, - { "Compaq Netelligent 10/100 TX PCI UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, + { "Compaq Netelligent 10/100 TX PCI UTP", + TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, { "Compaq Integrated NetFlex-3/P", TLAN_ADAPTER_NONE, 0x83 }, { "Compaq NetFlex-3/P", TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 }, { "Compaq NetFlex-3/P", TLAN_ADAPTER_NONE, 0x83 }, { "Compaq Netelligent Integrated 10/100 TX UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, - { "Compaq Netelligent Dual 10/100 TX PCI UTP", TLAN_ADAPTER_NONE, 0x83 }, - { "Compaq Netelligent 10/100 TX Embedded UTP", TLAN_ADAPTER_NONE, 0x83 }, + { "Compaq Netelligent Dual 10/100 TX PCI UTP", + TLAN_ADAPTER_NONE, 0x83 }, + { "Compaq Netelligent 10/100 TX Embedded UTP", + TLAN_ADAPTER_NONE, 0x83 }, { "Olicom OC-2183/2185", TLAN_ADAPTER_USE_INTERN_10, 0x83 }, - { "Olicom OC-2325", TLAN_ADAPTER_UNMANAGED_PHY, 0xF8 }, - { "Olicom OC-2326", TLAN_ADAPTER_USE_INTERN_10, 0xF8 }, + { "Olicom OC-2325", TLAN_ADAPTER_UNMANAGED_PHY, 0xf8 }, + { "Olicom OC-2326", TLAN_ADAPTER_USE_INTERN_10, 0xf8 }, { "Compaq Netelligent 10/100 TX UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, - { "Compaq Netelligent 10 T/2 PCI UTP/Coax", TLAN_ADAPTER_NONE, 0x83 }, + { "Compaq Netelligent 10 T/2 PCI UTP/coax", TLAN_ADAPTER_NONE, 0x83 }, { "Compaq NetFlex-3/E", - TLAN_ADAPTER_ACTIVITY_LED | /* EISA card */ + TLAN_ADAPTER_ACTIVITY_LED | /* EISA card */ TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 }, - { "Compaq NetFlex-3/E", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, /* EISA card */ + { "Compaq NetFlex-3/E", + TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, /* EISA card */ }; static DEFINE_PCI_DEVICE_TABLE(tlan_pci_tbl) = { { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL10, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL100, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETFLEX3I, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_THUNDER, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 }, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETFLEX3B, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL100PI, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL100D, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 }, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL100I, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 }, { PCI_VENDOR_ID_OLICOM, PCI_DEVICE_ID_OLICOM_OC2183, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, { PCI_VENDOR_ID_OLICOM, PCI_DEVICE_ID_OLICOM_OC2325, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 }, { PCI_VENDOR_ID_OLICOM, PCI_DEVICE_ID_OLICOM_OC2326, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 }, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100_WS_5100, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 }, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_T2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 }, { 0,} }; MODULE_DEVICE_TABLE(pci, tlan_pci_tbl); -static void TLan_EisaProbe( void ); -static void TLan_Eisa_Cleanup( void ); -static int TLan_Init( struct net_device * ); -static int TLan_Open( struct net_device *dev ); -static netdev_tx_t TLan_StartTx( struct sk_buff *, struct net_device *); -static irqreturn_t TLan_HandleInterrupt( int, void *); -static int TLan_Close( struct net_device *); -static struct net_device_stats *TLan_GetStats( struct net_device *); -static void TLan_SetMulticastList( struct net_device *); -static int TLan_ioctl( struct net_device *dev, struct ifreq *rq, int cmd); -static int TLan_probe1( struct pci_dev *pdev, long ioaddr, - int irq, int rev, const struct pci_device_id *ent); -static void TLan_tx_timeout( struct net_device *dev); -static void TLan_tx_timeout_work(struct work_struct *work); -static int tlan_init_one( struct pci_dev *pdev, const struct pci_device_id *ent); - -static u32 TLan_HandleTxEOF( struct net_device *, u16 ); -static u32 TLan_HandleStatOverflow( struct net_device *, u16 ); -static u32 TLan_HandleRxEOF( struct net_device *, u16 ); -static u32 TLan_HandleDummy( struct net_device *, u16 ); -static u32 TLan_HandleTxEOC( struct net_device *, u16 ); -static u32 TLan_HandleStatusCheck( struct net_device *, u16 ); -static u32 TLan_HandleRxEOC( struct net_device *, u16 ); - -static void TLan_Timer( unsigned long ); - -static void TLan_ResetLists( struct net_device * ); -static void TLan_FreeLists( struct net_device * ); -static void TLan_PrintDio( u16 ); -static void TLan_PrintList( TLanList *, char *, int ); -static void TLan_ReadAndClearStats( struct net_device *, int ); -static void TLan_ResetAdapter( struct net_device * ); -static void TLan_FinishReset( struct net_device * ); -static void TLan_SetMac( struct net_device *, int areg, char *mac ); - -static void TLan_PhyPrint( struct net_device * ); -static void TLan_PhyDetect( struct net_device * ); -static void TLan_PhyPowerDown( struct net_device * ); -static void TLan_PhyPowerUp( struct net_device * ); -static void TLan_PhyReset( struct net_device * ); -static void TLan_PhyStartLink( struct net_device * ); -static void TLan_PhyFinishAutoNeg( struct net_device * ); +static void tlan_eisa_probe(void); +static void tlan_eisa_cleanup(void); +static int tlan_init(struct net_device *); +static int tlan_open(struct net_device *dev); +static netdev_tx_t tlan_start_tx(struct sk_buff *, struct net_device *); +static irqreturn_t tlan_handle_interrupt(int, void *); +static int tlan_close(struct net_device *); +static struct net_device_stats *tlan_get_stats(struct net_device *); +static void tlan_set_multicast_list(struct net_device *); +static int tlan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int tlan_probe1(struct pci_dev *pdev, long ioaddr, + int irq, int rev, const struct pci_device_id *ent); +static void tlan_tx_timeout(struct net_device *dev); +static void tlan_tx_timeout_work(struct work_struct *work); +static int tlan_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent); + +static u32 tlan_handle_tx_eof(struct net_device *, u16); +static u32 tlan_handle_stat_overflow(struct net_device *, u16); +static u32 tlan_handle_rx_eof(struct net_device *, u16); +static u32 tlan_handle_dummy(struct net_device *, u16); +static u32 tlan_handle_tx_eoc(struct net_device *, u16); +static u32 tlan_handle_status_check(struct net_device *, u16); +static u32 tlan_handle_rx_eoc(struct net_device *, u16); + +static void tlan_timer(unsigned long); + +static void tlan_reset_lists(struct net_device *); +static void tlan_free_lists(struct net_device *); +static void tlan_print_dio(u16); +static void tlan_print_list(struct tlan_list *, char *, int); +static void tlan_read_and_clear_stats(struct net_device *, int); +static void tlan_reset_adapter(struct net_device *); +static void tlan_finish_reset(struct net_device *); +static void tlan_set_mac(struct net_device *, int areg, char *mac); + +static void tlan_phy_print(struct net_device *); +static void tlan_phy_detect(struct net_device *); +static void tlan_phy_power_down(struct net_device *); +static void tlan_phy_power_up(struct net_device *); +static void tlan_phy_reset(struct net_device *); +static void tlan_phy_start_link(struct net_device *); +static void tlan_phy_finish_auto_neg(struct net_device *); #ifdef MONITOR -static void TLan_PhyMonitor( struct net_device * ); +static void tlan_phy_monitor(struct net_device *); #endif /* -static int TLan_PhyNop( struct net_device * ); -static int TLan_PhyInternalCheck( struct net_device * ); -static int TLan_PhyInternalService( struct net_device * ); -static int TLan_PhyDp83840aCheck( struct net_device * ); + static int tlan_phy_nop(struct net_device *); + static int tlan_phy_internal_check(struct net_device *); + static int tlan_phy_internal_service(struct net_device *); + static int tlan_phy_dp83840a_check(struct net_device *); */ -static bool TLan_MiiReadReg( struct net_device *, u16, u16, u16 * ); -static void TLan_MiiSendData( u16, u32, unsigned ); -static void TLan_MiiSync( u16 ); -static void TLan_MiiWriteReg( struct net_device *, u16, u16, u16 ); +static bool tlan_mii_read_reg(struct net_device *, u16, u16, u16 *); +static void tlan_mii_send_data(u16, u32, unsigned); +static void tlan_mii_sync(u16); +static void tlan_mii_write_reg(struct net_device *, u16, u16, u16); -static void TLan_EeSendStart( u16 ); -static int TLan_EeSendByte( u16, u8, int ); -static void TLan_EeReceiveByte( u16, u8 *, int ); -static int TLan_EeReadByte( struct net_device *, u8, u8 * ); +static void tlan_ee_send_start(u16); +static int tlan_ee_send_byte(u16, u8, int); +static void tlan_ee_receive_byte(u16, u8 *, int); +static int tlan_ee_read_byte(struct net_device *, u8, u8 *); static inline void -TLan_StoreSKB( struct tlan_list_tag *tag, struct sk_buff *skb) +tlan_store_skb(struct tlan_list *tag, struct sk_buff *skb) { unsigned long addr = (unsigned long)skb; tag->buffer[9].address = addr; @@ -358,7 +364,7 @@ TLan_StoreSKB( struct tlan_list_tag *tag, struct sk_buff *skb) } static inline struct sk_buff * -TLan_GetSKB( const struct tlan_list_tag *tag) +tlan_get_skb(const struct tlan_list *tag) { unsigned long addr; @@ -367,50 +373,50 @@ TLan_GetSKB( const struct tlan_list_tag *tag) return (struct sk_buff *) addr; } - -static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = { +static u32 +(*tlan_int_vector[TLAN_INT_NUMBER_OF_INTS])(struct net_device *, u16) = { NULL, - TLan_HandleTxEOF, - TLan_HandleStatOverflow, - TLan_HandleRxEOF, - TLan_HandleDummy, - TLan_HandleTxEOC, - TLan_HandleStatusCheck, - TLan_HandleRxEOC + tlan_handle_tx_eof, + tlan_handle_stat_overflow, + tlan_handle_rx_eof, + tlan_handle_dummy, + tlan_handle_tx_eoc, + tlan_handle_status_check, + tlan_handle_rx_eoc }; static inline void -TLan_SetTimer( struct net_device *dev, u32 ticks, u32 type ) +tlan_set_timer(struct net_device *dev, u32 ticks, u32 type) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); unsigned long flags = 0; if (!in_irq()) spin_lock_irqsave(&priv->lock, flags); - if ( priv->timer.function != NULL && - priv->timerType != TLAN_TIMER_ACTIVITY ) { + if (priv->timer.function != NULL && + priv->timer_type != TLAN_TIMER_ACTIVITY) { if (!in_irq()) spin_unlock_irqrestore(&priv->lock, flags); return; } - priv->timer.function = TLan_Timer; + priv->timer.function = tlan_timer; if (!in_irq()) spin_unlock_irqrestore(&priv->lock, flags); priv->timer.data = (unsigned long) dev; - priv->timerSetAt = jiffies; - priv->timerType = type; + priv->timer_set_at = jiffies; + priv->timer_type = type; mod_timer(&priv->timer, jiffies + ticks); -} /* TLan_SetTimer */ +} /***************************************************************************** ****************************************************************************** - ThunderLAN Driver Primary Functions +ThunderLAN driver primary functions - These functions are more or less common to all Linux network drivers. +these functions are more or less common to all linux network drivers. ****************************************************************************** *****************************************************************************/ @@ -419,49 +425,117 @@ TLan_SetTimer( struct net_device *dev, u32 ticks, u32 type ) - /*************************************************************** - * tlan_remove_one - * - * Returns: - * Nothing - * Parms: - * None - * - * Goes through the TLanDevices list and frees the device - * structs and memory associated with each device (lists - * and buffers). It also ureserves the IO port regions - * associated with this device. - * - **************************************************************/ +/*************************************************************** + * tlan_remove_one + * + * Returns: + * Nothing + * Parms: + * None + * + * Goes through the TLanDevices list and frees the device + * structs and memory associated with each device (lists + * and buffers). It also ureserves the IO port regions + * associated with this device. + * + **************************************************************/ -static void __devexit tlan_remove_one( struct pci_dev *pdev) +static void __devexit tlan_remove_one(struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata( pdev ); - TLanPrivateInfo *priv = netdev_priv(dev); + struct net_device *dev = pci_get_drvdata(pdev); + struct tlan_priv *priv = netdev_priv(dev); - unregister_netdev( dev ); + unregister_netdev(dev); - if ( priv->dmaStorage ) { - pci_free_consistent(priv->pciDev, - priv->dmaSize, priv->dmaStorage, - priv->dmaStorageDMA ); + if (priv->dma_storage) { + pci_free_consistent(priv->pci_dev, + priv->dma_size, priv->dma_storage, + priv->dma_storage_dma); } #ifdef CONFIG_PCI pci_release_regions(pdev); #endif - free_netdev( dev ); + free_netdev(dev); + + pci_set_drvdata(pdev, NULL); +} + +static void tlan_start(struct net_device *dev) +{ + tlan_reset_lists(dev); + /* NOTE: It might not be necessary to read the stats before a + reset if you don't care what the values are. + */ + tlan_read_and_clear_stats(dev, TLAN_IGNORE); + tlan_reset_adapter(dev); + netif_wake_queue(dev); +} + +static void tlan_stop(struct net_device *dev) +{ + struct tlan_priv *priv = netdev_priv(dev); + + tlan_read_and_clear_stats(dev, TLAN_RECORD); + outl(TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD); + /* Reset and power down phy */ + tlan_reset_adapter(dev); + if (priv->timer.function != NULL) { + del_timer_sync(&priv->timer); + priv->timer.function = NULL; + } +} + +#ifdef CONFIG_PM + +static int tlan_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (netif_running(dev)) + tlan_stop(dev); + + netif_device_detach(dev); + pci_save_state(pdev); + pci_disable_device(pdev); + pci_wake_from_d3(pdev, false); + pci_set_power_state(pdev, PCI_D3hot); - pci_set_drvdata( pdev, NULL ); + return 0; } +static int tlan_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + pci_enable_wake(pdev, 0, 0); + netif_device_attach(dev); + + if (netif_running(dev)) + tlan_start(dev); + + return 0; +} + +#else /* CONFIG_PM */ + +#define tlan_suspend NULL +#define tlan_resume NULL + +#endif /* CONFIG_PM */ + + static struct pci_driver tlan_driver = { .name = "tlan", .id_table = tlan_pci_tbl, .probe = tlan_init_one, .remove = __devexit_p(tlan_remove_one), + .suspend = tlan_suspend, + .resume = tlan_resume, }; static int __init tlan_probe(void) @@ -482,13 +556,13 @@ static int __init tlan_probe(void) } TLAN_DBG(TLAN_DEBUG_PROBE, "Starting EISA Probe....\n"); - TLan_EisaProbe(); + tlan_eisa_probe(); printk(KERN_INFO "TLAN: %d device%s installed, PCI: %d EISA: %d\n", - TLanDevicesInstalled, TLanDevicesInstalled == 1 ? "" : "s", - tlan_have_pci, tlan_have_eisa); + tlan_devices_installed, tlan_devices_installed == 1 ? "" : "s", + tlan_have_pci, tlan_have_eisa); - if (TLanDevicesInstalled == 0) { + if (tlan_devices_installed == 0) { rc = -ENODEV; goto err_out_pci_unreg; } @@ -501,39 +575,39 @@ err_out_pci_free: } -static int __devinit tlan_init_one( struct pci_dev *pdev, - const struct pci_device_id *ent) +static int __devinit tlan_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) { - return TLan_probe1( pdev, -1, -1, 0, ent); + return tlan_probe1(pdev, -1, -1, 0, ent); } /* - *************************************************************** - * tlan_probe1 - * - * Returns: - * 0 on success, error code on error - * Parms: - * none - * - * The name is lower case to fit in with all the rest of - * the netcard_probe names. This function looks for - * another TLan based adapter, setting it up with the - * allocated device struct if one is found. - * tlan_probe has been ported to the new net API and - * now allocates its own device structure. This function - * is also used by modules. - * - **************************************************************/ - -static int __devinit TLan_probe1(struct pci_dev *pdev, +*************************************************************** +* tlan_probe1 +* +* Returns: +* 0 on success, error code on error +* Parms: +* none +* +* The name is lower case to fit in with all the rest of +* the netcard_probe names. This function looks for +* another TLan based adapter, setting it up with the +* allocated device struct if one is found. +* tlan_probe has been ported to the new net API and +* now allocates its own device structure. This function +* is also used by modules. +* +**************************************************************/ + +static int __devinit tlan_probe1(struct pci_dev *pdev, long ioaddr, int irq, int rev, - const struct pci_device_id *ent ) + const struct pci_device_id *ent) { struct net_device *dev; - TLanPrivateInfo *priv; + struct tlan_priv *priv; u16 device_id; int reg, rc = -ENODEV; @@ -543,7 +617,7 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, if (rc) return rc; - rc = pci_request_regions(pdev, TLanSignature); + rc = pci_request_regions(pdev, tlan_signature); if (rc) { printk(KERN_ERR "TLAN: Could not reserve IO regions\n"); goto err_out; @@ -551,7 +625,7 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, } #endif /* CONFIG_PCI */ - dev = alloc_etherdev(sizeof(TLanPrivateInfo)); + dev = alloc_etherdev(sizeof(struct tlan_priv)); if (dev == NULL) { printk(KERN_ERR "TLAN: Could not allocate memory for device.\n"); rc = -ENOMEM; @@ -561,26 +635,28 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, priv = netdev_priv(dev); - priv->pciDev = pdev; + priv->pci_dev = pdev; priv->dev = dev; /* Is this a PCI device? */ if (pdev) { - u32 pci_io_base = 0; + u32 pci_io_base = 0; priv->adapter = &board_info[ent->driver_data]; rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - printk(KERN_ERR "TLAN: No suitable PCI mapping available.\n"); + printk(KERN_ERR + "TLAN: No suitable PCI mapping available.\n"); goto err_out_free_dev; } - for ( reg= 0; reg <= 5; reg ++ ) { + for (reg = 0; reg <= 5; reg++) { if (pci_resource_flags(pdev, reg) & IORESOURCE_IO) { pci_io_base = pci_resource_start(pdev, reg); - TLAN_DBG( TLAN_DEBUG_GNRL, "IO mapping is available at %x.\n", - pci_io_base); + TLAN_DBG(TLAN_DEBUG_GNRL, + "IO mapping is available at %x.\n", + pci_io_base); break; } } @@ -592,7 +668,7 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, dev->base_addr = pci_io_base; dev->irq = pdev->irq; - priv->adapterRev = pdev->revision; + priv->adapter_rev = pdev->revision; pci_set_master(pdev); pci_set_drvdata(pdev, dev); @@ -602,11 +678,11 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, device_id = inw(ioaddr + EISA_ID2); priv->is_eisa = 1; if (device_id == 0x20F1) { - priv->adapter = &board_info[13]; /* NetFlex-3/E */ - priv->adapterRev = 23; /* TLAN 2.3 */ + priv->adapter = &board_info[13]; /* NetFlex-3/E */ + priv->adapter_rev = 23; /* TLAN 2.3 */ } else { priv->adapter = &board_info[14]; - priv->adapterRev = 10; /* TLAN 1.0 */ + priv->adapter_rev = 10; /* TLAN 1.0 */ } dev->base_addr = ioaddr; dev->irq = irq; @@ -620,11 +696,11 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, priv->speed = ((dev->mem_start & 0x18) == 0x18) ? 0 : (dev->mem_start & 0x18) >> 3; - if (priv->speed == 0x1) { + if (priv->speed == 0x1) priv->speed = TLAN_SPEED_10; - } else if (priv->speed == 0x2) { + else if (priv->speed == 0x2) priv->speed = TLAN_SPEED_100; - } + debug = priv->debug = dev->mem_end; } else { priv->aui = aui[boards_found]; @@ -635,11 +711,11 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, /* This will be used when we get an adapter error from * within our irq handler */ - INIT_WORK(&priv->tlan_tqueue, TLan_tx_timeout_work); + INIT_WORK(&priv->tlan_tqueue, tlan_tx_timeout_work); spin_lock_init(&priv->lock); - rc = TLan_Init(dev); + rc = tlan_init(dev); if (rc) { printk(KERN_ERR "TLAN: Could not set up device.\n"); goto err_out_free_dev; @@ -652,29 +728,29 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, } - TLanDevicesInstalled++; + tlan_devices_installed++; boards_found++; /* pdev is NULL if this is an EISA device */ if (pdev) tlan_have_pci++; else { - priv->nextDevice = TLan_Eisa_Devices; - TLan_Eisa_Devices = dev; + priv->next_device = tlan_eisa_devices; + tlan_eisa_devices = dev; tlan_have_eisa++; } printk(KERN_INFO "TLAN: %s irq=%2d, io=%04x, %s, Rev. %d\n", - dev->name, - (int) dev->irq, - (int) dev->base_addr, - priv->adapter->deviceLabel, - priv->adapterRev); + dev->name, + (int) dev->irq, + (int) dev->base_addr, + priv->adapter->device_label, + priv->adapter_rev); return 0; err_out_uninit: - pci_free_consistent(priv->pciDev, priv->dmaSize, priv->dmaStorage, - priv->dmaStorageDMA ); + pci_free_consistent(priv->pci_dev, priv->dma_size, priv->dma_storage, + priv->dma_storage_dma); err_out_free_dev: free_netdev(dev); err_out_regions: @@ -689,22 +765,23 @@ err_out: } -static void TLan_Eisa_Cleanup(void) +static void tlan_eisa_cleanup(void) { struct net_device *dev; - TLanPrivateInfo *priv; + struct tlan_priv *priv; - while( tlan_have_eisa ) { - dev = TLan_Eisa_Devices; + while (tlan_have_eisa) { + dev = tlan_eisa_devices; priv = netdev_priv(dev); - if (priv->dmaStorage) { - pci_free_consistent(priv->pciDev, priv->dmaSize, - priv->dmaStorage, priv->dmaStorageDMA ); + if (priv->dma_storage) { + pci_free_consistent(priv->pci_dev, priv->dma_size, + priv->dma_storage, + priv->dma_storage_dma); } - release_region( dev->base_addr, 0x10); - unregister_netdev( dev ); - TLan_Eisa_Devices = priv->nextDevice; - free_netdev( dev ); + release_region(dev->base_addr, 0x10); + unregister_netdev(dev); + tlan_eisa_devices = priv->next_device; + free_netdev(dev); tlan_have_eisa--; } } @@ -715,7 +792,7 @@ static void __exit tlan_exit(void) pci_unregister_driver(&tlan_driver); if (tlan_have_eisa) - TLan_Eisa_Cleanup(); + tlan_eisa_cleanup(); } @@ -726,24 +803,24 @@ module_exit(tlan_exit); - /************************************************************** - * TLan_EisaProbe - * - * Returns: 0 on success, 1 otherwise - * - * Parms: None - * - * - * This functions probes for EISA devices and calls - * TLan_probe1 when one is found. - * - *************************************************************/ +/************************************************************** + * tlan_eisa_probe + * + * Returns: 0 on success, 1 otherwise + * + * Parms: None + * + * + * This functions probes for EISA devices and calls + * TLan_probe1 when one is found. + * + *************************************************************/ -static void __init TLan_EisaProbe (void) +static void __init tlan_eisa_probe(void) { - long ioaddr; - int rc = -ENODEV; - int irq; + long ioaddr; + int rc = -ENODEV; + int irq; u16 device_id; if (!EISA_bus) { @@ -754,15 +831,16 @@ static void __init TLan_EisaProbe (void) /* Loop through all slots of the EISA bus */ for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { - TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", - (int) ioaddr + 0xC80, inw(ioaddr + EISA_ID)); - TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", - (int) ioaddr + 0xC82, inw(ioaddr + EISA_ID2)); + TLAN_DBG(TLAN_DEBUG_PROBE, "EISA_ID 0x%4x: 0x%4x\n", + (int) ioaddr + 0xc80, inw(ioaddr + EISA_ID)); + TLAN_DBG(TLAN_DEBUG_PROBE, "EISA_ID 0x%4x: 0x%4x\n", + (int) ioaddr + 0xc82, inw(ioaddr + EISA_ID2)); - TLAN_DBG(TLAN_DEBUG_PROBE, "Probing for EISA adapter at IO: 0x%4x : ", - (int) ioaddr); - if (request_region(ioaddr, 0x10, TLanSignature) == NULL) + TLAN_DBG(TLAN_DEBUG_PROBE, + "Probing for EISA adapter at IO: 0x%4x : ", + (int) ioaddr); + if (request_region(ioaddr, 0x10, tlan_signature) == NULL) goto out; if (inw(ioaddr + EISA_ID) != 0x110E) { @@ -772,326 +850,326 @@ static void __init TLan_EisaProbe (void) device_id = inw(ioaddr + EISA_ID2); if (device_id != 0x20F1 && device_id != 0x40F1) { - release_region (ioaddr, 0x10); + release_region(ioaddr, 0x10); goto out; } - if (inb(ioaddr + EISA_CR) != 0x1) { /* Check if adapter is enabled */ - release_region (ioaddr, 0x10); + /* check if adapter is enabled */ + if (inb(ioaddr + EISA_CR) != 0x1) { + release_region(ioaddr, 0x10); goto out2; } if (debug == 0x10) - printk("Found one\n"); + printk(KERN_INFO "Found one\n"); /* Get irq from board */ - switch (inb(ioaddr + 0xCC0)) { - case(0x10): - irq=5; - break; - case(0x20): - irq=9; - break; - case(0x40): - irq=10; - break; - case(0x80): - irq=11; - break; - default: - goto out; + switch (inb(ioaddr + 0xcc0)) { + case(0x10): + irq = 5; + break; + case(0x20): + irq = 9; + break; + case(0x40): + irq = 10; + break; + case(0x80): + irq = 11; + break; + default: + goto out; } /* Setup the newly found eisa adapter */ - rc = TLan_probe1( NULL, ioaddr, irq, - 12, NULL); + rc = tlan_probe1(NULL, ioaddr, irq, + 12, NULL); continue; - out: - if (debug == 0x10) - printk("None found\n"); - continue; +out: + if (debug == 0x10) + printk(KERN_INFO "None found\n"); + continue; - out2: if (debug == 0x10) - printk("Card found but it is not enabled, skipping\n"); - continue; +out2: + if (debug == 0x10) + printk(KERN_INFO "Card found but it is not enabled, skipping\n"); + continue; } -} /* TLan_EisaProbe */ +} #ifdef CONFIG_NET_POLL_CONTROLLER -static void TLan_Poll(struct net_device *dev) +static void tlan_poll(struct net_device *dev) { disable_irq(dev->irq); - TLan_HandleInterrupt(dev->irq, dev); + tlan_handle_interrupt(dev->irq, dev); enable_irq(dev->irq); } #endif -static const struct net_device_ops TLan_netdev_ops = { - .ndo_open = TLan_Open, - .ndo_stop = TLan_Close, - .ndo_start_xmit = TLan_StartTx, - .ndo_tx_timeout = TLan_tx_timeout, - .ndo_get_stats = TLan_GetStats, - .ndo_set_multicast_list = TLan_SetMulticastList, - .ndo_do_ioctl = TLan_ioctl, +static const struct net_device_ops tlan_netdev_ops = { + .ndo_open = tlan_open, + .ndo_stop = tlan_close, + .ndo_start_xmit = tlan_start_tx, + .ndo_tx_timeout = tlan_tx_timeout, + .ndo_get_stats = tlan_get_stats, + .ndo_set_multicast_list = tlan_set_multicast_list, + .ndo_do_ioctl = tlan_ioctl, .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, #ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = TLan_Poll, + .ndo_poll_controller = tlan_poll, #endif }; - /*************************************************************** - * TLan_Init - * - * Returns: - * 0 on success, error code otherwise. - * Parms: - * dev The structure of the device to be - * init'ed. - * - * This function completes the initialization of the - * device structure and driver. It reserves the IO - * addresses, allocates memory for the lists and bounce - * buffers, retrieves the MAC address from the eeprom - * and assignes the device's methods. - * - **************************************************************/ - -static int TLan_Init( struct net_device *dev ) +/*************************************************************** + * tlan_init + * + * Returns: + * 0 on success, error code otherwise. + * Parms: + * dev The structure of the device to be + * init'ed. + * + * This function completes the initialization of the + * device structure and driver. It reserves the IO + * addresses, allocates memory for the lists and bounce + * buffers, retrieves the MAC address from the eeprom + * and assignes the device's methods. + * + **************************************************************/ + +static int tlan_init(struct net_device *dev) { int dma_size; - int err; + int err; int i; - TLanPrivateInfo *priv; + struct tlan_priv *priv; priv = netdev_priv(dev); - dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) - * ( sizeof(TLanList) ); - priv->dmaStorage = pci_alloc_consistent(priv->pciDev, - dma_size, &priv->dmaStorageDMA); - priv->dmaSize = dma_size; - - if ( priv->dmaStorage == NULL ) { - printk(KERN_ERR "TLAN: Could not allocate lists and buffers for %s.\n", - dev->name ); + dma_size = (TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS) + * (sizeof(struct tlan_list)); + priv->dma_storage = pci_alloc_consistent(priv->pci_dev, + dma_size, + &priv->dma_storage_dma); + priv->dma_size = dma_size; + + if (priv->dma_storage == NULL) { + printk(KERN_ERR + "TLAN: Could not allocate lists and buffers for %s.\n", + dev->name); return -ENOMEM; } - memset( priv->dmaStorage, 0, dma_size ); - priv->rxList = (TLanList *) ALIGN((unsigned long)priv->dmaStorage, 8); - priv->rxListDMA = ALIGN(priv->dmaStorageDMA, 8); - priv->txList = priv->rxList + TLAN_NUM_RX_LISTS; - priv->txListDMA = priv->rxListDMA + sizeof(TLanList) * TLAN_NUM_RX_LISTS; + memset(priv->dma_storage, 0, dma_size); + priv->rx_list = (struct tlan_list *) + ALIGN((unsigned long)priv->dma_storage, 8); + priv->rx_list_dma = ALIGN(priv->dma_storage_dma, 8); + priv->tx_list = priv->rx_list + TLAN_NUM_RX_LISTS; + priv->tx_list_dma = + priv->rx_list_dma + sizeof(struct tlan_list)*TLAN_NUM_RX_LISTS; err = 0; - for ( i = 0; i < 6 ; i++ ) - err |= TLan_EeReadByte( dev, - (u8) priv->adapter->addrOfs + i, - (u8 *) &dev->dev_addr[i] ); - if ( err ) { + for (i = 0; i < 6 ; i++) + err |= tlan_ee_read_byte(dev, + (u8) priv->adapter->addr_ofs + i, + (u8 *) &dev->dev_addr[i]); + if (err) { printk(KERN_ERR "TLAN: %s: Error reading MAC from eeprom: %d\n", - dev->name, - err ); + dev->name, + err); } dev->addr_len = 6; netif_carrier_off(dev); /* Device methods */ - dev->netdev_ops = &TLan_netdev_ops; + dev->netdev_ops = &tlan_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; return 0; -} /* TLan_Init */ +} - /*************************************************************** - * TLan_Open - * - * Returns: - * 0 on success, error code otherwise. - * Parms: - * dev Structure of device to be opened. - * - * This routine puts the driver and TLAN adapter in a - * state where it is ready to send and receive packets. - * It allocates the IRQ, resets and brings the adapter - * out of reset, and allows interrupts. It also delays - * the startup for autonegotiation or sends a Rx GO - * command to the adapter, as appropriate. - * - **************************************************************/ +/*************************************************************** + * tlan_open + * + * Returns: + * 0 on success, error code otherwise. + * Parms: + * dev Structure of device to be opened. + * + * This routine puts the driver and TLAN adapter in a + * state where it is ready to send and receive packets. + * It allocates the IRQ, resets and brings the adapter + * out of reset, and allows interrupts. It also delays + * the startup for autonegotiation or sends a Rx GO + * command to the adapter, as appropriate. + * + **************************************************************/ -static int TLan_Open( struct net_device *dev ) +static int tlan_open(struct net_device *dev) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); int err; - priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION ); - err = request_irq( dev->irq, TLan_HandleInterrupt, IRQF_SHARED, - dev->name, dev ); + priv->tlan_rev = tlan_dio_read8(dev->base_addr, TLAN_DEF_REVISION); + err = request_irq(dev->irq, tlan_handle_interrupt, IRQF_SHARED, + dev->name, dev); - if ( err ) { + if (err) { pr_err("TLAN: Cannot open %s because IRQ %d is already in use.\n", - dev->name, dev->irq ); + dev->name, dev->irq); return err; } init_timer(&priv->timer); - netif_start_queue(dev); - /* NOTE: It might not be necessary to read the stats before a - reset if you don't care what the values are. - */ - TLan_ResetLists( dev ); - TLan_ReadAndClearStats( dev, TLAN_IGNORE ); - TLan_ResetAdapter( dev ); + tlan_start(dev); - TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Opened. TLAN Chip Rev: %x\n", - dev->name, priv->tlanRev ); + TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Opened. TLAN Chip Rev: %x\n", + dev->name, priv->tlan_rev); return 0; -} /* TLan_Open */ +} - /************************************************************** - * TLan_ioctl - * - * Returns: - * 0 on success, error code otherwise - * Params: - * dev structure of device to receive ioctl. - * - * rq ifreq structure to hold userspace data. - * - * cmd ioctl command. - * - * - *************************************************************/ +/************************************************************** + * tlan_ioctl + * + * Returns: + * 0 on success, error code otherwise + * Params: + * dev structure of device to receive ioctl. + * + * rq ifreq structure to hold userspace data. + * + * cmd ioctl command. + * + * + *************************************************************/ -static int TLan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static int tlan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); struct mii_ioctl_data *data = if_mii(rq); - u32 phy = priv->phy[priv->phyNum]; + u32 phy = priv->phy[priv->phy_num]; - if (!priv->phyOnline) + if (!priv->phy_online) return -EAGAIN; - switch(cmd) { - case SIOCGMIIPHY: /* Get address of MII PHY in use. */ - data->phy_id = phy; + switch (cmd) { + case SIOCGMIIPHY: /* get address of MII PHY in use. */ + data->phy_id = phy; - case SIOCGMIIREG: /* Read MII PHY register. */ - TLan_MiiReadReg(dev, data->phy_id & 0x1f, - data->reg_num & 0x1f, &data->val_out); - return 0; + case SIOCGMIIREG: /* read MII PHY register. */ + tlan_mii_read_reg(dev, data->phy_id & 0x1f, + data->reg_num & 0x1f, &data->val_out); + return 0; - case SIOCSMIIREG: /* Write MII PHY register. */ - TLan_MiiWriteReg(dev, data->phy_id & 0x1f, - data->reg_num & 0x1f, data->val_in); - return 0; - default: - return -EOPNOTSUPP; + case SIOCSMIIREG: /* write MII PHY register. */ + tlan_mii_write_reg(dev, data->phy_id & 0x1f, + data->reg_num & 0x1f, data->val_in); + return 0; + default: + return -EOPNOTSUPP; } -} /* tlan_ioctl */ +} - /*************************************************************** - * TLan_tx_timeout - * - * Returns: nothing - * - * Params: - * dev structure of device which timed out - * during transmit. - * - **************************************************************/ +/*************************************************************** + * tlan_tx_timeout + * + * Returns: nothing + * + * Params: + * dev structure of device which timed out + * during transmit. + * + **************************************************************/ -static void TLan_tx_timeout(struct net_device *dev) +static void tlan_tx_timeout(struct net_device *dev) { - TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Transmit timed out.\n", dev->name); + TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Transmit timed out.\n", dev->name); /* Ok so we timed out, lets see what we can do about it...*/ - TLan_FreeLists( dev ); - TLan_ResetLists( dev ); - TLan_ReadAndClearStats( dev, TLAN_IGNORE ); - TLan_ResetAdapter( dev ); + tlan_free_lists(dev); + tlan_reset_lists(dev); + tlan_read_and_clear_stats(dev, TLAN_IGNORE); + tlan_reset_adapter(dev); dev->trans_start = jiffies; /* prevent tx timeout */ - netif_wake_queue( dev ); + netif_wake_queue(dev); } - /*************************************************************** - * TLan_tx_timeout_work - * - * Returns: nothing - * - * Params: - * work work item of device which timed out - * - **************************************************************/ +/*************************************************************** + * tlan_tx_timeout_work + * + * Returns: nothing + * + * Params: + * work work item of device which timed out + * + **************************************************************/ -static void TLan_tx_timeout_work(struct work_struct *work) +static void tlan_tx_timeout_work(struct work_struct *work) { - TLanPrivateInfo *priv = - container_of(work, TLanPrivateInfo, tlan_tqueue); + struct tlan_priv *priv = + container_of(work, struct tlan_priv, tlan_tqueue); - TLan_tx_timeout(priv->dev); + tlan_tx_timeout(priv->dev); } - /*************************************************************** - * TLan_StartTx - * - * Returns: - * 0 on success, non-zero on failure. - * Parms: - * skb A pointer to the sk_buff containing the - * frame to be sent. - * dev The device to send the data on. - * - * This function adds a frame to the Tx list to be sent - * ASAP. First it verifies that the adapter is ready and - * there is room in the queue. Then it sets up the next - * available list, copies the frame to the corresponding - * buffer. If the adapter Tx channel is idle, it gives - * the adapter a Tx Go command on the list, otherwise it - * sets the forward address of the previous list to point - * to this one. Then it frees the sk_buff. - * - **************************************************************/ - -static netdev_tx_t TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) +/*************************************************************** + * tlan_start_tx + * + * Returns: + * 0 on success, non-zero on failure. + * Parms: + * skb A pointer to the sk_buff containing the + * frame to be sent. + * dev The device to send the data on. + * + * This function adds a frame to the Tx list to be sent + * ASAP. First it verifies that the adapter is ready and + * there is room in the queue. Then it sets up the next + * available list, copies the frame to the corresponding + * buffer. If the adapter Tx channel is idle, it gives + * the adapter a Tx Go command on the list, otherwise it + * sets the forward address of the previous list to point + * to this one. Then it frees the sk_buff. + * + **************************************************************/ + +static netdev_tx_t tlan_start_tx(struct sk_buff *skb, struct net_device *dev) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); dma_addr_t tail_list_phys; - TLanList *tail_list; + struct tlan_list *tail_list; unsigned long flags; unsigned int txlen; - if ( ! priv->phyOnline ) { - TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s PHY is not ready\n", - dev->name ); + if (!priv->phy_online) { + TLAN_DBG(TLAN_DEBUG_TX, "TRANSMIT: %s PHY is not ready\n", + dev->name); dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -1100,218 +1178,214 @@ static netdev_tx_t TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) return NETDEV_TX_OK; txlen = max(skb->len, (unsigned int)TLAN_MIN_FRAME_SIZE); - tail_list = priv->txList + priv->txTail; - tail_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txTail; + tail_list = priv->tx_list + priv->tx_tail; + tail_list_phys = + priv->tx_list_dma + sizeof(struct tlan_list)*priv->tx_tail; - if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) { - TLAN_DBG( TLAN_DEBUG_TX, - "TRANSMIT: %s is busy (Head=%d Tail=%d)\n", - dev->name, priv->txHead, priv->txTail ); + if (tail_list->c_stat != TLAN_CSTAT_UNUSED) { + TLAN_DBG(TLAN_DEBUG_TX, + "TRANSMIT: %s is busy (Head=%d Tail=%d)\n", + dev->name, priv->tx_head, priv->tx_tail); netif_stop_queue(dev); - priv->txBusyCount++; + priv->tx_busy_count++; return NETDEV_TX_BUSY; } tail_list->forward = 0; - tail_list->buffer[0].address = pci_map_single(priv->pciDev, + tail_list->buffer[0].address = pci_map_single(priv->pci_dev, skb->data, txlen, PCI_DMA_TODEVICE); - TLan_StoreSKB(tail_list, skb); + tlan_store_skb(tail_list, skb); - tail_list->frameSize = (u16) txlen; + tail_list->frame_size = (u16) txlen; tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) txlen; tail_list->buffer[1].count = 0; tail_list->buffer[1].address = 0; spin_lock_irqsave(&priv->lock, flags); - tail_list->cStat = TLAN_CSTAT_READY; - if ( ! priv->txInProgress ) { - priv->txInProgress = 1; - TLAN_DBG( TLAN_DEBUG_TX, - "TRANSMIT: Starting TX on buffer %d\n", priv->txTail ); - outl( tail_list_phys, dev->base_addr + TLAN_CH_PARM ); - outl( TLAN_HC_GO, dev->base_addr + TLAN_HOST_CMD ); + tail_list->c_stat = TLAN_CSTAT_READY; + if (!priv->tx_in_progress) { + priv->tx_in_progress = 1; + TLAN_DBG(TLAN_DEBUG_TX, + "TRANSMIT: Starting TX on buffer %d\n", + priv->tx_tail); + outl(tail_list_phys, dev->base_addr + TLAN_CH_PARM); + outl(TLAN_HC_GO, dev->base_addr + TLAN_HOST_CMD); } else { - TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Adding buffer %d to TX channel\n", - priv->txTail ); - if ( priv->txTail == 0 ) { - ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward + TLAN_DBG(TLAN_DEBUG_TX, + "TRANSMIT: Adding buffer %d to TX channel\n", + priv->tx_tail); + if (priv->tx_tail == 0) { + (priv->tx_list + (TLAN_NUM_TX_LISTS - 1))->forward = tail_list_phys; } else { - ( priv->txList + ( priv->txTail - 1 ) )->forward + (priv->tx_list + (priv->tx_tail - 1))->forward = tail_list_phys; } } spin_unlock_irqrestore(&priv->lock, flags); - CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS ); + CIRC_INC(priv->tx_tail, TLAN_NUM_TX_LISTS); return NETDEV_TX_OK; -} /* TLan_StartTx */ +} - /*************************************************************** - * TLan_HandleInterrupt - * - * Returns: - * Nothing - * Parms: - * irq The line on which the interrupt - * occurred. - * dev_id A pointer to the device assigned to - * this irq line. - * - * This function handles an interrupt generated by its - * assigned TLAN adapter. The function deactivates - * interrupts on its adapter, records the type of - * interrupt, executes the appropriate subhandler, and - * acknowdges the interrupt to the adapter (thus - * re-enabling adapter interrupts. - * - **************************************************************/ +/*************************************************************** + * tlan_handle_interrupt + * + * Returns: + * Nothing + * Parms: + * irq The line on which the interrupt + * occurred. + * dev_id A pointer to the device assigned to + * this irq line. + * + * This function handles an interrupt generated by its + * assigned TLAN adapter. The function deactivates + * interrupts on its adapter, records the type of + * interrupt, executes the appropriate subhandler, and + * acknowdges the interrupt to the adapter (thus + * re-enabling adapter interrupts. + * + **************************************************************/ -static irqreturn_t TLan_HandleInterrupt(int irq, void *dev_id) +static irqreturn_t tlan_handle_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); u16 host_int; u16 type; spin_lock(&priv->lock); - host_int = inw( dev->base_addr + TLAN_HOST_INT ); - type = ( host_int & TLAN_HI_IT_MASK ) >> 2; - if ( type ) { + host_int = inw(dev->base_addr + TLAN_HOST_INT); + type = (host_int & TLAN_HI_IT_MASK) >> 2; + if (type) { u32 ack; u32 host_cmd; - outw( host_int, dev->base_addr + TLAN_HOST_INT ); - ack = TLanIntVector[type]( dev, host_int ); + outw(host_int, dev->base_addr + TLAN_HOST_INT); + ack = tlan_int_vector[type](dev, host_int); - if ( ack ) { - host_cmd = TLAN_HC_ACK | ack | ( type << 18 ); - outl( host_cmd, dev->base_addr + TLAN_HOST_CMD ); + if (ack) { + host_cmd = TLAN_HC_ACK | ack | (type << 18); + outl(host_cmd, dev->base_addr + TLAN_HOST_CMD); } } spin_unlock(&priv->lock); return IRQ_RETVAL(type); -} /* TLan_HandleInterrupts */ +} - /*************************************************************** - * TLan_Close - * - * Returns: - * An error code. - * Parms: - * dev The device structure of the device to - * close. - * - * This function shuts down the adapter. It records any - * stats, puts the adapter into reset state, deactivates - * its time as needed, and frees the irq it is using. - * - **************************************************************/ +/*************************************************************** + * tlan_close + * + * Returns: + * An error code. + * Parms: + * dev The device structure of the device to + * close. + * + * This function shuts down the adapter. It records any + * stats, puts the adapter into reset state, deactivates + * its time as needed, and frees the irq it is using. + * + **************************************************************/ -static int TLan_Close(struct net_device *dev) +static int tlan_close(struct net_device *dev) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); - netif_stop_queue(dev); priv->neg_be_verbose = 0; + tlan_stop(dev); - TLan_ReadAndClearStats( dev, TLAN_RECORD ); - outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); - if ( priv->timer.function != NULL ) { - del_timer_sync( &priv->timer ); - priv->timer.function = NULL; - } - - free_irq( dev->irq, dev ); - TLan_FreeLists( dev ); - TLAN_DBG( TLAN_DEBUG_GNRL, "Device %s closed.\n", dev->name ); + free_irq(dev->irq, dev); + tlan_free_lists(dev); + TLAN_DBG(TLAN_DEBUG_GNRL, "Device %s closed.\n", dev->name); return 0; -} /* TLan_Close */ +} - /*************************************************************** - * TLan_GetStats - * - * Returns: - * A pointer to the device's statistics structure. - * Parms: - * dev The device structure to return the - * stats for. - * - * This function updates the devices statistics by reading - * the TLAN chip's onboard registers. Then it returns the - * address of the statistics structure. - * - **************************************************************/ +/*************************************************************** + * tlan_get_stats + * + * Returns: + * A pointer to the device's statistics structure. + * Parms: + * dev The device structure to return the + * stats for. + * + * This function updates the devices statistics by reading + * the TLAN chip's onboard registers. Then it returns the + * address of the statistics structure. + * + **************************************************************/ -static struct net_device_stats *TLan_GetStats( struct net_device *dev ) +static struct net_device_stats *tlan_get_stats(struct net_device *dev) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); int i; /* Should only read stats if open ? */ - TLan_ReadAndClearStats( dev, TLAN_RECORD ); + tlan_read_and_clear_stats(dev, TLAN_RECORD); - TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: %s EOC count = %d\n", dev->name, - priv->rxEocCount ); - TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s Busy count = %d\n", dev->name, - priv->txBusyCount ); - if ( debug & TLAN_DEBUG_GNRL ) { - TLan_PrintDio( dev->base_addr ); - TLan_PhyPrint( dev ); + TLAN_DBG(TLAN_DEBUG_RX, "RECEIVE: %s EOC count = %d\n", dev->name, + priv->rx_eoc_count); + TLAN_DBG(TLAN_DEBUG_TX, "TRANSMIT: %s Busy count = %d\n", dev->name, + priv->tx_busy_count); + if (debug & TLAN_DEBUG_GNRL) { + tlan_print_dio(dev->base_addr); + tlan_phy_print(dev); } - if ( debug & TLAN_DEBUG_LIST ) { - for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) - TLan_PrintList( priv->rxList + i, "RX", i ); - for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) - TLan_PrintList( priv->txList + i, "TX", i ); + if (debug & TLAN_DEBUG_LIST) { + for (i = 0; i < TLAN_NUM_RX_LISTS; i++) + tlan_print_list(priv->rx_list + i, "RX", i); + for (i = 0; i < TLAN_NUM_TX_LISTS; i++) + tlan_print_list(priv->tx_list + i, "TX", i); } return &dev->stats; -} /* TLan_GetStats */ +} - /*************************************************************** - * TLan_SetMulticastList - * - * Returns: - * Nothing - * Parms: - * dev The device structure to set the - * multicast list for. - * - * This function sets the TLAN adaptor to various receive - * modes. If the IFF_PROMISC flag is set, promiscuous - * mode is acitviated. Otherwise, promiscuous mode is - * turned off. If the IFF_ALLMULTI flag is set, then - * the hash table is set to receive all group addresses. - * Otherwise, the first three multicast addresses are - * stored in AREG_1-3, and the rest are selected via the - * hash table, as necessary. - * - **************************************************************/ +/*************************************************************** + * tlan_set_multicast_list + * + * Returns: + * Nothing + * Parms: + * dev The device structure to set the + * multicast list for. + * + * This function sets the TLAN adaptor to various receive + * modes. If the IFF_PROMISC flag is set, promiscuous + * mode is acitviated. Otherwise, promiscuous mode is + * turned off. If the IFF_ALLMULTI flag is set, then + * the hash table is set to receive all group addresses. + * Otherwise, the first three multicast addresses are + * stored in AREG_1-3, and the rest are selected via the + * hash table, as necessary. + * + **************************************************************/ -static void TLan_SetMulticastList( struct net_device *dev ) +static void tlan_set_multicast_list(struct net_device *dev) { struct netdev_hw_addr *ha; u32 hash1 = 0; @@ -1320,53 +1394,56 @@ static void TLan_SetMulticastList( struct net_device *dev ) u32 offset; u8 tmp; - if ( dev->flags & IFF_PROMISC ) { - tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD ); - TLan_DioWrite8( dev->base_addr, - TLAN_NET_CMD, tmp | TLAN_NET_CMD_CAF ); + if (dev->flags & IFF_PROMISC) { + tmp = tlan_dio_read8(dev->base_addr, TLAN_NET_CMD); + tlan_dio_write8(dev->base_addr, + TLAN_NET_CMD, tmp | TLAN_NET_CMD_CAF); } else { - tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD ); - TLan_DioWrite8( dev->base_addr, - TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF ); - if ( dev->flags & IFF_ALLMULTI ) { - for ( i = 0; i < 3; i++ ) - TLan_SetMac( dev, i + 1, NULL ); - TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, 0xFFFFFFFF ); - TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, 0xFFFFFFFF ); + tmp = tlan_dio_read8(dev->base_addr, TLAN_NET_CMD); + tlan_dio_write8(dev->base_addr, + TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF); + if (dev->flags & IFF_ALLMULTI) { + for (i = 0; i < 3; i++) + tlan_set_mac(dev, i + 1, NULL); + tlan_dio_write32(dev->base_addr, TLAN_HASH_1, + 0xffffffff); + tlan_dio_write32(dev->base_addr, TLAN_HASH_2, + 0xffffffff); } else { i = 0; netdev_for_each_mc_addr(ha, dev) { - if ( i < 3 ) { - TLan_SetMac( dev, i + 1, + if (i < 3) { + tlan_set_mac(dev, i + 1, (char *) &ha->addr); } else { - offset = TLan_HashFunc((u8 *)&ha->addr); - if ( offset < 32 ) - hash1 |= ( 1 << offset ); + offset = + tlan_hash_func((u8 *)&ha->addr); + if (offset < 32) + hash1 |= (1 << offset); else - hash2 |= ( 1 << ( offset - 32 ) ); + hash2 |= (1 << (offset - 32)); } i++; } - for ( ; i < 3; i++ ) - TLan_SetMac( dev, i + 1, NULL ); - TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, hash1 ); - TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, hash2 ); + for ( ; i < 3; i++) + tlan_set_mac(dev, i + 1, NULL); + tlan_dio_write32(dev->base_addr, TLAN_HASH_1, hash1); + tlan_dio_write32(dev->base_addr, TLAN_HASH_2, hash2); } } -} /* TLan_SetMulticastList */ +} /***************************************************************************** ****************************************************************************** - ThunderLAN Driver Interrupt Vectors and Table +ThunderLAN driver interrupt vectors and table - Please see Chap. 4, "Interrupt Handling" of the "ThunderLAN - Programmer's Guide" for more informations on handling interrupts - generated by TLAN based adapters. +please see chap. 4, "Interrupt Handling" of the "ThunderLAN +Programmer's Guide" for more informations on handling interrupts +generated by TLAN based adapters. ****************************************************************************** *****************************************************************************/ @@ -1374,46 +1451,48 @@ static void TLan_SetMulticastList( struct net_device *dev ) - /*************************************************************** - * TLan_HandleTxEOF - * - * Returns: - * 1 - * Parms: - * dev Device assigned the IRQ that was - * raised. - * host_int The contents of the HOST_INT - * port. - * - * This function handles Tx EOF interrupts which are raised - * by the adapter when it has completed sending the - * contents of a buffer. If detemines which list/buffer - * was completed and resets it. If the buffer was the last - * in the channel (EOC), then the function checks to see if - * another buffer is ready to send, and if so, sends a Tx - * Go command. Finally, the driver activates/continues the - * activity LED. - * - **************************************************************/ - -static u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int ) +/*************************************************************** + * tlan_handle_tx_eof + * + * Returns: + * 1 + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This function handles Tx EOF interrupts which are raised + * by the adapter when it has completed sending the + * contents of a buffer. If detemines which list/buffer + * was completed and resets it. If the buffer was the last + * in the channel (EOC), then the function checks to see if + * another buffer is ready to send, and if so, sends a Tx + * Go command. Finally, the driver activates/continues the + * activity LED. + * + **************************************************************/ + +static u32 tlan_handle_tx_eof(struct net_device *dev, u16 host_int) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); int eoc = 0; - TLanList *head_list; + struct tlan_list *head_list; dma_addr_t head_list_phys; u32 ack = 0; - u16 tmpCStat; + u16 tmp_c_stat; - TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n", - priv->txHead, priv->txTail ); - head_list = priv->txList + priv->txHead; + TLAN_DBG(TLAN_DEBUG_TX, + "TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n", + priv->tx_head, priv->tx_tail); + head_list = priv->tx_list + priv->tx_head; - while (((tmpCStat = head_list->cStat ) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { - struct sk_buff *skb = TLan_GetSKB(head_list); + while (((tmp_c_stat = head_list->c_stat) & TLAN_CSTAT_FRM_CMP) + && (ack < 255)) { + struct sk_buff *skb = tlan_get_skb(head_list); ack++; - pci_unmap_single(priv->pciDev, head_list->buffer[0].address, + pci_unmap_single(priv->pci_dev, head_list->buffer[0].address, max(skb->len, (unsigned int)TLAN_MIN_FRAME_SIZE), PCI_DMA_TODEVICE); @@ -1421,304 +1500,313 @@ static u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int ) head_list->buffer[8].address = 0; head_list->buffer[9].address = 0; - if ( tmpCStat & TLAN_CSTAT_EOC ) + if (tmp_c_stat & TLAN_CSTAT_EOC) eoc = 1; - dev->stats.tx_bytes += head_list->frameSize; + dev->stats.tx_bytes += head_list->frame_size; - head_list->cStat = TLAN_CSTAT_UNUSED; + head_list->c_stat = TLAN_CSTAT_UNUSED; netif_start_queue(dev); - CIRC_INC( priv->txHead, TLAN_NUM_TX_LISTS ); - head_list = priv->txList + priv->txHead; + CIRC_INC(priv->tx_head, TLAN_NUM_TX_LISTS); + head_list = priv->tx_list + priv->tx_head; } if (!ack) - printk(KERN_INFO "TLAN: Received interrupt for uncompleted TX frame.\n"); - - if ( eoc ) { - TLAN_DBG( TLAN_DEBUG_TX, - "TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n", - priv->txHead, priv->txTail ); - head_list = priv->txList + priv->txHead; - head_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txHead; - if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { - outl(head_list_phys, dev->base_addr + TLAN_CH_PARM ); + printk(KERN_INFO + "TLAN: Received interrupt for uncompleted TX frame.\n"); + + if (eoc) { + TLAN_DBG(TLAN_DEBUG_TX, + "TRANSMIT: handling TX EOC (Head=%d Tail=%d)\n", + priv->tx_head, priv->tx_tail); + head_list = priv->tx_list + priv->tx_head; + head_list_phys = priv->tx_list_dma + + sizeof(struct tlan_list)*priv->tx_head; + if ((head_list->c_stat & TLAN_CSTAT_READY) + == TLAN_CSTAT_READY) { + outl(head_list_phys, dev->base_addr + TLAN_CH_PARM); ack |= TLAN_HC_GO; } else { - priv->txInProgress = 0; + priv->tx_in_progress = 0; } } - if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) { - TLan_DioWrite8( dev->base_addr, - TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); - if ( priv->timer.function == NULL ) { - priv->timer.function = TLan_Timer; - priv->timer.data = (unsigned long) dev; - priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY; - priv->timerSetAt = jiffies; - priv->timerType = TLAN_TIMER_ACTIVITY; - add_timer(&priv->timer); - } else if ( priv->timerType == TLAN_TIMER_ACTIVITY ) { - priv->timerSetAt = jiffies; + if (priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED) { + tlan_dio_write8(dev->base_addr, + TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT); + if (priv->timer.function == NULL) { + priv->timer.function = tlan_timer; + priv->timer.data = (unsigned long) dev; + priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY; + priv->timer_set_at = jiffies; + priv->timer_type = TLAN_TIMER_ACTIVITY; + add_timer(&priv->timer); + } else if (priv->timer_type == TLAN_TIMER_ACTIVITY) { + priv->timer_set_at = jiffies; } } return ack; -} /* TLan_HandleTxEOF */ +} - /*************************************************************** - * TLan_HandleStatOverflow - * - * Returns: - * 1 - * Parms: - * dev Device assigned the IRQ that was - * raised. - * host_int The contents of the HOST_INT - * port. - * - * This function handles the Statistics Overflow interrupt - * which means that one or more of the TLAN statistics - * registers has reached 1/2 capacity and needs to be read. - * - **************************************************************/ +/*************************************************************** + * TLan_HandleStatOverflow + * + * Returns: + * 1 + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This function handles the Statistics Overflow interrupt + * which means that one or more of the TLAN statistics + * registers has reached 1/2 capacity and needs to be read. + * + **************************************************************/ -static u32 TLan_HandleStatOverflow( struct net_device *dev, u16 host_int ) +static u32 tlan_handle_stat_overflow(struct net_device *dev, u16 host_int) { - TLan_ReadAndClearStats( dev, TLAN_RECORD ); + tlan_read_and_clear_stats(dev, TLAN_RECORD); return 1; -} /* TLan_HandleStatOverflow */ - - - - - /*************************************************************** - * TLan_HandleRxEOF - * - * Returns: - * 1 - * Parms: - * dev Device assigned the IRQ that was - * raised. - * host_int The contents of the HOST_INT - * port. - * - * This function handles the Rx EOF interrupt which - * indicates a frame has been received by the adapter from - * the net and the frame has been transferred to memory. - * The function determines the bounce buffer the frame has - * been loaded into, creates a new sk_buff big enough to - * hold the frame, and sends it to protocol stack. It - * then resets the used buffer and appends it to the end - * of the list. If the frame was the last in the Rx - * channel (EOC), the function restarts the receive channel - * by sending an Rx Go command to the adapter. Then it - * activates/continues the activity LED. - * - **************************************************************/ - -static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) +} + + + + +/*************************************************************** + * TLan_HandleRxEOF + * + * Returns: + * 1 + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This function handles the Rx EOF interrupt which + * indicates a frame has been received by the adapter from + * the net and the frame has been transferred to memory. + * The function determines the bounce buffer the frame has + * been loaded into, creates a new sk_buff big enough to + * hold the frame, and sends it to protocol stack. It + * then resets the used buffer and appends it to the end + * of the list. If the frame was the last in the Rx + * channel (EOC), the function restarts the receive channel + * by sending an Rx Go command to the adapter. Then it + * activates/continues the activity LED. + * + **************************************************************/ + +static u32 tlan_handle_rx_eof(struct net_device *dev, u16 host_int) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); u32 ack = 0; int eoc = 0; - TLanList *head_list; + struct tlan_list *head_list; struct sk_buff *skb; - TLanList *tail_list; - u16 tmpCStat; + struct tlan_list *tail_list; + u16 tmp_c_stat; dma_addr_t head_list_phys; - TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOF (Head=%d Tail=%d)\n", - priv->rxHead, priv->rxTail ); - head_list = priv->rxList + priv->rxHead; - head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead; + TLAN_DBG(TLAN_DEBUG_RX, "RECEIVE: handling RX EOF (Head=%d Tail=%d)\n", + priv->rx_head, priv->rx_tail); + head_list = priv->rx_list + priv->rx_head; + head_list_phys = + priv->rx_list_dma + sizeof(struct tlan_list)*priv->rx_head; - while (((tmpCStat = head_list->cStat) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { - dma_addr_t frameDma = head_list->buffer[0].address; - u32 frameSize = head_list->frameSize; + while (((tmp_c_stat = head_list->c_stat) & TLAN_CSTAT_FRM_CMP) + && (ack < 255)) { + dma_addr_t frame_dma = head_list->buffer[0].address; + u32 frame_size = head_list->frame_size; struct sk_buff *new_skb; ack++; - if (tmpCStat & TLAN_CSTAT_EOC) + if (tmp_c_stat & TLAN_CSTAT_EOC) eoc = 1; new_skb = netdev_alloc_skb_ip_align(dev, TLAN_MAX_FRAME_SIZE + 5); - if ( !new_skb ) + if (!new_skb) goto drop_and_reuse; - skb = TLan_GetSKB(head_list); - pci_unmap_single(priv->pciDev, frameDma, + skb = tlan_get_skb(head_list); + pci_unmap_single(priv->pci_dev, frame_dma, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); - skb_put( skb, frameSize ); + skb_put(skb, frame_size); - dev->stats.rx_bytes += frameSize; + dev->stats.rx_bytes += frame_size; - skb->protocol = eth_type_trans( skb, dev ); - netif_rx( skb ); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); - head_list->buffer[0].address = pci_map_single(priv->pciDev, - new_skb->data, - TLAN_MAX_FRAME_SIZE, - PCI_DMA_FROMDEVICE); + head_list->buffer[0].address = + pci_map_single(priv->pci_dev, new_skb->data, + TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); - TLan_StoreSKB(head_list, new_skb); + tlan_store_skb(head_list, new_skb); drop_and_reuse: head_list->forward = 0; - head_list->cStat = 0; - tail_list = priv->rxList + priv->rxTail; + head_list->c_stat = 0; + tail_list = priv->rx_list + priv->rx_tail; tail_list->forward = head_list_phys; - CIRC_INC( priv->rxHead, TLAN_NUM_RX_LISTS ); - CIRC_INC( priv->rxTail, TLAN_NUM_RX_LISTS ); - head_list = priv->rxList + priv->rxHead; - head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead; + CIRC_INC(priv->rx_head, TLAN_NUM_RX_LISTS); + CIRC_INC(priv->rx_tail, TLAN_NUM_RX_LISTS); + head_list = priv->rx_list + priv->rx_head; + head_list_phys = priv->rx_list_dma + + sizeof(struct tlan_list)*priv->rx_head; } if (!ack) - printk(KERN_INFO "TLAN: Received interrupt for uncompleted RX frame.\n"); - - - if ( eoc ) { - TLAN_DBG( TLAN_DEBUG_RX, - "RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n", - priv->rxHead, priv->rxTail ); - head_list = priv->rxList + priv->rxHead; - head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead; - outl(head_list_phys, dev->base_addr + TLAN_CH_PARM ); + printk(KERN_INFO + "TLAN: Received interrupt for uncompleted RX frame.\n"); + + + if (eoc) { + TLAN_DBG(TLAN_DEBUG_RX, + "RECEIVE: handling RX EOC (Head=%d Tail=%d)\n", + priv->rx_head, priv->rx_tail); + head_list = priv->rx_list + priv->rx_head; + head_list_phys = priv->rx_list_dma + + sizeof(struct tlan_list)*priv->rx_head; + outl(head_list_phys, dev->base_addr + TLAN_CH_PARM); ack |= TLAN_HC_GO | TLAN_HC_RT; - priv->rxEocCount++; + priv->rx_eoc_count++; } - if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) { - TLan_DioWrite8( dev->base_addr, - TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); - if ( priv->timer.function == NULL ) { - priv->timer.function = TLan_Timer; + if (priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED) { + tlan_dio_write8(dev->base_addr, + TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT); + if (priv->timer.function == NULL) { + priv->timer.function = tlan_timer; priv->timer.data = (unsigned long) dev; priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY; - priv->timerSetAt = jiffies; - priv->timerType = TLAN_TIMER_ACTIVITY; + priv->timer_set_at = jiffies; + priv->timer_type = TLAN_TIMER_ACTIVITY; add_timer(&priv->timer); - } else if ( priv->timerType == TLAN_TIMER_ACTIVITY ) { - priv->timerSetAt = jiffies; + } else if (priv->timer_type == TLAN_TIMER_ACTIVITY) { + priv->timer_set_at = jiffies; } } return ack; -} /* TLan_HandleRxEOF */ +} - /*************************************************************** - * TLan_HandleDummy - * - * Returns: - * 1 - * Parms: - * dev Device assigned the IRQ that was - * raised. - * host_int The contents of the HOST_INT - * port. - * - * This function handles the Dummy interrupt, which is - * raised whenever a test interrupt is generated by setting - * the Req_Int bit of HOST_CMD to 1. - * - **************************************************************/ +/*************************************************************** + * tlan_handle_dummy + * + * Returns: + * 1 + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This function handles the Dummy interrupt, which is + * raised whenever a test interrupt is generated by setting + * the Req_Int bit of HOST_CMD to 1. + * + **************************************************************/ -static u32 TLan_HandleDummy( struct net_device *dev, u16 host_int ) +static u32 tlan_handle_dummy(struct net_device *dev, u16 host_int) { - printk( "TLAN: Test interrupt on %s.\n", dev->name ); + pr_info("TLAN: Test interrupt on %s.\n", dev->name); return 1; -} /* TLan_HandleDummy */ +} - /*************************************************************** - * TLan_HandleTxEOC - * - * Returns: - * 1 - * Parms: - * dev Device assigned the IRQ that was - * raised. - * host_int The contents of the HOST_INT - * port. - * - * This driver is structured to determine EOC occurrences by - * reading the CSTAT member of the list structure. Tx EOC - * interrupts are disabled via the DIO INTDIS register. - * However, TLAN chips before revision 3.0 didn't have this - * functionality, so process EOC events if this is the - * case. - * - **************************************************************/ +/*************************************************************** + * tlan_handle_tx_eoc + * + * Returns: + * 1 + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This driver is structured to determine EOC occurrences by + * reading the CSTAT member of the list structure. Tx EOC + * interrupts are disabled via the DIO INTDIS register. + * However, TLAN chips before revision 3.0 didn't have this + * functionality, so process EOC events if this is the + * case. + * + **************************************************************/ -static u32 TLan_HandleTxEOC( struct net_device *dev, u16 host_int ) +static u32 tlan_handle_tx_eoc(struct net_device *dev, u16 host_int) { - TLanPrivateInfo *priv = netdev_priv(dev); - TLanList *head_list; + struct tlan_priv *priv = netdev_priv(dev); + struct tlan_list *head_list; dma_addr_t head_list_phys; u32 ack = 1; host_int = 0; - if ( priv->tlanRev < 0x30 ) { - TLAN_DBG( TLAN_DEBUG_TX, - "TRANSMIT: Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", - priv->txHead, priv->txTail ); - head_list = priv->txList + priv->txHead; - head_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txHead; - if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { + if (priv->tlan_rev < 0x30) { + TLAN_DBG(TLAN_DEBUG_TX, + "TRANSMIT: handling TX EOC (Head=%d Tail=%d) -- IRQ\n", + priv->tx_head, priv->tx_tail); + head_list = priv->tx_list + priv->tx_head; + head_list_phys = priv->tx_list_dma + + sizeof(struct tlan_list)*priv->tx_head; + if ((head_list->c_stat & TLAN_CSTAT_READY) + == TLAN_CSTAT_READY) { netif_stop_queue(dev); - outl( head_list_phys, dev->base_addr + TLAN_CH_PARM ); + outl(head_list_phys, dev->base_addr + TLAN_CH_PARM); ack |= TLAN_HC_GO; } else { - priv->txInProgress = 0; + priv->tx_in_progress = 0; } } return ack; -} /* TLan_HandleTxEOC */ +} - /*************************************************************** - * TLan_HandleStatusCheck - * - * Returns: - * 0 if Adapter check, 1 if Network Status check. - * Parms: - * dev Device assigned the IRQ that was - * raised. - * host_int The contents of the HOST_INT - * port. - * - * This function handles Adapter Check/Network Status - * interrupts generated by the adapter. It checks the - * vector in the HOST_INT register to determine if it is - * an Adapter Check interrupt. If so, it resets the - * adapter. Otherwise it clears the status registers - * and services the PHY. - * - **************************************************************/ +/*************************************************************** + * tlan_handle_status_check + * + * Returns: + * 0 if Adapter check, 1 if Network Status check. + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This function handles Adapter Check/Network Status + * interrupts generated by the adapter. It checks the + * vector in the HOST_INT register to determine if it is + * an Adapter Check interrupt. If so, it resets the + * adapter. Otherwise it clears the status registers + * and services the PHY. + * + **************************************************************/ -static u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int ) +static u32 tlan_handle_status_check(struct net_device *dev, u16 host_int) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); u32 ack; u32 error; u8 net_sts; @@ -1727,92 +1815,94 @@ static u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int ) u16 tlphy_sts; ack = 1; - if ( host_int & TLAN_HI_IV_MASK ) { - netif_stop_queue( dev ); - error = inl( dev->base_addr + TLAN_CH_PARM ); - printk( "TLAN: %s: Adaptor Error = 0x%x\n", dev->name, error ); - TLan_ReadAndClearStats( dev, TLAN_RECORD ); - outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); + if (host_int & TLAN_HI_IV_MASK) { + netif_stop_queue(dev); + error = inl(dev->base_addr + TLAN_CH_PARM); + pr_info("TLAN: %s: Adaptor Error = 0x%x\n", dev->name, error); + tlan_read_and_clear_stats(dev, TLAN_RECORD); + outl(TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD); schedule_work(&priv->tlan_tqueue); netif_wake_queue(dev); ack = 0; } else { - TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Status Check\n", dev->name ); - phy = priv->phy[priv->phyNum]; - - net_sts = TLan_DioRead8( dev->base_addr, TLAN_NET_STS ); - if ( net_sts ) { - TLan_DioWrite8( dev->base_addr, TLAN_NET_STS, net_sts ); - TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Net_Sts = %x\n", - dev->name, (unsigned) net_sts ); + TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Status Check\n", dev->name); + phy = priv->phy[priv->phy_num]; + + net_sts = tlan_dio_read8(dev->base_addr, TLAN_NET_STS); + if (net_sts) { + tlan_dio_write8(dev->base_addr, TLAN_NET_STS, net_sts); + TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Net_Sts = %x\n", + dev->name, (unsigned) net_sts); } - if ( ( net_sts & TLAN_NET_STS_MIRQ ) && ( priv->phyNum == 0 ) ) { - TLan_MiiReadReg( dev, phy, TLAN_TLPHY_STS, &tlphy_sts ); - TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl ); - if ( ! ( tlphy_sts & TLAN_TS_POLOK ) && - ! ( tlphy_ctl & TLAN_TC_SWAPOL ) ) { - tlphy_ctl |= TLAN_TC_SWAPOL; - TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl); - } else if ( ( tlphy_sts & TLAN_TS_POLOK ) && - ( tlphy_ctl & TLAN_TC_SWAPOL ) ) { - tlphy_ctl &= ~TLAN_TC_SWAPOL; - TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl); - } - - if (debug) { - TLan_PhyPrint( dev ); + if ((net_sts & TLAN_NET_STS_MIRQ) && (priv->phy_num == 0)) { + tlan_mii_read_reg(dev, phy, TLAN_TLPHY_STS, &tlphy_sts); + tlan_mii_read_reg(dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl); + if (!(tlphy_sts & TLAN_TS_POLOK) && + !(tlphy_ctl & TLAN_TC_SWAPOL)) { + tlphy_ctl |= TLAN_TC_SWAPOL; + tlan_mii_write_reg(dev, phy, TLAN_TLPHY_CTL, + tlphy_ctl); + } else if ((tlphy_sts & TLAN_TS_POLOK) && + (tlphy_ctl & TLAN_TC_SWAPOL)) { + tlphy_ctl &= ~TLAN_TC_SWAPOL; + tlan_mii_write_reg(dev, phy, TLAN_TLPHY_CTL, + tlphy_ctl); } + + if (debug) + tlan_phy_print(dev); } } return ack; -} /* TLan_HandleStatusCheck */ +} - /*************************************************************** - * TLan_HandleRxEOC - * - * Returns: - * 1 - * Parms: - * dev Device assigned the IRQ that was - * raised. - * host_int The contents of the HOST_INT - * port. - * - * This driver is structured to determine EOC occurrences by - * reading the CSTAT member of the list structure. Rx EOC - * interrupts are disabled via the DIO INTDIS register. - * However, TLAN chips before revision 3.0 didn't have this - * CSTAT member or a INTDIS register, so if this chip is - * pre-3.0, process EOC interrupts normally. - * - **************************************************************/ +/*************************************************************** + * tlan_handle_rx_eoc + * + * Returns: + * 1 + * Parms: + * dev Device assigned the IRQ that was + * raised. + * host_int The contents of the HOST_INT + * port. + * + * This driver is structured to determine EOC occurrences by + * reading the CSTAT member of the list structure. Rx EOC + * interrupts are disabled via the DIO INTDIS register. + * However, TLAN chips before revision 3.0 didn't have this + * CSTAT member or a INTDIS register, so if this chip is + * pre-3.0, process EOC interrupts normally. + * + **************************************************************/ -static u32 TLan_HandleRxEOC( struct net_device *dev, u16 host_int ) +static u32 tlan_handle_rx_eoc(struct net_device *dev, u16 host_int) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); dma_addr_t head_list_phys; u32 ack = 1; - if ( priv->tlanRev < 0x30 ) { - TLAN_DBG( TLAN_DEBUG_RX, - "RECEIVE: Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", - priv->rxHead, priv->rxTail ); - head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead; - outl( head_list_phys, dev->base_addr + TLAN_CH_PARM ); + if (priv->tlan_rev < 0x30) { + TLAN_DBG(TLAN_DEBUG_RX, + "RECEIVE: Handling RX EOC (head=%d tail=%d) -- IRQ\n", + priv->rx_head, priv->rx_tail); + head_list_phys = priv->rx_list_dma + + sizeof(struct tlan_list)*priv->rx_head; + outl(head_list_phys, dev->base_addr + TLAN_CH_PARM); ack |= TLAN_HC_GO | TLAN_HC_RT; - priv->rxEocCount++; + priv->rx_eoc_count++; } return ack; -} /* TLan_HandleRxEOC */ +} @@ -1820,98 +1910,98 @@ static u32 TLan_HandleRxEOC( struct net_device *dev, u16 host_int ) /***************************************************************************** ****************************************************************************** - ThunderLAN Driver Timer Function +ThunderLAN driver timer function ****************************************************************************** *****************************************************************************/ - /*************************************************************** - * TLan_Timer - * - * Returns: - * Nothing - * Parms: - * data A value given to add timer when - * add_timer was called. - * - * This function handles timed functionality for the - * TLAN driver. The two current timer uses are for - * delaying for autonegotionation and driving the ACT LED. - * - Autonegotiation requires being allowed about - * 2 1/2 seconds before attempting to transmit a - * packet. It would be a very bad thing to hang - * the kernel this long, so the driver doesn't - * allow transmission 'til after this time, for - * certain PHYs. It would be much nicer if all - * PHYs were interrupt-capable like the internal - * PHY. - * - The ACT LED, which shows adapter activity, is - * driven by the driver, and so must be left on - * for a short period to power up the LED so it - * can be seen. This delay can be changed by - * changing the TLAN_TIMER_ACT_DELAY in tlan.h, - * if desired. 100 ms produces a slightly - * sluggish response. - * - **************************************************************/ - -static void TLan_Timer( unsigned long data ) +/*************************************************************** + * tlan_timer + * + * Returns: + * Nothing + * Parms: + * data A value given to add timer when + * add_timer was called. + * + * This function handles timed functionality for the + * TLAN driver. The two current timer uses are for + * delaying for autonegotionation and driving the ACT LED. + * - Autonegotiation requires being allowed about + * 2 1/2 seconds before attempting to transmit a + * packet. It would be a very bad thing to hang + * the kernel this long, so the driver doesn't + * allow transmission 'til after this time, for + * certain PHYs. It would be much nicer if all + * PHYs were interrupt-capable like the internal + * PHY. + * - The ACT LED, which shows adapter activity, is + * driven by the driver, and so must be left on + * for a short period to power up the LED so it + * can be seen. This delay can be changed by + * changing the TLAN_TIMER_ACT_DELAY in tlan.h, + * if desired. 100 ms produces a slightly + * sluggish response. + * + **************************************************************/ + +static void tlan_timer(unsigned long data) { struct net_device *dev = (struct net_device *) data; - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); u32 elapsed; unsigned long flags = 0; priv->timer.function = NULL; - switch ( priv->timerType ) { + switch (priv->timer_type) { #ifdef MONITOR - case TLAN_TIMER_LINK_BEAT: - TLan_PhyMonitor( dev ); - break; + case TLAN_TIMER_LINK_BEAT: + tlan_phy_monitor(dev); + break; #endif - case TLAN_TIMER_PHY_PDOWN: - TLan_PhyPowerDown( dev ); - break; - case TLAN_TIMER_PHY_PUP: - TLan_PhyPowerUp( dev ); - break; - case TLAN_TIMER_PHY_RESET: - TLan_PhyReset( dev ); - break; - case TLAN_TIMER_PHY_START_LINK: - TLan_PhyStartLink( dev ); - break; - case TLAN_TIMER_PHY_FINISH_AN: - TLan_PhyFinishAutoNeg( dev ); - break; - case TLAN_TIMER_FINISH_RESET: - TLan_FinishReset( dev ); - break; - case TLAN_TIMER_ACTIVITY: - spin_lock_irqsave(&priv->lock, flags); - if ( priv->timer.function == NULL ) { - elapsed = jiffies - priv->timerSetAt; - if ( elapsed >= TLAN_TIMER_ACT_DELAY ) { - TLan_DioWrite8( dev->base_addr, - TLAN_LED_REG, TLAN_LED_LINK ); - } else { - priv->timer.function = TLan_Timer; - priv->timer.expires = priv->timerSetAt - + TLAN_TIMER_ACT_DELAY; - spin_unlock_irqrestore(&priv->lock, flags); - add_timer( &priv->timer ); - break; - } + case TLAN_TIMER_PHY_PDOWN: + tlan_phy_power_down(dev); + break; + case TLAN_TIMER_PHY_PUP: + tlan_phy_power_up(dev); + break; + case TLAN_TIMER_PHY_RESET: + tlan_phy_reset(dev); + break; + case TLAN_TIMER_PHY_START_LINK: + tlan_phy_start_link(dev); + break; + case TLAN_TIMER_PHY_FINISH_AN: + tlan_phy_finish_auto_neg(dev); + break; + case TLAN_TIMER_FINISH_RESET: + tlan_finish_reset(dev); + break; + case TLAN_TIMER_ACTIVITY: + spin_lock_irqsave(&priv->lock, flags); + if (priv->timer.function == NULL) { + elapsed = jiffies - priv->timer_set_at; + if (elapsed >= TLAN_TIMER_ACT_DELAY) { + tlan_dio_write8(dev->base_addr, + TLAN_LED_REG, TLAN_LED_LINK); + } else { + priv->timer.function = tlan_timer; + priv->timer.expires = priv->timer_set_at + + TLAN_TIMER_ACT_DELAY; + spin_unlock_irqrestore(&priv->lock, flags); + add_timer(&priv->timer); + break; } - spin_unlock_irqrestore(&priv->lock, flags); - break; - default: - break; + } + spin_unlock_irqrestore(&priv->lock, flags); + break; + default: + break; } -} /* TLan_Timer */ +} @@ -1919,39 +2009,39 @@ static void TLan_Timer( unsigned long data ) /***************************************************************************** ****************************************************************************** - ThunderLAN Driver Adapter Related Routines +ThunderLAN driver adapter related routines ****************************************************************************** *****************************************************************************/ - /*************************************************************** - * TLan_ResetLists - * - * Returns: - * Nothing - * Parms: - * dev The device structure with the list - * stuctures to be reset. - * - * This routine sets the variables associated with managing - * the TLAN lists to their initial values. - * - **************************************************************/ - -static void TLan_ResetLists( struct net_device *dev ) +/*************************************************************** + * tlan_reset_lists + * + * Returns: + * Nothing + * Parms: + * dev The device structure with the list + * stuctures to be reset. + * + * This routine sets the variables associated with managing + * the TLAN lists to their initial values. + * + **************************************************************/ + +static void tlan_reset_lists(struct net_device *dev) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); int i; - TLanList *list; + struct tlan_list *list; dma_addr_t list_phys; struct sk_buff *skb; - priv->txHead = 0; - priv->txTail = 0; - for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) { - list = priv->txList + i; - list->cStat = TLAN_CSTAT_UNUSED; + priv->tx_head = 0; + priv->tx_tail = 0; + for (i = 0; i < TLAN_NUM_TX_LISTS; i++) { + list = priv->tx_list + i; + list->c_stat = TLAN_CSTAT_UNUSED; list->buffer[0].address = 0; list->buffer[2].count = 0; list->buffer[2].address = 0; @@ -1959,169 +2049,169 @@ static void TLan_ResetLists( struct net_device *dev ) list->buffer[9].address = 0; } - priv->rxHead = 0; - priv->rxTail = TLAN_NUM_RX_LISTS - 1; - for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) { - list = priv->rxList + i; - list_phys = priv->rxListDMA + sizeof(TLanList) * i; - list->cStat = TLAN_CSTAT_READY; - list->frameSize = TLAN_MAX_FRAME_SIZE; + priv->rx_head = 0; + priv->rx_tail = TLAN_NUM_RX_LISTS - 1; + for (i = 0; i < TLAN_NUM_RX_LISTS; i++) { + list = priv->rx_list + i; + list_phys = priv->rx_list_dma + sizeof(struct tlan_list)*i; + list->c_stat = TLAN_CSTAT_READY; + list->frame_size = TLAN_MAX_FRAME_SIZE; list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; skb = netdev_alloc_skb_ip_align(dev, TLAN_MAX_FRAME_SIZE + 5); - if ( !skb ) { - pr_err("TLAN: out of memory for received data.\n" ); + if (!skb) { + pr_err("TLAN: out of memory for received data.\n"); break; } - list->buffer[0].address = pci_map_single(priv->pciDev, + list->buffer[0].address = pci_map_single(priv->pci_dev, skb->data, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); - TLan_StoreSKB(list, skb); + tlan_store_skb(list, skb); list->buffer[1].count = 0; list->buffer[1].address = 0; - list->forward = list_phys + sizeof(TLanList); + list->forward = list_phys + sizeof(struct tlan_list); } /* in case ran out of memory early, clear bits */ while (i < TLAN_NUM_RX_LISTS) { - TLan_StoreSKB(priv->rxList + i, NULL); + tlan_store_skb(priv->rx_list + i, NULL); ++i; } list->forward = 0; -} /* TLan_ResetLists */ +} -static void TLan_FreeLists( struct net_device *dev ) +static void tlan_free_lists(struct net_device *dev) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); int i; - TLanList *list; + struct tlan_list *list; struct sk_buff *skb; - for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) { - list = priv->txList + i; - skb = TLan_GetSKB(list); - if ( skb ) { + for (i = 0; i < TLAN_NUM_TX_LISTS; i++) { + list = priv->tx_list + i; + skb = tlan_get_skb(list); + if (skb) { pci_unmap_single( - priv->pciDev, + priv->pci_dev, list->buffer[0].address, max(skb->len, (unsigned int)TLAN_MIN_FRAME_SIZE), PCI_DMA_TODEVICE); - dev_kfree_skb_any( skb ); + dev_kfree_skb_any(skb); list->buffer[8].address = 0; list->buffer[9].address = 0; } } - for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) { - list = priv->rxList + i; - skb = TLan_GetSKB(list); - if ( skb ) { - pci_unmap_single(priv->pciDev, + for (i = 0; i < TLAN_NUM_RX_LISTS; i++) { + list = priv->rx_list + i; + skb = tlan_get_skb(list); + if (skb) { + pci_unmap_single(priv->pci_dev, list->buffer[0].address, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); - dev_kfree_skb_any( skb ); + dev_kfree_skb_any(skb); list->buffer[8].address = 0; list->buffer[9].address = 0; } } -} /* TLan_FreeLists */ +} - /*************************************************************** - * TLan_PrintDio - * - * Returns: - * Nothing - * Parms: - * io_base Base IO port of the device of - * which to print DIO registers. - * - * This function prints out all the internal (DIO) - * registers of a TLAN chip. - * - **************************************************************/ +/*************************************************************** + * tlan_print_dio + * + * Returns: + * Nothing + * Parms: + * io_base Base IO port of the device of + * which to print DIO registers. + * + * This function prints out all the internal (DIO) + * registers of a TLAN chip. + * + **************************************************************/ -static void TLan_PrintDio( u16 io_base ) +static void tlan_print_dio(u16 io_base) { u32 data0, data1; int i; - printk( "TLAN: Contents of internal registers for io base 0x%04hx.\n", - io_base ); - printk( "TLAN: Off. +0 +4\n" ); - for ( i = 0; i < 0x4C; i+= 8 ) { - data0 = TLan_DioRead32( io_base, i ); - data1 = TLan_DioRead32( io_base, i + 0x4 ); - printk( "TLAN: 0x%02x 0x%08x 0x%08x\n", i, data0, data1 ); + pr_info("TLAN: Contents of internal registers for io base 0x%04hx.\n", + io_base); + pr_info("TLAN: Off. +0 +4\n"); + for (i = 0; i < 0x4C; i += 8) { + data0 = tlan_dio_read32(io_base, i); + data1 = tlan_dio_read32(io_base, i + 0x4); + pr_info("TLAN: 0x%02x 0x%08x 0x%08x\n", i, data0, data1); } -} /* TLan_PrintDio */ +} - /*************************************************************** - * TLan_PrintList - * - * Returns: - * Nothing - * Parms: - * list A pointer to the TLanList structure to - * be printed. - * type A string to designate type of list, - * "Rx" or "Tx". - * num The index of the list. - * - * This function prints out the contents of the list - * pointed to by the list parameter. - * - **************************************************************/ +/*************************************************************** + * TLan_PrintList + * + * Returns: + * Nothing + * Parms: + * list A pointer to the struct tlan_list structure to + * be printed. + * type A string to designate type of list, + * "Rx" or "Tx". + * num The index of the list. + * + * This function prints out the contents of the list + * pointed to by the list parameter. + * + **************************************************************/ -static void TLan_PrintList( TLanList *list, char *type, int num) +static void tlan_print_list(struct tlan_list *list, char *type, int num) { int i; - printk( "TLAN: %s List %d at %p\n", type, num, list ); - printk( "TLAN: Forward = 0x%08x\n", list->forward ); - printk( "TLAN: CSTAT = 0x%04hx\n", list->cStat ); - printk( "TLAN: Frame Size = 0x%04hx\n", list->frameSize ); - /* for ( i = 0; i < 10; i++ ) { */ - for ( i = 0; i < 2; i++ ) { - printk( "TLAN: Buffer[%d].count, addr = 0x%08x, 0x%08x\n", - i, list->buffer[i].count, list->buffer[i].address ); + pr_info("TLAN: %s List %d at %p\n", type, num, list); + pr_info("TLAN: Forward = 0x%08x\n", list->forward); + pr_info("TLAN: CSTAT = 0x%04hx\n", list->c_stat); + pr_info("TLAN: Frame Size = 0x%04hx\n", list->frame_size); + /* for (i = 0; i < 10; i++) { */ + for (i = 0; i < 2; i++) { + pr_info("TLAN: Buffer[%d].count, addr = 0x%08x, 0x%08x\n", + i, list->buffer[i].count, list->buffer[i].address); } -} /* TLan_PrintList */ +} - /*************************************************************** - * TLan_ReadAndClearStats - * - * Returns: - * Nothing - * Parms: - * dev Pointer to device structure of adapter - * to which to read stats. - * record Flag indicating whether to add - * - * This functions reads all the internal status registers - * of the TLAN chip, which clears them as a side effect. - * It then either adds the values to the device's status - * struct, or discards them, depending on whether record - * is TLAN_RECORD (!=0) or TLAN_IGNORE (==0). - * - **************************************************************/ +/*************************************************************** + * tlan_read_and_clear_stats + * + * Returns: + * Nothing + * Parms: + * dev Pointer to device structure of adapter + * to which to read stats. + * record Flag indicating whether to add + * + * This functions reads all the internal status registers + * of the TLAN chip, which clears them as a side effect. + * It then either adds the values to the device's status + * struct, or discards them, depending on whether record + * is TLAN_RECORD (!=0) or TLAN_IGNORE (==0). + * + **************************************************************/ -static void TLan_ReadAndClearStats( struct net_device *dev, int record ) +static void tlan_read_and_clear_stats(struct net_device *dev, int record) { u32 tx_good, tx_under; u32 rx_good, rx_over; @@ -2129,41 +2219,42 @@ static void TLan_ReadAndClearStats( struct net_device *dev, int record ) u32 multi_col, single_col; u32 excess_col, late_col, loss; - outw( TLAN_GOOD_TX_FRMS, dev->base_addr + TLAN_DIO_ADR ); - tx_good = inb( dev->base_addr + TLAN_DIO_DATA ); - tx_good += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; - tx_good += inb( dev->base_addr + TLAN_DIO_DATA + 2 ) << 16; - tx_under = inb( dev->base_addr + TLAN_DIO_DATA + 3 ); - - outw( TLAN_GOOD_RX_FRMS, dev->base_addr + TLAN_DIO_ADR ); - rx_good = inb( dev->base_addr + TLAN_DIO_DATA ); - rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; - rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 2 ) << 16; - rx_over = inb( dev->base_addr + TLAN_DIO_DATA + 3 ); - - outw( TLAN_DEFERRED_TX, dev->base_addr + TLAN_DIO_ADR ); - def_tx = inb( dev->base_addr + TLAN_DIO_DATA ); - def_tx += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; - crc = inb( dev->base_addr + TLAN_DIO_DATA + 2 ); - code = inb( dev->base_addr + TLAN_DIO_DATA + 3 ); - - outw( TLAN_MULTICOL_FRMS, dev->base_addr + TLAN_DIO_ADR ); - multi_col = inb( dev->base_addr + TLAN_DIO_DATA ); - multi_col += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; - single_col = inb( dev->base_addr + TLAN_DIO_DATA + 2 ); - single_col += inb( dev->base_addr + TLAN_DIO_DATA + 3 ) << 8; - - outw( TLAN_EXCESSCOL_FRMS, dev->base_addr + TLAN_DIO_ADR ); - excess_col = inb( dev->base_addr + TLAN_DIO_DATA ); - late_col = inb( dev->base_addr + TLAN_DIO_DATA + 1 ); - loss = inb( dev->base_addr + TLAN_DIO_DATA + 2 ); - - if ( record ) { + outw(TLAN_GOOD_TX_FRMS, dev->base_addr + TLAN_DIO_ADR); + tx_good = inb(dev->base_addr + TLAN_DIO_DATA); + tx_good += inb(dev->base_addr + TLAN_DIO_DATA + 1) << 8; + tx_good += inb(dev->base_addr + TLAN_DIO_DATA + 2) << 16; + tx_under = inb(dev->base_addr + TLAN_DIO_DATA + 3); + + outw(TLAN_GOOD_RX_FRMS, dev->base_addr + TLAN_DIO_ADR); + rx_good = inb(dev->base_addr + TLAN_DIO_DATA); + rx_good += inb(dev->base_addr + TLAN_DIO_DATA + 1) << 8; + rx_good += inb(dev->base_addr + TLAN_DIO_DATA + 2) << 16; + rx_over = inb(dev->base_addr + TLAN_DIO_DATA + 3); + + outw(TLAN_DEFERRED_TX, dev->base_addr + TLAN_DIO_ADR); + def_tx = inb(dev->base_addr + TLAN_DIO_DATA); + def_tx += inb(dev->base_addr + TLAN_DIO_DATA + 1) << 8; + crc = inb(dev->base_addr + TLAN_DIO_DATA + 2); + code = inb(dev->base_addr + TLAN_DIO_DATA + 3); + + outw(TLAN_MULTICOL_FRMS, dev->base_addr + TLAN_DIO_ADR); + multi_col = inb(dev->base_addr + TLAN_DIO_DATA); + multi_col += inb(dev->base_addr + TLAN_DIO_DATA + 1) << 8; + single_col = inb(dev->base_addr + TLAN_DIO_DATA + 2); + single_col += inb(dev->base_addr + TLAN_DIO_DATA + 3) << 8; + + outw(TLAN_EXCESSCOL_FRMS, dev->base_addr + TLAN_DIO_ADR); + excess_col = inb(dev->base_addr + TLAN_DIO_DATA); + late_col = inb(dev->base_addr + TLAN_DIO_DATA + 1); + loss = inb(dev->base_addr + TLAN_DIO_DATA + 2); + + if (record) { dev->stats.rx_packets += rx_good; dev->stats.rx_errors += rx_over + crc + code; dev->stats.tx_packets += tx_good; dev->stats.tx_errors += tx_under + loss; - dev->stats.collisions += multi_col + single_col + excess_col + late_col; + dev->stats.collisions += multi_col + + single_col + excess_col + late_col; dev->stats.rx_over_errors += rx_over; dev->stats.rx_crc_errors += crc; @@ -2173,39 +2264,39 @@ static void TLan_ReadAndClearStats( struct net_device *dev, int record ) dev->stats.tx_carrier_errors += loss; } -} /* TLan_ReadAndClearStats */ +} - /*************************************************************** - * TLan_Reset - * - * Returns: - * 0 - * Parms: - * dev Pointer to device structure of adapter - * to be reset. - * - * This function resets the adapter and it's physical - * device. See Chap. 3, pp. 9-10 of the "ThunderLAN - * Programmer's Guide" for details. The routine tries to - * implement what is detailed there, though adjustments - * have been made. - * - **************************************************************/ +/*************************************************************** + * TLan_Reset + * + * Returns: + * 0 + * Parms: + * dev Pointer to device structure of adapter + * to be reset. + * + * This function resets the adapter and it's physical + * device. See Chap. 3, pp. 9-10 of the "ThunderLAN + * Programmer's Guide" for details. The routine tries to + * implement what is detailed there, though adjustments + * have been made. + * + **************************************************************/ static void -TLan_ResetAdapter( struct net_device *dev ) +tlan_reset_adapter(struct net_device *dev) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); int i; u32 addr; u32 data; u8 data8; - priv->tlanFullDuplex = false; - priv->phyOnline=0; + priv->tlan_full_duplex = false; + priv->phy_online = 0; netif_carrier_off(dev); /* 1. Assert reset bit. */ @@ -2216,7 +2307,7 @@ TLan_ResetAdapter( struct net_device *dev ) udelay(1000); -/* 2. Turn off interrupts. ( Probably isn't necessary ) */ +/* 2. Turn off interrupts. (Probably isn't necessary) */ data = inl(dev->base_addr + TLAN_HOST_CMD); data |= TLAN_HC_INT_OFF; @@ -2224,207 +2315,208 @@ TLan_ResetAdapter( struct net_device *dev ) /* 3. Clear AREGs and HASHs. */ - for ( i = TLAN_AREG_0; i <= TLAN_HASH_2; i += 4 ) { - TLan_DioWrite32( dev->base_addr, (u16) i, 0 ); - } + for (i = TLAN_AREG_0; i <= TLAN_HASH_2; i += 4) + tlan_dio_write32(dev->base_addr, (u16) i, 0); /* 4. Setup NetConfig register. */ data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN; - TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, (u16) data ); + tlan_dio_write16(dev->base_addr, TLAN_NET_CONFIG, (u16) data); /* 5. Load Ld_Tmr and Ld_Thr in HOST_CMD. */ - outl( TLAN_HC_LD_TMR | 0x3f, dev->base_addr + TLAN_HOST_CMD ); - outl( TLAN_HC_LD_THR | 0x9, dev->base_addr + TLAN_HOST_CMD ); + outl(TLAN_HC_LD_TMR | 0x3f, dev->base_addr + TLAN_HOST_CMD); + outl(TLAN_HC_LD_THR | 0x9, dev->base_addr + TLAN_HOST_CMD); /* 6. Unreset the MII by setting NMRST (in NetSio) to 1. */ - outw( TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR ); + outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR); addr = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; - TLan_SetBit( TLAN_NET_SIO_NMRST, addr ); + tlan_set_bit(TLAN_NET_SIO_NMRST, addr); /* 7. Setup the remaining registers. */ - if ( priv->tlanRev >= 0x30 ) { + if (priv->tlan_rev >= 0x30) { data8 = TLAN_ID_TX_EOC | TLAN_ID_RX_EOC; - TLan_DioWrite8( dev->base_addr, TLAN_INT_DIS, data8 ); + tlan_dio_write8(dev->base_addr, TLAN_INT_DIS, data8); } - TLan_PhyDetect( dev ); + tlan_phy_detect(dev); data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN; - if ( priv->adapter->flags & TLAN_ADAPTER_BIT_RATE_PHY ) { + if (priv->adapter->flags & TLAN_ADAPTER_BIT_RATE_PHY) { data |= TLAN_NET_CFG_BIT; - if ( priv->aui == 1 ) { - TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x0a ); - } else if ( priv->duplex == TLAN_DUPLEX_FULL ) { - TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x00 ); - priv->tlanFullDuplex = true; + if (priv->aui == 1) { + tlan_dio_write8(dev->base_addr, TLAN_ACOMMIT, 0x0a); + } else if (priv->duplex == TLAN_DUPLEX_FULL) { + tlan_dio_write8(dev->base_addr, TLAN_ACOMMIT, 0x00); + priv->tlan_full_duplex = true; } else { - TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x08 ); + tlan_dio_write8(dev->base_addr, TLAN_ACOMMIT, 0x08); } } - if ( priv->phyNum == 0 ) { + if (priv->phy_num == 0) data |= TLAN_NET_CFG_PHY_EN; - } - TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, (u16) data ); + tlan_dio_write16(dev->base_addr, TLAN_NET_CONFIG, (u16) data); - if ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) { - TLan_FinishReset( dev ); - } else { - TLan_PhyPowerDown( dev ); - } + if (priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY) + tlan_finish_reset(dev); + else + tlan_phy_power_down(dev); -} /* TLan_ResetAdapter */ +} static void -TLan_FinishReset( struct net_device *dev ) +tlan_finish_reset(struct net_device *dev) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); u8 data; u32 phy; u8 sio; u16 status; u16 partner; u16 tlphy_ctl; - u16 tlphy_par; + u16 tlphy_par; u16 tlphy_id1, tlphy_id2; - int i; + int i; - phy = priv->phy[priv->phyNum]; + phy = priv->phy[priv->phy_num]; data = TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP; - if ( priv->tlanFullDuplex ) { + if (priv->tlan_full_duplex) data |= TLAN_NET_CMD_DUPLEX; - } - TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, data ); + tlan_dio_write8(dev->base_addr, TLAN_NET_CMD, data); data = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5; - if ( priv->phyNum == 0 ) { + if (priv->phy_num == 0) data |= TLAN_NET_MASK_MASK7; - } - TLan_DioWrite8( dev->base_addr, TLAN_NET_MASK, data ); - TLan_DioWrite16( dev->base_addr, TLAN_MAX_RX, ((1536)+7)&~7 ); - TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &tlphy_id1 ); - TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &tlphy_id2 ); + tlan_dio_write8(dev->base_addr, TLAN_NET_MASK, data); + tlan_dio_write16(dev->base_addr, TLAN_MAX_RX, ((1536)+7)&~7); + tlan_mii_read_reg(dev, phy, MII_GEN_ID_HI, &tlphy_id1); + tlan_mii_read_reg(dev, phy, MII_GEN_ID_LO, &tlphy_id2); - if ( ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) || - ( priv->aui ) ) { + if ((priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY) || + (priv->aui)) { status = MII_GS_LINK; - printk( "TLAN: %s: Link forced.\n", dev->name ); + pr_info("TLAN: %s: Link forced.\n", dev->name); } else { - TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); - udelay( 1000 ); - TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); - if ( (status & MII_GS_LINK) && - /* We only support link info on Nat.Sem. PHY's */ - (tlphy_id1 == NAT_SEM_ID1) && - (tlphy_id2 == NAT_SEM_ID2) ) { - TLan_MiiReadReg( dev, phy, MII_AN_LPA, &partner ); - TLan_MiiReadReg( dev, phy, TLAN_TLPHY_PAR, &tlphy_par ); - - printk( "TLAN: %s: Link active with ", dev->name ); + tlan_mii_read_reg(dev, phy, MII_GEN_STS, &status); + udelay(1000); + tlan_mii_read_reg(dev, phy, MII_GEN_STS, &status); + if ((status & MII_GS_LINK) && + /* We only support link info on Nat.Sem. PHY's */ + (tlphy_id1 == NAT_SEM_ID1) && + (tlphy_id2 == NAT_SEM_ID2)) { + tlan_mii_read_reg(dev, phy, MII_AN_LPA, &partner); + tlan_mii_read_reg(dev, phy, TLAN_TLPHY_PAR, &tlphy_par); + + pr_info("TLAN: %s: Link active with ", dev->name); if (!(tlphy_par & TLAN_PHY_AN_EN_STAT)) { - printk( "forced 10%sMbps %s-Duplex\n", - tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0", - tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half"); + pr_info("forced 10%sMbps %s-Duplex\n", + tlphy_par & TLAN_PHY_SPEED_100 + ? "" : "0", + tlphy_par & TLAN_PHY_DUPLEX_FULL + ? "Full" : "Half"); } else { - printk( "AutoNegotiation enabled, at 10%sMbps %s-Duplex\n", - tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0", - tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half"); - printk("TLAN: Partner capability: "); - for (i = 5; i <= 10; i++) - if (partner & (1<<i)) - printk("%s",media[i-5]); + pr_info("Autonegotiation enabled, at 10%sMbps %s-Duplex\n", + tlphy_par & TLAN_PHY_SPEED_100 + ? "" : "0", + tlphy_par & TLAN_PHY_DUPLEX_FULL + ? "Full" : "half"); + pr_info("TLAN: Partner capability: "); + for (i = 5; i <= 10; i++) + if (partner & (1<<i)) + printk("%s", media[i-5]); printk("\n"); } - TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK ); + tlan_dio_write8(dev->base_addr, TLAN_LED_REG, + TLAN_LED_LINK); #ifdef MONITOR /* We have link beat..for now anyway */ - priv->link = 1; - /*Enabling link beat monitoring */ - TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_LINK_BEAT ); + priv->link = 1; + /*Enabling link beat monitoring */ + tlan_set_timer(dev, (10*HZ), TLAN_TIMER_LINK_BEAT); #endif } else if (status & MII_GS_LINK) { - printk( "TLAN: %s: Link active\n", dev->name ); - TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK ); + pr_info("TLAN: %s: Link active\n", dev->name); + tlan_dio_write8(dev->base_addr, TLAN_LED_REG, + TLAN_LED_LINK); } } - if ( priv->phyNum == 0 ) { - TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl ); - tlphy_ctl |= TLAN_TC_INTEN; - TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl ); - sio = TLan_DioRead8( dev->base_addr, TLAN_NET_SIO ); - sio |= TLAN_NET_SIO_MINTEN; - TLan_DioWrite8( dev->base_addr, TLAN_NET_SIO, sio ); - } - - if ( status & MII_GS_LINK ) { - TLan_SetMac( dev, 0, dev->dev_addr ); - priv->phyOnline = 1; - outb( ( TLAN_HC_INT_ON >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 ); - if ( debug >= 1 && debug != TLAN_DEBUG_PROBE ) { - outb( ( TLAN_HC_REQ_INT >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 ); - } - outl( priv->rxListDMA, dev->base_addr + TLAN_CH_PARM ); - outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD ); + if (priv->phy_num == 0) { + tlan_mii_read_reg(dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl); + tlphy_ctl |= TLAN_TC_INTEN; + tlan_mii_write_reg(dev, phy, TLAN_TLPHY_CTL, tlphy_ctl); + sio = tlan_dio_read8(dev->base_addr, TLAN_NET_SIO); + sio |= TLAN_NET_SIO_MINTEN; + tlan_dio_write8(dev->base_addr, TLAN_NET_SIO, sio); + } + + if (status & MII_GS_LINK) { + tlan_set_mac(dev, 0, dev->dev_addr); + priv->phy_online = 1; + outb((TLAN_HC_INT_ON >> 8), dev->base_addr + TLAN_HOST_CMD + 1); + if (debug >= 1 && debug != TLAN_DEBUG_PROBE) + outb((TLAN_HC_REQ_INT >> 8), + dev->base_addr + TLAN_HOST_CMD + 1); + outl(priv->rx_list_dma, dev->base_addr + TLAN_CH_PARM); + outl(TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD); netif_carrier_on(dev); } else { - printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n", - dev->name ); - TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_FINISH_RESET ); + pr_info("TLAN: %s: Link inactive, will retry in 10 secs...\n", + dev->name); + tlan_set_timer(dev, (10*HZ), TLAN_TIMER_FINISH_RESET); return; } - TLan_SetMulticastList(dev); + tlan_set_multicast_list(dev); -} /* TLan_FinishReset */ +} - /*************************************************************** - * TLan_SetMac - * - * Returns: - * Nothing - * Parms: - * dev Pointer to device structure of adapter - * on which to change the AREG. - * areg The AREG to set the address in (0 - 3). - * mac A pointer to an array of chars. Each - * element stores one byte of the address. - * IE, it isn't in ascii. - * - * This function transfers a MAC address to one of the - * TLAN AREGs (address registers). The TLAN chip locks - * the register on writing to offset 0 and unlocks the - * register after writing to offset 5. If NULL is passed - * in mac, then the AREG is filled with 0's. - * - **************************************************************/ +/*************************************************************** + * tlan_set_mac + * + * Returns: + * Nothing + * Parms: + * dev Pointer to device structure of adapter + * on which to change the AREG. + * areg The AREG to set the address in (0 - 3). + * mac A pointer to an array of chars. Each + * element stores one byte of the address. + * IE, it isn't in ascii. + * + * This function transfers a MAC address to one of the + * TLAN AREGs (address registers). The TLAN chip locks + * the register on writing to offset 0 and unlocks the + * register after writing to offset 5. If NULL is passed + * in mac, then the AREG is filled with 0's. + * + **************************************************************/ -static void TLan_SetMac( struct net_device *dev, int areg, char *mac ) +static void tlan_set_mac(struct net_device *dev, int areg, char *mac) { int i; areg *= 6; - if ( mac != NULL ) { - for ( i = 0; i < 6; i++ ) - TLan_DioWrite8( dev->base_addr, - TLAN_AREG_0 + areg + i, mac[i] ); + if (mac != NULL) { + for (i = 0; i < 6; i++) + tlan_dio_write8(dev->base_addr, + TLAN_AREG_0 + areg + i, mac[i]); } else { - for ( i = 0; i < 6; i++ ) - TLan_DioWrite8( dev->base_addr, - TLAN_AREG_0 + areg + i, 0 ); + for (i = 0; i < 6; i++) + tlan_dio_write8(dev->base_addr, + TLAN_AREG_0 + areg + i, 0); } -} /* TLan_SetMac */ +} @@ -2432,205 +2524,202 @@ static void TLan_SetMac( struct net_device *dev, int areg, char *mac ) /***************************************************************************** ****************************************************************************** - ThunderLAN Driver PHY Layer Routines +ThunderLAN driver PHY layer routines ****************************************************************************** *****************************************************************************/ - /********************************************************************* - * TLan_PhyPrint - * - * Returns: - * Nothing - * Parms: - * dev A pointer to the device structure of the - * TLAN device having the PHYs to be detailed. - * - * This function prints the registers a PHY (aka transceiver). - * - ********************************************************************/ +/********************************************************************* + * tlan_phy_print + * + * Returns: + * Nothing + * Parms: + * dev A pointer to the device structure of the + * TLAN device having the PHYs to be detailed. + * + * This function prints the registers a PHY (aka transceiver). + * + ********************************************************************/ -static void TLan_PhyPrint( struct net_device *dev ) +static void tlan_phy_print(struct net_device *dev) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); u16 i, data0, data1, data2, data3, phy; - phy = priv->phy[priv->phyNum]; - - if ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) { - printk( "TLAN: Device %s, Unmanaged PHY.\n", dev->name ); - } else if ( phy <= TLAN_PHY_MAX_ADDR ) { - printk( "TLAN: Device %s, PHY 0x%02x.\n", dev->name, phy ); - printk( "TLAN: Off. +0 +1 +2 +3\n" ); - for ( i = 0; i < 0x20; i+= 4 ) { - printk( "TLAN: 0x%02x", i ); - TLan_MiiReadReg( dev, phy, i, &data0 ); - printk( " 0x%04hx", data0 ); - TLan_MiiReadReg( dev, phy, i + 1, &data1 ); - printk( " 0x%04hx", data1 ); - TLan_MiiReadReg( dev, phy, i + 2, &data2 ); - printk( " 0x%04hx", data2 ); - TLan_MiiReadReg( dev, phy, i + 3, &data3 ); - printk( " 0x%04hx\n", data3 ); + phy = priv->phy[priv->phy_num]; + + if (priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY) { + pr_info("TLAN: Device %s, Unmanaged PHY.\n", dev->name); + } else if (phy <= TLAN_PHY_MAX_ADDR) { + pr_info("TLAN: Device %s, PHY 0x%02x.\n", dev->name, phy); + pr_info("TLAN: Off. +0 +1 +2 +3\n"); + for (i = 0; i < 0x20; i += 4) { + pr_info("TLAN: 0x%02x", i); + tlan_mii_read_reg(dev, phy, i, &data0); + printk(" 0x%04hx", data0); + tlan_mii_read_reg(dev, phy, i + 1, &data1); + printk(" 0x%04hx", data1); + tlan_mii_read_reg(dev, phy, i + 2, &data2); + printk(" 0x%04hx", data2); + tlan_mii_read_reg(dev, phy, i + 3, &data3); + printk(" 0x%04hx\n", data3); } } else { - printk( "TLAN: Device %s, Invalid PHY.\n", dev->name ); + pr_info("TLAN: Device %s, Invalid PHY.\n", dev->name); } -} /* TLan_PhyPrint */ +} - /********************************************************************* - * TLan_PhyDetect - * - * Returns: - * Nothing - * Parms: - * dev A pointer to the device structure of the adapter - * for which the PHY needs determined. - * - * So far I've found that adapters which have external PHYs - * may also use the internal PHY for part of the functionality. - * (eg, AUI/Thinnet). This function finds out if this TLAN - * chip has an internal PHY, and then finds the first external - * PHY (starting from address 0) if it exists). - * - ********************************************************************/ +/********************************************************************* + * tlan_phy_detect + * + * Returns: + * Nothing + * Parms: + * dev A pointer to the device structure of the adapter + * for which the PHY needs determined. + * + * So far I've found that adapters which have external PHYs + * may also use the internal PHY for part of the functionality. + * (eg, AUI/Thinnet). This function finds out if this TLAN + * chip has an internal PHY, and then finds the first external + * PHY (starting from address 0) if it exists). + * + ********************************************************************/ -static void TLan_PhyDetect( struct net_device *dev ) +static void tlan_phy_detect(struct net_device *dev) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); u16 control; u16 hi; u16 lo; u32 phy; - if ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) { - priv->phyNum = 0xFFFF; + if (priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY) { + priv->phy_num = 0xffff; return; } - TLan_MiiReadReg( dev, TLAN_PHY_MAX_ADDR, MII_GEN_ID_HI, &hi ); + tlan_mii_read_reg(dev, TLAN_PHY_MAX_ADDR, MII_GEN_ID_HI, &hi); - if ( hi != 0xFFFF ) { + if (hi != 0xffff) priv->phy[0] = TLAN_PHY_MAX_ADDR; - } else { + else priv->phy[0] = TLAN_PHY_NONE; - } priv->phy[1] = TLAN_PHY_NONE; - for ( phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++ ) { - TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &control ); - TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &hi ); - TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &lo ); - if ( ( control != 0xFFFF ) || - ( hi != 0xFFFF ) || ( lo != 0xFFFF ) ) { - TLAN_DBG( TLAN_DEBUG_GNRL, - "PHY found at %02x %04x %04x %04x\n", - phy, control, hi, lo ); - if ( ( priv->phy[1] == TLAN_PHY_NONE ) && - ( phy != TLAN_PHY_MAX_ADDR ) ) { + for (phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++) { + tlan_mii_read_reg(dev, phy, MII_GEN_CTL, &control); + tlan_mii_read_reg(dev, phy, MII_GEN_ID_HI, &hi); + tlan_mii_read_reg(dev, phy, MII_GEN_ID_LO, &lo); + if ((control != 0xffff) || + (hi != 0xffff) || (lo != 0xffff)) { + TLAN_DBG(TLAN_DEBUG_GNRL, + "PHY found at %02x %04x %04x %04x\n", + phy, control, hi, lo); + if ((priv->phy[1] == TLAN_PHY_NONE) && + (phy != TLAN_PHY_MAX_ADDR)) { priv->phy[1] = phy; } } } - if ( priv->phy[1] != TLAN_PHY_NONE ) { - priv->phyNum = 1; - } else if ( priv->phy[0] != TLAN_PHY_NONE ) { - priv->phyNum = 0; - } else { - printk( "TLAN: Cannot initialize device, no PHY was found!\n" ); - } + if (priv->phy[1] != TLAN_PHY_NONE) + priv->phy_num = 1; + else if (priv->phy[0] != TLAN_PHY_NONE) + priv->phy_num = 0; + else + pr_info("TLAN: Cannot initialize device, no PHY was found!\n"); -} /* TLan_PhyDetect */ +} -static void TLan_PhyPowerDown( struct net_device *dev ) +static void tlan_phy_power_down(struct net_device *dev) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); u16 value; - TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Powering down PHY(s).\n", dev->name ); + TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Powering down PHY(s).\n", dev->name); value = MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE; - TLan_MiiSync( dev->base_addr ); - TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value ); - if ( ( priv->phyNum == 0 ) && - ( priv->phy[1] != TLAN_PHY_NONE ) && - ( ! ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) ) ) { - TLan_MiiSync( dev->base_addr ); - TLan_MiiWriteReg( dev, priv->phy[1], MII_GEN_CTL, value ); + tlan_mii_sync(dev->base_addr); + tlan_mii_write_reg(dev, priv->phy[priv->phy_num], MII_GEN_CTL, value); + if ((priv->phy_num == 0) && + (priv->phy[1] != TLAN_PHY_NONE) && + (!(priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10))) { + tlan_mii_sync(dev->base_addr); + tlan_mii_write_reg(dev, priv->phy[1], MII_GEN_CTL, value); } /* Wait for 50 ms and powerup * This is abitrary. It is intended to make sure the * transceiver settles. */ - TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_PUP ); + tlan_set_timer(dev, (HZ/20), TLAN_TIMER_PHY_PUP); -} /* TLan_PhyPowerDown */ +} -static void TLan_PhyPowerUp( struct net_device *dev ) +static void tlan_phy_power_up(struct net_device *dev) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); u16 value; - TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Powering up PHY.\n", dev->name ); - TLan_MiiSync( dev->base_addr ); + TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Powering up PHY.\n", dev->name); + tlan_mii_sync(dev->base_addr); value = MII_GC_LOOPBK; - TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value ); - TLan_MiiSync(dev->base_addr); + tlan_mii_write_reg(dev, priv->phy[priv->phy_num], MII_GEN_CTL, value); + tlan_mii_sync(dev->base_addr); /* Wait for 500 ms and reset the * transceiver. The TLAN docs say both 50 ms and * 500 ms, so do the longer, just in case. */ - TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_RESET ); + tlan_set_timer(dev, (HZ/20), TLAN_TIMER_PHY_RESET); -} /* TLan_PhyPowerUp */ +} -static void TLan_PhyReset( struct net_device *dev ) +static void tlan_phy_reset(struct net_device *dev) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); u16 phy; u16 value; - phy = priv->phy[priv->phyNum]; + phy = priv->phy[priv->phy_num]; - TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Reseting PHY.\n", dev->name ); - TLan_MiiSync( dev->base_addr ); + TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Reseting PHY.\n", dev->name); + tlan_mii_sync(dev->base_addr); value = MII_GC_LOOPBK | MII_GC_RESET; - TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, value ); - TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &value ); - while ( value & MII_GC_RESET ) { - TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &value ); - } + tlan_mii_write_reg(dev, phy, MII_GEN_CTL, value); + tlan_mii_read_reg(dev, phy, MII_GEN_CTL, &value); + while (value & MII_GC_RESET) + tlan_mii_read_reg(dev, phy, MII_GEN_CTL, &value); /* Wait for 500 ms and initialize. * I don't remember why I wait this long. * I've changed this to 50ms, as it seems long enough. */ - TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_START_LINK ); + tlan_set_timer(dev, (HZ/20), TLAN_TIMER_PHY_START_LINK); -} /* TLan_PhyReset */ +} -static void TLan_PhyStartLink( struct net_device *dev ) +static void tlan_phy_start_link(struct net_device *dev) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); u16 ability; u16 control; u16 data; @@ -2638,86 +2727,88 @@ static void TLan_PhyStartLink( struct net_device *dev ) u16 status; u16 tctl; - phy = priv->phy[priv->phyNum]; - TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Trying to activate link.\n", dev->name ); - TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); - TLan_MiiReadReg( dev, phy, MII_GEN_STS, &ability ); + phy = priv->phy[priv->phy_num]; + TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Trying to activate link.\n", dev->name); + tlan_mii_read_reg(dev, phy, MII_GEN_STS, &status); + tlan_mii_read_reg(dev, phy, MII_GEN_STS, &ability); - if ( ( status & MII_GS_AUTONEG ) && - ( ! priv->aui ) ) { + if ((status & MII_GS_AUTONEG) && + (!priv->aui)) { ability = status >> 11; - if ( priv->speed == TLAN_SPEED_10 && - priv->duplex == TLAN_DUPLEX_HALF) { - TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0000); - } else if ( priv->speed == TLAN_SPEED_10 && - priv->duplex == TLAN_DUPLEX_FULL) { - priv->tlanFullDuplex = true; - TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0100); - } else if ( priv->speed == TLAN_SPEED_100 && - priv->duplex == TLAN_DUPLEX_HALF) { - TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2000); - } else if ( priv->speed == TLAN_SPEED_100 && - priv->duplex == TLAN_DUPLEX_FULL) { - priv->tlanFullDuplex = true; - TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2100); + if (priv->speed == TLAN_SPEED_10 && + priv->duplex == TLAN_DUPLEX_HALF) { + tlan_mii_write_reg(dev, phy, MII_GEN_CTL, 0x0000); + } else if (priv->speed == TLAN_SPEED_10 && + priv->duplex == TLAN_DUPLEX_FULL) { + priv->tlan_full_duplex = true; + tlan_mii_write_reg(dev, phy, MII_GEN_CTL, 0x0100); + } else if (priv->speed == TLAN_SPEED_100 && + priv->duplex == TLAN_DUPLEX_HALF) { + tlan_mii_write_reg(dev, phy, MII_GEN_CTL, 0x2000); + } else if (priv->speed == TLAN_SPEED_100 && + priv->duplex == TLAN_DUPLEX_FULL) { + priv->tlan_full_duplex = true; + tlan_mii_write_reg(dev, phy, MII_GEN_CTL, 0x2100); } else { /* Set Auto-Neg advertisement */ - TLan_MiiWriteReg( dev, phy, MII_AN_ADV, (ability << 5) | 1); + tlan_mii_write_reg(dev, phy, MII_AN_ADV, + (ability << 5) | 1); /* Enablee Auto-Neg */ - TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1000 ); + tlan_mii_write_reg(dev, phy, MII_GEN_CTL, 0x1000); /* Restart Auto-Neg */ - TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1200 ); + tlan_mii_write_reg(dev, phy, MII_GEN_CTL, 0x1200); /* Wait for 4 sec for autonegotiation - * to complete. The max spec time is less than this - * but the card need additional time to start AN. - * .5 sec should be plenty extra. - */ - printk( "TLAN: %s: Starting autonegotiation.\n", dev->name ); - TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_PHY_FINISH_AN ); + * to complete. The max spec time is less than this + * but the card need additional time to start AN. + * .5 sec should be plenty extra. + */ + pr_info("TLAN: %s: Starting autonegotiation.\n", + dev->name); + tlan_set_timer(dev, (2*HZ), TLAN_TIMER_PHY_FINISH_AN); return; } } - if ( ( priv->aui ) && ( priv->phyNum != 0 ) ) { - priv->phyNum = 0; - data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN; - TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data ); - TLan_SetTimer( dev, (40*HZ/1000), TLAN_TIMER_PHY_PDOWN ); + if ((priv->aui) && (priv->phy_num != 0)) { + priv->phy_num = 0; + data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN + | TLAN_NET_CFG_PHY_EN; + tlan_dio_write16(dev->base_addr, TLAN_NET_CONFIG, data); + tlan_set_timer(dev, (40*HZ/1000), TLAN_TIMER_PHY_PDOWN); return; - } else if ( priv->phyNum == 0 ) { + } else if (priv->phy_num == 0) { control = 0; - TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tctl ); - if ( priv->aui ) { - tctl |= TLAN_TC_AUISEL; + tlan_mii_read_reg(dev, phy, TLAN_TLPHY_CTL, &tctl); + if (priv->aui) { + tctl |= TLAN_TC_AUISEL; } else { - tctl &= ~TLAN_TC_AUISEL; - if ( priv->duplex == TLAN_DUPLEX_FULL ) { + tctl &= ~TLAN_TC_AUISEL; + if (priv->duplex == TLAN_DUPLEX_FULL) { control |= MII_GC_DUPLEX; - priv->tlanFullDuplex = true; + priv->tlan_full_duplex = true; } - if ( priv->speed == TLAN_SPEED_100 ) { + if (priv->speed == TLAN_SPEED_100) control |= MII_GC_SPEEDSEL; - } } - TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, control ); - TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tctl ); + tlan_mii_write_reg(dev, phy, MII_GEN_CTL, control); + tlan_mii_write_reg(dev, phy, TLAN_TLPHY_CTL, tctl); } /* Wait for 2 sec to give the transceiver time * to establish link. */ - TLan_SetTimer( dev, (4*HZ), TLAN_TIMER_FINISH_RESET ); + tlan_set_timer(dev, (4*HZ), TLAN_TIMER_FINISH_RESET); -} /* TLan_PhyStartLink */ +} -static void TLan_PhyFinishAutoNeg( struct net_device *dev ) +static void tlan_phy_finish_auto_neg(struct net_device *dev) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); u16 an_adv; u16 an_lpa; u16 data; @@ -2725,115 +2816,118 @@ static void TLan_PhyFinishAutoNeg( struct net_device *dev ) u16 phy; u16 status; - phy = priv->phy[priv->phyNum]; + phy = priv->phy[priv->phy_num]; - TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); - udelay( 1000 ); - TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); + tlan_mii_read_reg(dev, phy, MII_GEN_STS, &status); + udelay(1000); + tlan_mii_read_reg(dev, phy, MII_GEN_STS, &status); - if ( ! ( status & MII_GS_AUTOCMPLT ) ) { + if (!(status & MII_GS_AUTOCMPLT)) { /* Wait for 8 sec to give the process * more time. Perhaps we should fail after a while. */ - if (!priv->neg_be_verbose++) { - pr_info("TLAN: Giving autonegotiation more time.\n"); - pr_info("TLAN: Please check that your adapter has\n"); - pr_info("TLAN: been properly connected to a HUB or Switch.\n"); - pr_info("TLAN: Trying to establish link in the background...\n"); - } - TLan_SetTimer( dev, (8*HZ), TLAN_TIMER_PHY_FINISH_AN ); + if (!priv->neg_be_verbose++) { + pr_info("TLAN: Giving autonegotiation more time.\n"); + pr_info("TLAN: Please check that your adapter has\n"); + pr_info("TLAN: been properly connected to a HUB or Switch.\n"); + pr_info("TLAN: Trying to establish link in the background...\n"); + } + tlan_set_timer(dev, (8*HZ), TLAN_TIMER_PHY_FINISH_AN); return; } - printk( "TLAN: %s: Autonegotiation complete.\n", dev->name ); - TLan_MiiReadReg( dev, phy, MII_AN_ADV, &an_adv ); - TLan_MiiReadReg( dev, phy, MII_AN_LPA, &an_lpa ); + pr_info("TLAN: %s: Autonegotiation complete.\n", dev->name); + tlan_mii_read_reg(dev, phy, MII_AN_ADV, &an_adv); + tlan_mii_read_reg(dev, phy, MII_AN_LPA, &an_lpa); mode = an_adv & an_lpa & 0x03E0; - if ( mode & 0x0100 ) { - priv->tlanFullDuplex = true; - } else if ( ! ( mode & 0x0080 ) && ( mode & 0x0040 ) ) { - priv->tlanFullDuplex = true; - } - - if ( ( ! ( mode & 0x0180 ) ) && - ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) && - ( priv->phyNum != 0 ) ) { - priv->phyNum = 0; - data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN; - TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data ); - TLan_SetTimer( dev, (400*HZ/1000), TLAN_TIMER_PHY_PDOWN ); + if (mode & 0x0100) + priv->tlan_full_duplex = true; + else if (!(mode & 0x0080) && (mode & 0x0040)) + priv->tlan_full_duplex = true; + + if ((!(mode & 0x0180)) && + (priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10) && + (priv->phy_num != 0)) { + priv->phy_num = 0; + data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN + | TLAN_NET_CFG_PHY_EN; + tlan_dio_write16(dev->base_addr, TLAN_NET_CONFIG, data); + tlan_set_timer(dev, (400*HZ/1000), TLAN_TIMER_PHY_PDOWN); return; } - if ( priv->phyNum == 0 ) { - if ( ( priv->duplex == TLAN_DUPLEX_FULL ) || - ( an_adv & an_lpa & 0x0040 ) ) { - TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, - MII_GC_AUTOENB | MII_GC_DUPLEX ); - pr_info("TLAN: Starting internal PHY with FULL-DUPLEX\n" ); + if (priv->phy_num == 0) { + if ((priv->duplex == TLAN_DUPLEX_FULL) || + (an_adv & an_lpa & 0x0040)) { + tlan_mii_write_reg(dev, phy, MII_GEN_CTL, + MII_GC_AUTOENB | MII_GC_DUPLEX); + pr_info("TLAN: Starting internal PHY with FULL-DUPLEX\n"); } else { - TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB ); - pr_info( "TLAN: Starting internal PHY with HALF-DUPLEX\n" ); + tlan_mii_write_reg(dev, phy, MII_GEN_CTL, + MII_GC_AUTOENB); + pr_info("TLAN: Starting internal PHY with HALF-DUPLEX\n"); } } /* Wait for 100 ms. No reason in partiticular. */ - TLan_SetTimer( dev, (HZ/10), TLAN_TIMER_FINISH_RESET ); + tlan_set_timer(dev, (HZ/10), TLAN_TIMER_FINISH_RESET); -} /* TLan_PhyFinishAutoNeg */ +} #ifdef MONITOR - /********************************************************************* - * - * TLan_phyMonitor - * - * Returns: - * None - * - * Params: - * dev The device structure of this device. - * - * - * This function monitors PHY condition by reading the status - * register via the MII bus. This can be used to give info - * about link changes (up/down), and possible switch to alternate - * media. - * - * ******************************************************************/ - -void TLan_PhyMonitor( struct net_device *dev ) +/********************************************************************* + * + * tlan_phy_monitor + * + * Returns: + * None + * + * Params: + * dev The device structure of this device. + * + * + * This function monitors PHY condition by reading the status + * register via the MII bus. This can be used to give info + * about link changes (up/down), and possible switch to alternate + * media. + * + *******************************************************************/ + +void tlan_phy_monitor(struct net_device *dev) { - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); u16 phy; u16 phy_status; - phy = priv->phy[priv->phyNum]; + phy = priv->phy[priv->phy_num]; - /* Get PHY status register */ - TLan_MiiReadReg( dev, phy, MII_GEN_STS, &phy_status ); + /* Get PHY status register */ + tlan_mii_read_reg(dev, phy, MII_GEN_STS, &phy_status); - /* Check if link has been lost */ - if (!(phy_status & MII_GS_LINK)) { - if (priv->link) { - priv->link = 0; - printk(KERN_DEBUG "TLAN: %s has lost link\n", dev->name); - netif_carrier_off(dev); - TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); - return; + /* Check if link has been lost */ + if (!(phy_status & MII_GS_LINK)) { + if (priv->link) { + priv->link = 0; + printk(KERN_DEBUG "TLAN: %s has lost link\n", + dev->name); + netif_carrier_off(dev); + tlan_set_timer(dev, (2*HZ), TLAN_TIMER_LINK_BEAT); + return; } } - /* Link restablished? */ - if ((phy_status & MII_GS_LINK) && !priv->link) { - priv->link = 1; - printk(KERN_DEBUG "TLAN: %s has reestablished link\n", dev->name); + /* Link restablished? */ + if ((phy_status & MII_GS_LINK) && !priv->link) { + priv->link = 1; + printk(KERN_DEBUG "TLAN: %s has reestablished link\n", + dev->name); netif_carrier_on(dev); - } + } /* Setup a new monitor */ - TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); + tlan_set_timer(dev, (2*HZ), TLAN_TIMER_LINK_BEAT); } #endif /* MONITOR */ @@ -2842,47 +2936,48 @@ void TLan_PhyMonitor( struct net_device *dev ) /***************************************************************************** ****************************************************************************** - ThunderLAN Driver MII Routines +ThunderLAN driver MII routines - These routines are based on the information in Chap. 2 of the - "ThunderLAN Programmer's Guide", pp. 15-24. +these routines are based on the information in chap. 2 of the +"ThunderLAN Programmer's Guide", pp. 15-24. ****************************************************************************** *****************************************************************************/ - /*************************************************************** - * TLan_MiiReadReg - * - * Returns: - * false if ack received ok - * true if no ack received or other error - * - * Parms: - * dev The device structure containing - * The io address and interrupt count - * for this device. - * phy The address of the PHY to be queried. - * reg The register whose contents are to be - * retrieved. - * val A pointer to a variable to store the - * retrieved value. - * - * This function uses the TLAN's MII bus to retrieve the contents - * of a given register on a PHY. It sends the appropriate info - * and then reads the 16-bit register value from the MII bus via - * the TLAN SIO register. - * - **************************************************************/ - -static bool TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val ) +/*************************************************************** + * tlan_mii_read_reg + * + * Returns: + * false if ack received ok + * true if no ack received or other error + * + * Parms: + * dev The device structure containing + * The io address and interrupt count + * for this device. + * phy The address of the PHY to be queried. + * reg The register whose contents are to be + * retrieved. + * val A pointer to a variable to store the + * retrieved value. + * + * This function uses the TLAN's MII bus to retrieve the contents + * of a given register on a PHY. It sends the appropriate info + * and then reads the 16-bit register value from the MII bus via + * the TLAN SIO register. + * + **************************************************************/ + +static bool +tlan_mii_read_reg(struct net_device *dev, u16 phy, u16 reg, u16 *val) { u8 nack; u16 sio, tmp; - u32 i; + u32 i; bool err; int minten; - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); unsigned long flags = 0; err = false; @@ -2892,48 +2987,48 @@ static bool TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val if (!in_irq()) spin_lock_irqsave(&priv->lock, flags); - TLan_MiiSync(dev->base_addr); + tlan_mii_sync(dev->base_addr); - minten = TLan_GetBit( TLAN_NET_SIO_MINTEN, sio ); - if ( minten ) - TLan_ClearBit(TLAN_NET_SIO_MINTEN, sio); + minten = tlan_get_bit(TLAN_NET_SIO_MINTEN, sio); + if (minten) + tlan_clear_bit(TLAN_NET_SIO_MINTEN, sio); - TLan_MiiSendData( dev->base_addr, 0x1, 2 ); /* Start ( 01b ) */ - TLan_MiiSendData( dev->base_addr, 0x2, 2 ); /* Read ( 10b ) */ - TLan_MiiSendData( dev->base_addr, phy, 5 ); /* Device # */ - TLan_MiiSendData( dev->base_addr, reg, 5 ); /* Register # */ + tlan_mii_send_data(dev->base_addr, 0x1, 2); /* start (01b) */ + tlan_mii_send_data(dev->base_addr, 0x2, 2); /* read (10b) */ + tlan_mii_send_data(dev->base_addr, phy, 5); /* device # */ + tlan_mii_send_data(dev->base_addr, reg, 5); /* register # */ - TLan_ClearBit(TLAN_NET_SIO_MTXEN, sio); /* Change direction */ + tlan_clear_bit(TLAN_NET_SIO_MTXEN, sio); /* change direction */ - TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Clock Idle bit */ - TLan_SetBit(TLAN_NET_SIO_MCLK, sio); - TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Wait 300ns */ + tlan_clear_bit(TLAN_NET_SIO_MCLK, sio); /* clock idle bit */ + tlan_set_bit(TLAN_NET_SIO_MCLK, sio); + tlan_clear_bit(TLAN_NET_SIO_MCLK, sio); /* wait 300ns */ - nack = TLan_GetBit(TLAN_NET_SIO_MDATA, sio); /* Check for ACK */ - TLan_SetBit(TLAN_NET_SIO_MCLK, sio); /* Finish ACK */ - if (nack) { /* No ACK, so fake it */ + nack = tlan_get_bit(TLAN_NET_SIO_MDATA, sio); /* check for ACK */ + tlan_set_bit(TLAN_NET_SIO_MCLK, sio); /* finish ACK */ + if (nack) { /* no ACK, so fake it */ for (i = 0; i < 16; i++) { - TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); - TLan_SetBit(TLAN_NET_SIO_MCLK, sio); + tlan_clear_bit(TLAN_NET_SIO_MCLK, sio); + tlan_set_bit(TLAN_NET_SIO_MCLK, sio); } tmp = 0xffff; err = true; } else { /* ACK, so read data */ for (tmp = 0, i = 0x8000; i; i >>= 1) { - TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); - if (TLan_GetBit(TLAN_NET_SIO_MDATA, sio)) + tlan_clear_bit(TLAN_NET_SIO_MCLK, sio); + if (tlan_get_bit(TLAN_NET_SIO_MDATA, sio)) tmp |= i; - TLan_SetBit(TLAN_NET_SIO_MCLK, sio); + tlan_set_bit(TLAN_NET_SIO_MCLK, sio); } } - TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Idle cycle */ - TLan_SetBit(TLAN_NET_SIO_MCLK, sio); + tlan_clear_bit(TLAN_NET_SIO_MCLK, sio); /* idle cycle */ + tlan_set_bit(TLAN_NET_SIO_MCLK, sio); - if ( minten ) - TLan_SetBit(TLAN_NET_SIO_MINTEN, sio); + if (minten) + tlan_set_bit(TLAN_NET_SIO_MINTEN, sio); *val = tmp; @@ -2942,116 +3037,117 @@ static bool TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val return err; -} /* TLan_MiiReadReg */ +} - /*************************************************************** - * TLan_MiiSendData - * - * Returns: - * Nothing - * Parms: - * base_port The base IO port of the adapter in - * question. - * dev The address of the PHY to be queried. - * data The value to be placed on the MII bus. - * num_bits The number of bits in data that are to - * be placed on the MII bus. - * - * This function sends on sequence of bits on the MII - * configuration bus. - * - **************************************************************/ +/*************************************************************** + * tlan_mii_send_data + * + * Returns: + * Nothing + * Parms: + * base_port The base IO port of the adapter in + * question. + * dev The address of the PHY to be queried. + * data The value to be placed on the MII bus. + * num_bits The number of bits in data that are to + * be placed on the MII bus. + * + * This function sends on sequence of bits on the MII + * configuration bus. + * + **************************************************************/ -static void TLan_MiiSendData( u16 base_port, u32 data, unsigned num_bits ) +static void tlan_mii_send_data(u16 base_port, u32 data, unsigned num_bits) { u16 sio; u32 i; - if ( num_bits == 0 ) + if (num_bits == 0) return; - outw( TLAN_NET_SIO, base_port + TLAN_DIO_ADR ); + outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR); sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO; - TLan_SetBit( TLAN_NET_SIO_MTXEN, sio ); + tlan_set_bit(TLAN_NET_SIO_MTXEN, sio); - for ( i = ( 0x1 << ( num_bits - 1 ) ); i; i >>= 1 ) { - TLan_ClearBit( TLAN_NET_SIO_MCLK, sio ); - (void) TLan_GetBit( TLAN_NET_SIO_MCLK, sio ); - if ( data & i ) - TLan_SetBit( TLAN_NET_SIO_MDATA, sio ); + for (i = (0x1 << (num_bits - 1)); i; i >>= 1) { + tlan_clear_bit(TLAN_NET_SIO_MCLK, sio); + (void) tlan_get_bit(TLAN_NET_SIO_MCLK, sio); + if (data & i) + tlan_set_bit(TLAN_NET_SIO_MDATA, sio); else - TLan_ClearBit( TLAN_NET_SIO_MDATA, sio ); - TLan_SetBit( TLAN_NET_SIO_MCLK, sio ); - (void) TLan_GetBit( TLAN_NET_SIO_MCLK, sio ); + tlan_clear_bit(TLAN_NET_SIO_MDATA, sio); + tlan_set_bit(TLAN_NET_SIO_MCLK, sio); + (void) tlan_get_bit(TLAN_NET_SIO_MCLK, sio); } -} /* TLan_MiiSendData */ +} - /*************************************************************** - * TLan_MiiSync - * - * Returns: - * Nothing - * Parms: - * base_port The base IO port of the adapter in - * question. - * - * This functions syncs all PHYs in terms of the MII configuration - * bus. - * - **************************************************************/ +/*************************************************************** + * TLan_MiiSync + * + * Returns: + * Nothing + * Parms: + * base_port The base IO port of the adapter in + * question. + * + * This functions syncs all PHYs in terms of the MII configuration + * bus. + * + **************************************************************/ -static void TLan_MiiSync( u16 base_port ) +static void tlan_mii_sync(u16 base_port) { int i; u16 sio; - outw( TLAN_NET_SIO, base_port + TLAN_DIO_ADR ); + outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR); sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO; - TLan_ClearBit( TLAN_NET_SIO_MTXEN, sio ); - for ( i = 0; i < 32; i++ ) { - TLan_ClearBit( TLAN_NET_SIO_MCLK, sio ); - TLan_SetBit( TLAN_NET_SIO_MCLK, sio ); + tlan_clear_bit(TLAN_NET_SIO_MTXEN, sio); + for (i = 0; i < 32; i++) { + tlan_clear_bit(TLAN_NET_SIO_MCLK, sio); + tlan_set_bit(TLAN_NET_SIO_MCLK, sio); } -} /* TLan_MiiSync */ +} - /*************************************************************** - * TLan_MiiWriteReg - * - * Returns: - * Nothing - * Parms: - * dev The device structure for the device - * to write to. - * phy The address of the PHY to be written to. - * reg The register whose contents are to be - * written. - * val The value to be written to the register. - * - * This function uses the TLAN's MII bus to write the contents of a - * given register on a PHY. It sends the appropriate info and then - * writes the 16-bit register value from the MII configuration bus - * via the TLAN SIO register. - * - **************************************************************/ +/*************************************************************** + * tlan_mii_write_reg + * + * Returns: + * Nothing + * Parms: + * dev The device structure for the device + * to write to. + * phy The address of the PHY to be written to. + * reg The register whose contents are to be + * written. + * val The value to be written to the register. + * + * This function uses the TLAN's MII bus to write the contents of a + * given register on a PHY. It sends the appropriate info and then + * writes the 16-bit register value from the MII configuration bus + * via the TLAN SIO register. + * + **************************************************************/ -static void TLan_MiiWriteReg( struct net_device *dev, u16 phy, u16 reg, u16 val ) +static void +tlan_mii_write_reg(struct net_device *dev, u16 phy, u16 reg, u16 val) { u16 sio; int minten; unsigned long flags = 0; - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR); sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; @@ -3059,30 +3155,30 @@ static void TLan_MiiWriteReg( struct net_device *dev, u16 phy, u16 reg, u16 val if (!in_irq()) spin_lock_irqsave(&priv->lock, flags); - TLan_MiiSync( dev->base_addr ); + tlan_mii_sync(dev->base_addr); - minten = TLan_GetBit( TLAN_NET_SIO_MINTEN, sio ); - if ( minten ) - TLan_ClearBit( TLAN_NET_SIO_MINTEN, sio ); + minten = tlan_get_bit(TLAN_NET_SIO_MINTEN, sio); + if (minten) + tlan_clear_bit(TLAN_NET_SIO_MINTEN, sio); - TLan_MiiSendData( dev->base_addr, 0x1, 2 ); /* Start ( 01b ) */ - TLan_MiiSendData( dev->base_addr, 0x1, 2 ); /* Write ( 01b ) */ - TLan_MiiSendData( dev->base_addr, phy, 5 ); /* Device # */ - TLan_MiiSendData( dev->base_addr, reg, 5 ); /* Register # */ + tlan_mii_send_data(dev->base_addr, 0x1, 2); /* start (01b) */ + tlan_mii_send_data(dev->base_addr, 0x1, 2); /* write (01b) */ + tlan_mii_send_data(dev->base_addr, phy, 5); /* device # */ + tlan_mii_send_data(dev->base_addr, reg, 5); /* register # */ - TLan_MiiSendData( dev->base_addr, 0x2, 2 ); /* Send ACK */ - TLan_MiiSendData( dev->base_addr, val, 16 ); /* Send Data */ + tlan_mii_send_data(dev->base_addr, 0x2, 2); /* send ACK */ + tlan_mii_send_data(dev->base_addr, val, 16); /* send data */ - TLan_ClearBit( TLAN_NET_SIO_MCLK, sio ); /* Idle cycle */ - TLan_SetBit( TLAN_NET_SIO_MCLK, sio ); + tlan_clear_bit(TLAN_NET_SIO_MCLK, sio); /* idle cycle */ + tlan_set_bit(TLAN_NET_SIO_MCLK, sio); - if ( minten ) - TLan_SetBit( TLAN_NET_SIO_MINTEN, sio ); + if (minten) + tlan_set_bit(TLAN_NET_SIO_MINTEN, sio); if (!in_irq()) spin_unlock_irqrestore(&priv->lock, flags); -} /* TLan_MiiWriteReg */ +} @@ -3090,229 +3186,226 @@ static void TLan_MiiWriteReg( struct net_device *dev, u16 phy, u16 reg, u16 val /***************************************************************************** ****************************************************************************** - ThunderLAN Driver Eeprom routines +ThunderLAN driver eeprom routines - The Compaq Netelligent 10 and 10/100 cards use a Microchip 24C02A - EEPROM. These functions are based on information in Microchip's - data sheet. I don't know how well this functions will work with - other EEPROMs. +the Compaq netelligent 10 and 10/100 cards use a microchip 24C02A +EEPROM. these functions are based on information in microchip's +data sheet. I don't know how well this functions will work with +other Eeproms. ****************************************************************************** *****************************************************************************/ - /*************************************************************** - * TLan_EeSendStart - * - * Returns: - * Nothing - * Parms: - * io_base The IO port base address for the - * TLAN device with the EEPROM to - * use. - * - * This function sends a start cycle to an EEPROM attached - * to a TLAN chip. - * - **************************************************************/ - -static void TLan_EeSendStart( u16 io_base ) +/*************************************************************** + * tlan_ee_send_start + * + * Returns: + * Nothing + * Parms: + * io_base The IO port base address for the + * TLAN device with the EEPROM to + * use. + * + * This function sends a start cycle to an EEPROM attached + * to a TLAN chip. + * + **************************************************************/ + +static void tlan_ee_send_start(u16 io_base) { u16 sio; - outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR ); + outw(TLAN_NET_SIO, io_base + TLAN_DIO_ADR); sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; - TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); - TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); - TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); - TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); - TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); - -} /* TLan_EeSendStart */ - - - - - /*************************************************************** - * TLan_EeSendByte - * - * Returns: - * If the correct ack was received, 0, otherwise 1 - * Parms: io_base The IO port base address for the - * TLAN device with the EEPROM to - * use. - * data The 8 bits of information to - * send to the EEPROM. - * stop If TLAN_EEPROM_STOP is passed, a - * stop cycle is sent after the - * byte is sent after the ack is - * read. - * - * This function sends a byte on the serial EEPROM line, - * driving the clock to send each bit. The function then - * reverses transmission direction and reads an acknowledge - * bit. - * - **************************************************************/ - -static int TLan_EeSendByte( u16 io_base, u8 data, int stop ) + tlan_set_bit(TLAN_NET_SIO_ECLOK, sio); + tlan_set_bit(TLAN_NET_SIO_EDATA, sio); + tlan_set_bit(TLAN_NET_SIO_ETXEN, sio); + tlan_clear_bit(TLAN_NET_SIO_EDATA, sio); + tlan_clear_bit(TLAN_NET_SIO_ECLOK, sio); + +} + + + + +/*************************************************************** + * tlan_ee_send_byte + * + * Returns: + * If the correct ack was received, 0, otherwise 1 + * Parms: io_base The IO port base address for the + * TLAN device with the EEPROM to + * use. + * data The 8 bits of information to + * send to the EEPROM. + * stop If TLAN_EEPROM_STOP is passed, a + * stop cycle is sent after the + * byte is sent after the ack is + * read. + * + * This function sends a byte on the serial EEPROM line, + * driving the clock to send each bit. The function then + * reverses transmission direction and reads an acknowledge + * bit. + * + **************************************************************/ + +static int tlan_ee_send_byte(u16 io_base, u8 data, int stop) { int err; u8 place; u16 sio; - outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR ); + outw(TLAN_NET_SIO, io_base + TLAN_DIO_ADR); sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; /* Assume clock is low, tx is enabled; */ - for ( place = 0x80; place != 0; place >>= 1 ) { - if ( place & data ) - TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); + for (place = 0x80; place != 0; place >>= 1) { + if (place & data) + tlan_set_bit(TLAN_NET_SIO_EDATA, sio); else - TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); - TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); - TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + tlan_clear_bit(TLAN_NET_SIO_EDATA, sio); + tlan_set_bit(TLAN_NET_SIO_ECLOK, sio); + tlan_clear_bit(TLAN_NET_SIO_ECLOK, sio); } - TLan_ClearBit( TLAN_NET_SIO_ETXEN, sio ); - TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); - err = TLan_GetBit( TLAN_NET_SIO_EDATA, sio ); - TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); - TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); + tlan_clear_bit(TLAN_NET_SIO_ETXEN, sio); + tlan_set_bit(TLAN_NET_SIO_ECLOK, sio); + err = tlan_get_bit(TLAN_NET_SIO_EDATA, sio); + tlan_clear_bit(TLAN_NET_SIO_ECLOK, sio); + tlan_set_bit(TLAN_NET_SIO_ETXEN, sio); - if ( ( ! err ) && stop ) { + if ((!err) && stop) { /* STOP, raise data while clock is high */ - TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); - TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); - TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); + tlan_clear_bit(TLAN_NET_SIO_EDATA, sio); + tlan_set_bit(TLAN_NET_SIO_ECLOK, sio); + tlan_set_bit(TLAN_NET_SIO_EDATA, sio); } return err; -} /* TLan_EeSendByte */ - - - - - /*************************************************************** - * TLan_EeReceiveByte - * - * Returns: - * Nothing - * Parms: - * io_base The IO port base address for the - * TLAN device with the EEPROM to - * use. - * data An address to a char to hold the - * data sent from the EEPROM. - * stop If TLAN_EEPROM_STOP is passed, a - * stop cycle is sent after the - * byte is received, and no ack is - * sent. - * - * This function receives 8 bits of data from the EEPROM - * over the serial link. It then sends and ack bit, or no - * ack and a stop bit. This function is used to retrieve - * data after the address of a byte in the EEPROM has been - * sent. - * - **************************************************************/ - -static void TLan_EeReceiveByte( u16 io_base, u8 *data, int stop ) +} + + + + +/*************************************************************** + * tlan_ee_receive_byte + * + * Returns: + * Nothing + * Parms: + * io_base The IO port base address for the + * TLAN device with the EEPROM to + * use. + * data An address to a char to hold the + * data sent from the EEPROM. + * stop If TLAN_EEPROM_STOP is passed, a + * stop cycle is sent after the + * byte is received, and no ack is + * sent. + * + * This function receives 8 bits of data from the EEPROM + * over the serial link. It then sends and ack bit, or no + * ack and a stop bit. This function is used to retrieve + * data after the address of a byte in the EEPROM has been + * sent. + * + **************************************************************/ + +static void tlan_ee_receive_byte(u16 io_base, u8 *data, int stop) { u8 place; u16 sio; - outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR ); + outw(TLAN_NET_SIO, io_base + TLAN_DIO_ADR); sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; *data = 0; /* Assume clock is low, tx is enabled; */ - TLan_ClearBit( TLAN_NET_SIO_ETXEN, sio ); - for ( place = 0x80; place; place >>= 1 ) { - TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); - if ( TLan_GetBit( TLAN_NET_SIO_EDATA, sio ) ) + tlan_clear_bit(TLAN_NET_SIO_ETXEN, sio); + for (place = 0x80; place; place >>= 1) { + tlan_set_bit(TLAN_NET_SIO_ECLOK, sio); + if (tlan_get_bit(TLAN_NET_SIO_EDATA, sio)) *data |= place; - TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + tlan_clear_bit(TLAN_NET_SIO_ECLOK, sio); } - TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); - if ( ! stop ) { - TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); /* Ack = 0 */ - TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); - TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + tlan_set_bit(TLAN_NET_SIO_ETXEN, sio); + if (!stop) { + tlan_clear_bit(TLAN_NET_SIO_EDATA, sio); /* ack = 0 */ + tlan_set_bit(TLAN_NET_SIO_ECLOK, sio); + tlan_clear_bit(TLAN_NET_SIO_ECLOK, sio); } else { - TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); /* No ack = 1 (?) */ - TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); - TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + tlan_set_bit(TLAN_NET_SIO_EDATA, sio); /* no ack = 1 (?) */ + tlan_set_bit(TLAN_NET_SIO_ECLOK, sio); + tlan_clear_bit(TLAN_NET_SIO_ECLOK, sio); /* STOP, raise data while clock is high */ - TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); - TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); - TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); - } - -} /* TLan_EeReceiveByte */ - - - - - /*************************************************************** - * TLan_EeReadByte - * - * Returns: - * No error = 0, else, the stage at which the error - * occurred. - * Parms: - * io_base The IO port base address for the - * TLAN device with the EEPROM to - * use. - * ee_addr The address of the byte in the - * EEPROM whose contents are to be - * retrieved. - * data An address to a char to hold the - * data obtained from the EEPROM. - * - * This function reads a byte of information from an byte - * cell in the EEPROM. - * - **************************************************************/ - -static int TLan_EeReadByte( struct net_device *dev, u8 ee_addr, u8 *data ) + tlan_clear_bit(TLAN_NET_SIO_EDATA, sio); + tlan_set_bit(TLAN_NET_SIO_ECLOK, sio); + tlan_set_bit(TLAN_NET_SIO_EDATA, sio); + } + +} + + + + +/*************************************************************** + * tlan_ee_read_byte + * + * Returns: + * No error = 0, else, the stage at which the error + * occurred. + * Parms: + * io_base The IO port base address for the + * TLAN device with the EEPROM to + * use. + * ee_addr The address of the byte in the + * EEPROM whose contents are to be + * retrieved. + * data An address to a char to hold the + * data obtained from the EEPROM. + * + * This function reads a byte of information from an byte + * cell in the EEPROM. + * + **************************************************************/ + +static int tlan_ee_read_byte(struct net_device *dev, u8 ee_addr, u8 *data) { int err; - TLanPrivateInfo *priv = netdev_priv(dev); + struct tlan_priv *priv = netdev_priv(dev); unsigned long flags = 0; - int ret=0; + int ret = 0; spin_lock_irqsave(&priv->lock, flags); - TLan_EeSendStart( dev->base_addr ); - err = TLan_EeSendByte( dev->base_addr, 0xA0, TLAN_EEPROM_ACK ); - if (err) - { - ret=1; + tlan_ee_send_start(dev->base_addr); + err = tlan_ee_send_byte(dev->base_addr, 0xa0, TLAN_EEPROM_ACK); + if (err) { + ret = 1; goto fail; } - err = TLan_EeSendByte( dev->base_addr, ee_addr, TLAN_EEPROM_ACK ); - if (err) - { - ret=2; + err = tlan_ee_send_byte(dev->base_addr, ee_addr, TLAN_EEPROM_ACK); + if (err) { + ret = 2; goto fail; } - TLan_EeSendStart( dev->base_addr ); - err = TLan_EeSendByte( dev->base_addr, 0xA1, TLAN_EEPROM_ACK ); - if (err) - { - ret=3; + tlan_ee_send_start(dev->base_addr); + err = tlan_ee_send_byte(dev->base_addr, 0xa1, TLAN_EEPROM_ACK); + if (err) { + ret = 3; goto fail; } - TLan_EeReceiveByte( dev->base_addr, data, TLAN_EEPROM_STOP ); + tlan_ee_receive_byte(dev->base_addr, data, TLAN_EEPROM_STOP); fail: spin_unlock_irqrestore(&priv->lock, flags); return ret; -} /* TLan_EeReadByte */ +} diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h index 3315ced774e2..5fc98a8e4889 100644 --- a/drivers/net/tlan.h +++ b/drivers/net/tlan.h @@ -20,8 +20,8 @@ ********************************************************************/ -#include <asm/io.h> -#include <asm/types.h> +#include <linux/io.h> +#include <linux/types.h> #include <linux/netdevice.h> @@ -40,8 +40,11 @@ #define TLAN_IGNORE 0 #define TLAN_RECORD 1 -#define TLAN_DBG(lvl, format, args...) \ - do { if (debug&lvl) printk(KERN_DEBUG "TLAN: " format, ##args ); } while(0) +#define TLAN_DBG(lvl, format, args...) \ + do { \ + if (debug&lvl) \ + printk(KERN_DEBUG "TLAN: " format, ##args); \ + } while (0) #define TLAN_DEBUG_GNRL 0x0001 #define TLAN_DEBUG_TX 0x0002 @@ -50,7 +53,8 @@ #define TLAN_DEBUG_PROBE 0x0010 #define TX_TIMEOUT (10*HZ) /* We need time for auto-neg */ -#define MAX_TLAN_BOARDS 8 /* Max number of boards installed at a time */ +#define MAX_TLAN_BOARDS 8 /* Max number of boards installed + at a time */ /***************************************************************** @@ -70,13 +74,13 @@ #define PCI_DEVICE_ID_OLICOM_OC2326 0x0014 #endif -typedef struct tlan_adapter_entry { - u16 vendorId; - u16 deviceId; - char *deviceLabel; +struct tlan_adapter_entry { + u16 vendor_id; + u16 device_id; + char *device_label; u32 flags; - u16 addrOfs; -} TLanAdapterEntry; + u16 addr_ofs; +}; #define TLAN_ADAPTER_NONE 0x00000000 #define TLAN_ADAPTER_UNMANAGED_PHY 0x00000001 @@ -129,18 +133,18 @@ typedef struct tlan_adapter_entry { #define TLAN_CSTAT_DP_PR 0x0100 -typedef struct tlan_buffer_ref_tag { +struct tlan_buffer { u32 count; u32 address; -} TLanBufferRef; +}; -typedef struct tlan_list_tag { +struct tlan_list { u32 forward; - u16 cStat; - u16 frameSize; - TLanBufferRef buffer[TLAN_BUFFERS_PER_LIST]; -} TLanList; + u16 c_stat; + u16 frame_size; + struct tlan_buffer buffer[TLAN_BUFFERS_PER_LIST]; +}; typedef u8 TLanBuffer[TLAN_MAX_FRAME_SIZE]; @@ -164,49 +168,49 @@ typedef u8 TLanBuffer[TLAN_MAX_FRAME_SIZE]; * ****************************************************************/ -typedef struct tlan_private_tag { - struct net_device *nextDevice; - struct pci_dev *pciDev; +struct tlan_priv { + struct net_device *next_device; + struct pci_dev *pci_dev; struct net_device *dev; - void *dmaStorage; - dma_addr_t dmaStorageDMA; - unsigned int dmaSize; - u8 *padBuffer; - TLanList *rxList; - dma_addr_t rxListDMA; - u8 *rxBuffer; - dma_addr_t rxBufferDMA; - u32 rxHead; - u32 rxTail; - u32 rxEocCount; - TLanList *txList; - dma_addr_t txListDMA; - u8 *txBuffer; - dma_addr_t txBufferDMA; - u32 txHead; - u32 txInProgress; - u32 txTail; - u32 txBusyCount; - u32 phyOnline; - u32 timerSetAt; - u32 timerType; + void *dma_storage; + dma_addr_t dma_storage_dma; + unsigned int dma_size; + u8 *pad_buffer; + struct tlan_list *rx_list; + dma_addr_t rx_list_dma; + u8 *rx_buffer; + dma_addr_t rx_buffer_dma; + u32 rx_head; + u32 rx_tail; + u32 rx_eoc_count; + struct tlan_list *tx_list; + dma_addr_t tx_list_dma; + u8 *tx_buffer; + dma_addr_t tx_buffer_dma; + u32 tx_head; + u32 tx_in_progress; + u32 tx_tail; + u32 tx_busy_count; + u32 phy_online; + u32 timer_set_at; + u32 timer_type; struct timer_list timer; struct board *adapter; - u32 adapterRev; + u32 adapter_rev; u32 aui; u32 debug; u32 duplex; u32 phy[2]; - u32 phyNum; + u32 phy_num; u32 speed; - u8 tlanRev; - u8 tlanFullDuplex; + u8 tlan_rev; + u8 tlan_full_duplex; spinlock_t lock; u8 link; u8 is_eisa; struct work_struct tlan_tqueue; u8 neg_be_verbose; -} TLanPrivateInfo; +}; @@ -247,7 +251,7 @@ typedef struct tlan_private_tag { ****************************************************************/ #define TLAN_HOST_CMD 0x00 -#define TLAN_HC_GO 0x80000000 +#define TLAN_HC_GO 0x80000000 #define TLAN_HC_STOP 0x40000000 #define TLAN_HC_ACK 0x20000000 #define TLAN_HC_CS_MASK 0x1FE00000 @@ -283,7 +287,7 @@ typedef struct tlan_private_tag { #define TLAN_NET_CMD_TRFRAM 0x02 #define TLAN_NET_CMD_TXPACE 0x01 #define TLAN_NET_SIO 0x01 -#define TLAN_NET_SIO_MINTEN 0x80 +#define TLAN_NET_SIO_MINTEN 0x80 #define TLAN_NET_SIO_ECLOK 0x40 #define TLAN_NET_SIO_ETXEN 0x20 #define TLAN_NET_SIO_EDATA 0x10 @@ -304,7 +308,7 @@ typedef struct tlan_private_tag { #define TLAN_NET_MASK_MASK4 0x10 #define TLAN_NET_MASK_RSRVD 0x0F #define TLAN_NET_CONFIG 0x04 -#define TLAN_NET_CFG_RCLK 0x8000 +#define TLAN_NET_CFG_RCLK 0x8000 #define TLAN_NET_CFG_TCLK 0x4000 #define TLAN_NET_CFG_BIT 0x2000 #define TLAN_NET_CFG_RXCRC 0x1000 @@ -372,7 +376,7 @@ typedef struct tlan_private_tag { /* Generic MII/PHY Registers */ #define MII_GEN_CTL 0x00 -#define MII_GC_RESET 0x8000 +#define MII_GC_RESET 0x8000 #define MII_GC_LOOPBK 0x4000 #define MII_GC_SPEEDSEL 0x2000 #define MII_GC_AUTOENB 0x1000 @@ -397,9 +401,9 @@ typedef struct tlan_private_tag { #define MII_GS_EXTCAP 0x0001 #define MII_GEN_ID_HI 0x02 #define MII_GEN_ID_LO 0x03 -#define MII_GIL_OUI 0xFC00 -#define MII_GIL_MODEL 0x03F0 -#define MII_GIL_REVISION 0x000F +#define MII_GIL_OUI 0xFC00 +#define MII_GIL_MODEL 0x03F0 +#define MII_GIL_REVISION 0x000F #define MII_AN_ADV 0x04 #define MII_AN_LPA 0x05 #define MII_AN_EXP 0x06 @@ -408,7 +412,7 @@ typedef struct tlan_private_tag { #define TLAN_TLPHY_ID 0x10 #define TLAN_TLPHY_CTL 0x11 -#define TLAN_TC_IGLINK 0x8000 +#define TLAN_TC_IGLINK 0x8000 #define TLAN_TC_SWAPOL 0x4000 #define TLAN_TC_AUISEL 0x2000 #define TLAN_TC_SQEEN 0x1000 @@ -435,41 +439,41 @@ typedef struct tlan_private_tag { #define LEVEL1_ID1 0x7810 #define LEVEL1_ID2 0x0000 -#define CIRC_INC( a, b ) if ( ++a >= b ) a = 0 +#define CIRC_INC(a, b) if (++a >= b) a = 0 /* Routines to access internal registers. */ -static inline u8 TLan_DioRead8(u16 base_addr, u16 internal_addr) +static inline u8 tlan_dio_read8(u16 base_addr, u16 internal_addr) { outw(internal_addr, base_addr + TLAN_DIO_ADR); return inb((base_addr + TLAN_DIO_DATA) + (internal_addr & 0x3)); -} /* TLan_DioRead8 */ +} -static inline u16 TLan_DioRead16(u16 base_addr, u16 internal_addr) +static inline u16 tlan_dio_read16(u16 base_addr, u16 internal_addr) { outw(internal_addr, base_addr + TLAN_DIO_ADR); return inw((base_addr + TLAN_DIO_DATA) + (internal_addr & 0x2)); -} /* TLan_DioRead16 */ +} -static inline u32 TLan_DioRead32(u16 base_addr, u16 internal_addr) +static inline u32 tlan_dio_read32(u16 base_addr, u16 internal_addr) { outw(internal_addr, base_addr + TLAN_DIO_ADR); return inl(base_addr + TLAN_DIO_DATA); -} /* TLan_DioRead32 */ +} -static inline void TLan_DioWrite8(u16 base_addr, u16 internal_addr, u8 data) +static inline void tlan_dio_write8(u16 base_addr, u16 internal_addr, u8 data) { outw(internal_addr, base_addr + TLAN_DIO_ADR); outb(data, base_addr + TLAN_DIO_DATA + (internal_addr & 0x3)); @@ -479,7 +483,7 @@ static inline void TLan_DioWrite8(u16 base_addr, u16 internal_addr, u8 data) -static inline void TLan_DioWrite16(u16 base_addr, u16 internal_addr, u16 data) +static inline void tlan_dio_write16(u16 base_addr, u16 internal_addr, u16 data) { outw(internal_addr, base_addr + TLAN_DIO_ADR); outw(data, base_addr + TLAN_DIO_DATA + (internal_addr & 0x2)); @@ -489,16 +493,16 @@ static inline void TLan_DioWrite16(u16 base_addr, u16 internal_addr, u16 data) -static inline void TLan_DioWrite32(u16 base_addr, u16 internal_addr, u32 data) +static inline void tlan_dio_write32(u16 base_addr, u16 internal_addr, u32 data) { outw(internal_addr, base_addr + TLAN_DIO_ADR); outl(data, base_addr + TLAN_DIO_DATA + (internal_addr & 0x2)); } -#define TLan_ClearBit( bit, port ) outb_p(inb_p(port) & ~bit, port) -#define TLan_GetBit( bit, port ) ((int) (inb_p(port) & bit)) -#define TLan_SetBit( bit, port ) outb_p(inb_p(port) | bit, port) +#define tlan_clear_bit(bit, port) outb_p(inb_p(port) & ~bit, port) +#define tlan_get_bit(bit, port) ((int) (inb_p(port) & bit)) +#define tlan_set_bit(bit, port) outb_p(inb_p(port) | bit, port) /* * given 6 bytes, view them as 8 6-bit numbers and return the XOR of those @@ -506,37 +510,37 @@ static inline void TLan_DioWrite32(u16 base_addr, u16 internal_addr, u32 data) * * The original code was: * - * u32 xor( u32 a, u32 b ) { return ( ( a && ! b ) || ( ! a && b ) ); } + * u32 xor(u32 a, u32 b) { return ((a && !b ) || (! a && b )); } * - * #define XOR8( a, b, c, d, e, f, g, h ) \ - * xor( a, xor( b, xor( c, xor( d, xor( e, xor( f, xor( g, h ) ) ) ) ) ) ) - * #define DA( a, bit ) ( ( (u8) a[bit/8] ) & ( (u8) ( 1 << bit%8 ) ) ) + * #define XOR8(a, b, c, d, e, f, g, h) \ + * xor(a, xor(b, xor(c, xor(d, xor(e, xor(f, xor(g, h)) ) ) ) ) ) + * #define DA(a, bit) (( (u8) a[bit/8] ) & ( (u8) (1 << bit%8)) ) * - * hash = XOR8( DA(a,0), DA(a, 6), DA(a,12), DA(a,18), DA(a,24), - * DA(a,30), DA(a,36), DA(a,42) ); - * hash |= XOR8( DA(a,1), DA(a, 7), DA(a,13), DA(a,19), DA(a,25), - * DA(a,31), DA(a,37), DA(a,43) ) << 1; - * hash |= XOR8( DA(a,2), DA(a, 8), DA(a,14), DA(a,20), DA(a,26), - * DA(a,32), DA(a,38), DA(a,44) ) << 2; - * hash |= XOR8( DA(a,3), DA(a, 9), DA(a,15), DA(a,21), DA(a,27), - * DA(a,33), DA(a,39), DA(a,45) ) << 3; - * hash |= XOR8( DA(a,4), DA(a,10), DA(a,16), DA(a,22), DA(a,28), - * DA(a,34), DA(a,40), DA(a,46) ) << 4; - * hash |= XOR8( DA(a,5), DA(a,11), DA(a,17), DA(a,23), DA(a,29), - * DA(a,35), DA(a,41), DA(a,47) ) << 5; + * hash = XOR8(DA(a,0), DA(a, 6), DA(a,12), DA(a,18), DA(a,24), + * DA(a,30), DA(a,36), DA(a,42)); + * hash |= XOR8(DA(a,1), DA(a, 7), DA(a,13), DA(a,19), DA(a,25), + * DA(a,31), DA(a,37), DA(a,43)) << 1; + * hash |= XOR8(DA(a,2), DA(a, 8), DA(a,14), DA(a,20), DA(a,26), + * DA(a,32), DA(a,38), DA(a,44)) << 2; + * hash |= XOR8(DA(a,3), DA(a, 9), DA(a,15), DA(a,21), DA(a,27), + * DA(a,33), DA(a,39), DA(a,45)) << 3; + * hash |= XOR8(DA(a,4), DA(a,10), DA(a,16), DA(a,22), DA(a,28), + * DA(a,34), DA(a,40), DA(a,46)) << 4; + * hash |= XOR8(DA(a,5), DA(a,11), DA(a,17), DA(a,23), DA(a,29), + * DA(a,35), DA(a,41), DA(a,47)) << 5; * */ -static inline u32 TLan_HashFunc( const u8 *a ) +static inline u32 tlan_hash_func(const u8 *a) { - u8 hash; + u8 hash; - hash = (a[0]^a[3]); /* & 077 */ - hash ^= ((a[0]^a[3])>>6); /* & 003 */ - hash ^= ((a[1]^a[4])<<2); /* & 074 */ - hash ^= ((a[1]^a[4])>>4); /* & 017 */ - hash ^= ((a[2]^a[5])<<4); /* & 060 */ - hash ^= ((a[2]^a[5])>>2); /* & 077 */ + hash = (a[0]^a[3]); /* & 077 */ + hash ^= ((a[0]^a[3])>>6); /* & 003 */ + hash ^= ((a[1]^a[4])<<2); /* & 074 */ + hash ^= ((a[1]^a[4])>>4); /* & 017 */ + hash ^= ((a[2]^a[5])<<4); /* & 060 */ + hash ^= ((a[2]^a[5])>>2); /* & 077 */ - return hash & 077; + return hash & 077; } #endif diff --git a/drivers/net/tun.c b/drivers/net/tun.c index b100bd50a0d7..55786a0efc41 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1142,7 +1142,7 @@ static int tun_get_iff(struct net *net, struct tun_struct *tun, * privs required. */ static int set_offload(struct net_device *dev, unsigned long arg) { - unsigned int old_features, features; + u32 old_features, features; old_features = dev->features; /* Unset features, set them as we chew on the arg. */ diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index a3c46f6a15e7..7fa5ec2de942 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -123,12 +123,11 @@ static const int multicast_filter_limit = 32; #include <linux/in6.h> #include <linux/dma-mapping.h> #include <linux/firmware.h> -#include <generated/utsrelease.h> #include "typhoon.h" MODULE_AUTHOR("David Dillow <dave@thedillows.org>"); -MODULE_VERSION(UTS_RELEASE); +MODULE_VERSION("1.0"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(FIRMWARE_NAME); MODULE_DESCRIPTION("3Com Typhoon Family (3C990, 3CR990, and variants)"); diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index bed8fcedff49..6d83812603b6 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -2628,15 +2628,15 @@ exit: static void hso_free_tiomget(struct hso_serial *serial) { - struct hso_tiocmget *tiocmget = serial->tiocmget; + struct hso_tiocmget *tiocmget; + if (!serial) + return; + tiocmget = serial->tiocmget; if (tiocmget) { - if (tiocmget->urb) { - usb_free_urb(tiocmget->urb); - tiocmget->urb = NULL; - } + usb_free_urb(tiocmget->urb); + tiocmget->urb = NULL; serial->tiocmget = NULL; kfree(tiocmget); - } } diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index ed9a41643ff4..95c41d56631c 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -931,8 +931,10 @@ fail_halt: if (urb != NULL) { clear_bit (EVENT_RX_MEMORY, &dev->flags); status = usb_autopm_get_interface(dev->intf); - if (status < 0) + if (status < 0) { + usb_free_urb(urb); goto fail_lowmem; + } if (rx_submit (dev, urb, GFP_KERNEL) == -ENOLINK) resched = 0; usb_autopm_put_interface(dev->intf); diff --git a/drivers/net/veth.c b/drivers/net/veth.c index cc83fa71c3ff..105d7f0630cc 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -403,17 +403,6 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, if (tb[IFLA_ADDRESS] == NULL) random_ether_addr(dev->dev_addr); - if (tb[IFLA_IFNAME]) - nla_strlcpy(dev->name, tb[IFLA_IFNAME], IFNAMSIZ); - else - snprintf(dev->name, IFNAMSIZ, DRV_NAME "%%d"); - - if (strchr(dev->name, '%')) { - err = dev_alloc_name(dev, dev->name); - if (err < 0) - goto err_alloc_name; - } - err = register_netdevice(dev); if (err < 0) goto err_register_dev; @@ -433,7 +422,6 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, err_register_dev: /* nothing to do */ -err_alloc_name: err_configure_peer: unregister_netdevice(peer); return err; diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 09cac704fdd7..0d6fec6b7d93 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -2923,6 +2923,7 @@ static u16 wol_calc_crc(int size, u8 *pattern, u8 *mask_pattern) static int velocity_set_wol(struct velocity_info *vptr) { struct mac_regs __iomem *regs = vptr->mac_regs; + enum speed_opt spd_dpx = vptr->options.spd_dpx; static u8 buf[256]; int i; @@ -2968,6 +2969,12 @@ static int velocity_set_wol(struct velocity_info *vptr) writew(0x0FFF, ®s->WOLSRClr); + if (spd_dpx == SPD_DPX_1000_FULL) + goto mac_done; + + if (spd_dpx != SPD_DPX_AUTO) + goto advertise_done; + if (vptr->mii_status & VELOCITY_AUTONEG_ENABLE) { if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) MII_REG_BITS_ON(AUXCR_MDPPS, MII_NCONFIG, vptr->mac_regs); @@ -2978,6 +2985,7 @@ static int velocity_set_wol(struct velocity_info *vptr) if (vptr->mii_status & VELOCITY_SPEED_1000) MII_REG_BITS_ON(BMCR_ANRESTART, MII_BMCR, vptr->mac_regs); +advertise_done: BYTE_REG_BITS_ON(CHIPGCR_FCMODE, ®s->CHIPGCR); { @@ -2987,6 +2995,7 @@ static int velocity_set_wol(struct velocity_info *vptr) writeb(GCR, ®s->CHIPGCR); } +mac_done: BYTE_REG_BITS_OFF(ISR_PWEI, ®s->ISR); /* Turn on SWPTAG just before entering power mode */ BYTE_REG_BITS_ON(STICKHW_SWPTAG, ®s->STICKHW); diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h index aa2e69b9ff61..d7227539484e 100644 --- a/drivers/net/via-velocity.h +++ b/drivers/net/via-velocity.h @@ -361,7 +361,7 @@ enum velocity_owner { #define MAC_REG_CHIPGSR 0x9C #define MAC_REG_TESTCFG 0x9D #define MAC_REG_DEBUG 0x9E -#define MAC_REG_CHIPGCR 0x9F +#define MAC_REG_CHIPGCR 0x9F /* Chip Operation and Diagnostic Control */ #define MAC_REG_WOLCR0_SET 0xA0 #define MAC_REG_WOLCR1_SET 0xA1 #define MAC_REG_PWCFG_SET 0xA2 @@ -848,10 +848,10 @@ enum velocity_owner { * Bits in CHIPGCR register */ -#define CHIPGCR_FCGMII 0x80 /* enable GMII mode */ -#define CHIPGCR_FCFDX 0x40 +#define CHIPGCR_FCGMII 0x80 /* force GMII (else MII only) */ +#define CHIPGCR_FCFDX 0x40 /* force full duplex */ #define CHIPGCR_FCRESV 0x20 -#define CHIPGCR_FCMODE 0x10 +#define CHIPGCR_FCMODE 0x10 /* enable MAC forced mode */ #define CHIPGCR_LPSOPT 0x08 #define CHIPGCR_TM1US 0x04 #define CHIPGCR_TM0US 0x02 diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 90a23e410d1b..82dba5aaf423 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -446,6 +446,20 @@ static void skb_recv_done(struct virtqueue *rvq) } } +static void virtnet_napi_enable(struct virtnet_info *vi) +{ + napi_enable(&vi->napi); + + /* If all buffers were filled by other side before we napi_enabled, we + * won't get another interrupt, so process any outstanding packets + * now. virtnet_poll wants re-enable the queue, so we disable here. + * We synchronize against interrupts via NAPI_STATE_SCHED */ + if (napi_schedule_prep(&vi->napi)) { + virtqueue_disable_cb(vi->rvq); + __napi_schedule(&vi->napi); + } +} + static void refill_work(struct work_struct *work) { struct virtnet_info *vi; @@ -454,7 +468,7 @@ static void refill_work(struct work_struct *work) vi = container_of(work, struct virtnet_info, refill.work); napi_disable(&vi->napi); still_empty = !try_fill_recv(vi, GFP_KERNEL); - napi_enable(&vi->napi); + virtnet_napi_enable(vi); /* In theory, this can happen: if we don't get any buffers in * we will *never* try to fill again. */ @@ -638,16 +652,7 @@ static int virtnet_open(struct net_device *dev) { struct virtnet_info *vi = netdev_priv(dev); - napi_enable(&vi->napi); - - /* If all buffers were filled by other side before we napi_enabled, we - * won't get another interrupt, so process any outstanding packets - * now. virtnet_poll wants re-enable the queue, so we disable here. - * We synchronize against interrupts via NAPI_STATE_SCHED */ - if (napi_schedule_prep(&vi->napi)) { - virtqueue_disable_cb(vi->rvq); - __napi_schedule(&vi->napi); - } + virtnet_napi_enable(vi); return 0; } diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index 228d4f7a58af..e74e4b42592d 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -387,8 +387,8 @@ vxge_hw_vpath_eprom_img_ver_get(struct __vxge_hw_device *hldev, data1 = steer_ctrl = 0; status = vxge_hw_vpath_fw_api(vpath, - VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO, VXGE_HW_FW_API_GET_EPROM_REV, + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO, 0, &data0, &data1, &steer_ctrl); if (status != VXGE_HW_OK) break; @@ -2868,6 +2868,8 @@ __vxge_hw_ring_create(struct __vxge_hw_vpath_handle *vp, ring->rxd_init = attr->rxd_init; ring->rxd_term = attr->rxd_term; ring->buffer_mode = config->buffer_mode; + ring->tim_rti_cfg1_saved = vp->vpath->tim_rti_cfg1_saved; + ring->tim_rti_cfg3_saved = vp->vpath->tim_rti_cfg3_saved; ring->rxds_limit = config->rxds_limit; ring->rxd_size = vxge_hw_ring_rxd_size_get(config->buffer_mode); @@ -3511,6 +3513,8 @@ __vxge_hw_fifo_create(struct __vxge_hw_vpath_handle *vp, /* apply "interrupts per txdl" attribute */ fifo->interrupt_type = VXGE_HW_FIFO_TXD_INT_TYPE_UTILZ; + fifo->tim_tti_cfg1_saved = vpath->tim_tti_cfg1_saved; + fifo->tim_tti_cfg3_saved = vpath->tim_tti_cfg3_saved; if (fifo->config->intr) fifo->interrupt_type = VXGE_HW_FIFO_TXD_INT_TYPE_PER_LIST; @@ -4377,6 +4381,8 @@ __vxge_hw_vpath_tim_configure(struct __vxge_hw_device *hldev, u32 vp_id) } writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_TX]); + vpath->tim_tti_cfg1_saved = val64; + val64 = readq(&vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_TX]); if (config->tti.uec_a != VXGE_HW_USE_FLASH_DEFAULT) { @@ -4433,6 +4439,7 @@ __vxge_hw_vpath_tim_configure(struct __vxge_hw_device *hldev, u32 vp_id) } writeq(val64, &vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_TX]); + vpath->tim_tti_cfg3_saved = val64; } if (config->ring.enable == VXGE_HW_RING_ENABLE) { @@ -4481,6 +4488,8 @@ __vxge_hw_vpath_tim_configure(struct __vxge_hw_device *hldev, u32 vp_id) } writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_RX]); + vpath->tim_rti_cfg1_saved = val64; + val64 = readq(&vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_RX]); if (config->rti.uec_a != VXGE_HW_USE_FLASH_DEFAULT) { @@ -4537,6 +4546,7 @@ __vxge_hw_vpath_tim_configure(struct __vxge_hw_device *hldev, u32 vp_id) } writeq(val64, &vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_RX]); + vpath->tim_rti_cfg3_saved = val64; } val64 = 0; @@ -4555,26 +4565,6 @@ __vxge_hw_vpath_tim_configure(struct __vxge_hw_device *hldev, u32 vp_id) return status; } -void vxge_hw_vpath_tti_ci_set(struct __vxge_hw_device *hldev, u32 vp_id) -{ - struct __vxge_hw_virtualpath *vpath; - struct vxge_hw_vpath_reg __iomem *vp_reg; - struct vxge_hw_vp_config *config; - u64 val64; - - vpath = &hldev->virtual_paths[vp_id]; - vp_reg = vpath->vp_reg; - config = vpath->vp_config; - - if (config->fifo.enable == VXGE_HW_FIFO_ENABLE && - config->tti.timer_ci_en != VXGE_HW_TIM_TIMER_CI_ENABLE) { - config->tti.timer_ci_en = VXGE_HW_TIM_TIMER_CI_ENABLE; - val64 = readq(&vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_TX]); - val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI; - writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_TX]); - } -} - /* * __vxge_hw_vpath_initialize * This routine is the final phase of init which initializes the diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h index e249e288d160..3c53aa732c9d 100644 --- a/drivers/net/vxge/vxge-config.h +++ b/drivers/net/vxge/vxge-config.h @@ -682,6 +682,10 @@ struct __vxge_hw_virtualpath { u32 vsport_number; u32 max_kdfc_db; u32 max_nofl_db; + u64 tim_tti_cfg1_saved; + u64 tim_tti_cfg3_saved; + u64 tim_rti_cfg1_saved; + u64 tim_rti_cfg3_saved; struct __vxge_hw_ring *____cacheline_aligned ringh; struct __vxge_hw_fifo *____cacheline_aligned fifoh; @@ -921,6 +925,9 @@ struct __vxge_hw_ring { u32 doorbell_cnt; u32 total_db_cnt; u64 rxds_limit; + u32 rtimer; + u64 tim_rti_cfg1_saved; + u64 tim_rti_cfg3_saved; enum vxge_hw_status (*callback)( struct __vxge_hw_ring *ringh, @@ -1000,6 +1007,9 @@ struct __vxge_hw_fifo { u32 per_txdl_space; u32 vp_id; u32 tx_intr_num; + u32 rtimer; + u64 tim_tti_cfg1_saved; + u64 tim_tti_cfg3_saved; enum vxge_hw_status (*callback)( struct __vxge_hw_fifo *fifo_handle, diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index c81a6512c683..e40f619b62b1 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -371,9 +371,6 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, struct vxge_hw_ring_rxd_info ext_info; vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d", ring->ndev->name, __func__, __LINE__); - ring->pkts_processed = 0; - - vxge_hw_ring_replenish(ringh); do { prefetch((char *)dtr + L1_CACHE_BYTES); @@ -1588,6 +1585,36 @@ static int vxge_reset_vpath(struct vxgedev *vdev, int vp_id) return ret; } +/* Configure CI */ +static void vxge_config_ci_for_tti_rti(struct vxgedev *vdev) +{ + int i = 0; + + /* Enable CI for RTI */ + if (vdev->config.intr_type == MSI_X) { + for (i = 0; i < vdev->no_of_vpath; i++) { + struct __vxge_hw_ring *hw_ring; + + hw_ring = vdev->vpaths[i].ring.handle; + vxge_hw_vpath_dynamic_rti_ci_set(hw_ring); + } + } + + /* Enable CI for TTI */ + for (i = 0; i < vdev->no_of_vpath; i++) { + struct __vxge_hw_fifo *hw_fifo = vdev->vpaths[i].fifo.handle; + vxge_hw_vpath_tti_ci_set(hw_fifo); + /* + * For Inta (with or without napi), Set CI ON for only one + * vpath. (Have only one free running timer). + */ + if ((vdev->config.intr_type == INTA) && (i == 0)) + break; + } + + return; +} + static int do_vxge_reset(struct vxgedev *vdev, int event) { enum vxge_hw_status status; @@ -1753,6 +1780,9 @@ static int do_vxge_reset(struct vxgedev *vdev, int event) netif_tx_wake_all_queues(vdev->ndev); } + /* configure CI */ + vxge_config_ci_for_tti_rti(vdev); + out: vxge_debug_entryexit(VXGE_TRACE, "%s:%d Exiting...", __func__, __LINE__); @@ -1793,22 +1823,29 @@ static void vxge_reset(struct work_struct *work) */ static int vxge_poll_msix(struct napi_struct *napi, int budget) { - struct vxge_ring *ring = - container_of(napi, struct vxge_ring, napi); + struct vxge_ring *ring = container_of(napi, struct vxge_ring, napi); + int pkts_processed; int budget_org = budget; - ring->budget = budget; + ring->budget = budget; + ring->pkts_processed = 0; vxge_hw_vpath_poll_rx(ring->handle); + pkts_processed = ring->pkts_processed; if (ring->pkts_processed < budget_org) { napi_complete(napi); + /* Re enable the Rx interrupts for the vpath */ vxge_hw_channel_msix_unmask( (struct __vxge_hw_channel *)ring->handle, ring->rx_vector_no); + mmiowb(); } - return ring->pkts_processed; + /* We are copying and returning the local variable, in case if after + * clearing the msix interrupt above, if the interrupt fires right + * away which can preempt this NAPI thread */ + return pkts_processed; } static int vxge_poll_inta(struct napi_struct *napi, int budget) @@ -1824,6 +1861,7 @@ static int vxge_poll_inta(struct napi_struct *napi, int budget) for (i = 0; i < vdev->no_of_vpath; i++) { ring = &vdev->vpaths[i].ring; ring->budget = budget; + ring->pkts_processed = 0; vxge_hw_vpath_poll_rx(ring->handle); pkts_processed += ring->pkts_processed; budget -= ring->pkts_processed; @@ -2054,6 +2092,7 @@ static int vxge_open_vpaths(struct vxgedev *vdev) netdev_get_tx_queue(vdev->ndev, 0); vpath->fifo.indicate_max_pkts = vdev->config.fifo_indicate_max_pkts; + vpath->fifo.tx_vector_no = 0; vpath->ring.rx_vector_no = 0; vpath->ring.rx_csum = vdev->rx_csum; vpath->ring.rx_hwts = vdev->rx_hwts; @@ -2079,6 +2118,61 @@ static int vxge_open_vpaths(struct vxgedev *vdev) return VXGE_HW_OK; } +/** + * adaptive_coalesce_tx_interrupts - Changes the interrupt coalescing + * if the interrupts are not within a range + * @fifo: pointer to transmit fifo structure + * Description: The function changes boundary timer and restriction timer + * value depends on the traffic + * Return Value: None + */ +static void adaptive_coalesce_tx_interrupts(struct vxge_fifo *fifo) +{ + fifo->interrupt_count++; + if (jiffies > fifo->jiffies + HZ / 100) { + struct __vxge_hw_fifo *hw_fifo = fifo->handle; + + fifo->jiffies = jiffies; + if (fifo->interrupt_count > VXGE_T1A_MAX_TX_INTERRUPT_COUNT && + hw_fifo->rtimer != VXGE_TTI_RTIMER_ADAPT_VAL) { + hw_fifo->rtimer = VXGE_TTI_RTIMER_ADAPT_VAL; + vxge_hw_vpath_dynamic_tti_rtimer_set(hw_fifo); + } else if (hw_fifo->rtimer != 0) { + hw_fifo->rtimer = 0; + vxge_hw_vpath_dynamic_tti_rtimer_set(hw_fifo); + } + fifo->interrupt_count = 0; + } +} + +/** + * adaptive_coalesce_rx_interrupts - Changes the interrupt coalescing + * if the interrupts are not within a range + * @ring: pointer to receive ring structure + * Description: The function increases of decreases the packet counts within + * the ranges of traffic utilization, if the interrupts due to this ring are + * not within a fixed range. + * Return Value: Nothing + */ +static void adaptive_coalesce_rx_interrupts(struct vxge_ring *ring) +{ + ring->interrupt_count++; + if (jiffies > ring->jiffies + HZ / 100) { + struct __vxge_hw_ring *hw_ring = ring->handle; + + ring->jiffies = jiffies; + if (ring->interrupt_count > VXGE_T1A_MAX_INTERRUPT_COUNT && + hw_ring->rtimer != VXGE_RTI_RTIMER_ADAPT_VAL) { + hw_ring->rtimer = VXGE_RTI_RTIMER_ADAPT_VAL; + vxge_hw_vpath_dynamic_rti_rtimer_set(hw_ring); + } else if (hw_ring->rtimer != 0) { + hw_ring->rtimer = 0; + vxge_hw_vpath_dynamic_rti_rtimer_set(hw_ring); + } + ring->interrupt_count = 0; + } +} + /* * vxge_isr_napi * @irq: the irq of the device. @@ -2139,24 +2233,39 @@ static irqreturn_t vxge_isr_napi(int irq, void *dev_id) #ifdef CONFIG_PCI_MSI -static irqreturn_t -vxge_tx_msix_handle(int irq, void *dev_id) +static irqreturn_t vxge_tx_msix_handle(int irq, void *dev_id) { struct vxge_fifo *fifo = (struct vxge_fifo *)dev_id; + adaptive_coalesce_tx_interrupts(fifo); + + vxge_hw_channel_msix_mask((struct __vxge_hw_channel *)fifo->handle, + fifo->tx_vector_no); + + vxge_hw_channel_msix_clear((struct __vxge_hw_channel *)fifo->handle, + fifo->tx_vector_no); + VXGE_COMPLETE_VPATH_TX(fifo); + vxge_hw_channel_msix_unmask((struct __vxge_hw_channel *)fifo->handle, + fifo->tx_vector_no); + + mmiowb(); + return IRQ_HANDLED; } -static irqreturn_t -vxge_rx_msix_napi_handle(int irq, void *dev_id) +static irqreturn_t vxge_rx_msix_napi_handle(int irq, void *dev_id) { struct vxge_ring *ring = (struct vxge_ring *)dev_id; - /* MSIX_IDX for Rx is 1 */ + adaptive_coalesce_rx_interrupts(ring); + vxge_hw_channel_msix_mask((struct __vxge_hw_channel *)ring->handle, - ring->rx_vector_no); + ring->rx_vector_no); + + vxge_hw_channel_msix_clear((struct __vxge_hw_channel *)ring->handle, + ring->rx_vector_no); napi_schedule(&ring->napi); return IRQ_HANDLED; @@ -2173,14 +2282,20 @@ vxge_alarm_msix_handle(int irq, void *dev_id) VXGE_HW_VPATH_MSIX_ACTIVE) + VXGE_ALARM_MSIX_ID; for (i = 0; i < vdev->no_of_vpath; i++) { + /* Reduce the chance of loosing alarm interrupts by masking + * the vector. A pending bit will be set if an alarm is + * generated and on unmask the interrupt will be fired. + */ vxge_hw_vpath_msix_mask(vdev->vpaths[i].handle, msix_id); + vxge_hw_vpath_msix_clear(vdev->vpaths[i].handle, msix_id); + mmiowb(); status = vxge_hw_vpath_alarm_process(vdev->vpaths[i].handle, vdev->exec_mode); if (status == VXGE_HW_OK) { - vxge_hw_vpath_msix_unmask(vdev->vpaths[i].handle, - msix_id); + msix_id); + mmiowb(); continue; } vxge_debug_intr(VXGE_ERR, @@ -2299,6 +2414,9 @@ static int vxge_enable_msix(struct vxgedev *vdev) vpath->ring.rx_vector_no = (vpath->device_id * VXGE_HW_VPATH_MSIX_ACTIVE) + 1; + vpath->fifo.tx_vector_no = (vpath->device_id * + VXGE_HW_VPATH_MSIX_ACTIVE); + vxge_hw_vpath_msix_set(vpath->handle, tim_msix_id, VXGE_ALARM_MSIX_ID); } @@ -2474,8 +2592,9 @@ INTA_MODE: "%s:vxge:INTA", vdev->ndev->name); vxge_hw_device_set_intr_type(vdev->devh, VXGE_HW_INTR_MODE_IRQLINE); - vxge_hw_vpath_tti_ci_set(vdev->devh, - vdev->vpaths[0].device_id); + + vxge_hw_vpath_tti_ci_set(vdev->vpaths[0].fifo.handle); + ret = request_irq((int) vdev->pdev->irq, vxge_isr_napi, IRQF_SHARED, vdev->desc[0], vdev); @@ -2745,6 +2864,10 @@ static int vxge_open(struct net_device *dev) } netif_tx_start_all_queues(vdev->ndev); + + /* configure CI */ + vxge_config_ci_for_tti_rti(vdev); + goto out0; out2: @@ -3348,7 +3471,7 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, vxge_debug_init(VXGE_ERR, "%s: vpath memory allocation failed", vdev->ndev->name); - ret = -ENODEV; + ret = -ENOMEM; goto _out1; } @@ -3369,11 +3492,11 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, if (vdev->config.gro_enable) ndev->features |= NETIF_F_GRO; - if (register_netdev(ndev)) { + ret = register_netdev(ndev); + if (ret) { vxge_debug_init(vxge_hw_device_trace_level_get(hldev), "%s: %s : device registration failed!", ndev->name, __func__); - ret = -ENODEV; goto _out2; } @@ -3444,6 +3567,11 @@ static void vxge_device_unregister(struct __vxge_hw_device *hldev) /* in 2.6 will call stop() if device is up */ unregister_netdev(dev); + kfree(vdev->vpaths); + + /* we are safe to free it now */ + free_netdev(dev); + vxge_debug_init(vdev->level_trace, "%s: ethernet device unregistered", buf); vxge_debug_entryexit(vdev->level_trace, "%s: %s:%d Exiting...", buf, @@ -3799,7 +3927,7 @@ static void __devinit vxge_device_config_init( break; case MSI_X: - device_config->intr_mode = VXGE_HW_INTR_MODE_MSIX; + device_config->intr_mode = VXGE_HW_INTR_MODE_MSIX_ONE_SHOT; break; } @@ -4335,10 +4463,10 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) goto _exit1; } - if (pci_request_region(pdev, 0, VXGE_DRIVER_NAME)) { + ret = pci_request_region(pdev, 0, VXGE_DRIVER_NAME); + if (ret) { vxge_debug_init(VXGE_ERR, "%s : request regions failed", __func__); - ret = -ENODEV; goto _exit1; } @@ -4446,7 +4574,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) if (!img[i].is_valid) break; vxge_debug_init(VXGE_TRACE, "%s: EPROM %d, version " - "%d.%d.%d.%d\n", VXGE_DRIVER_NAME, i, + "%d.%d.%d.%d", VXGE_DRIVER_NAME, i, VXGE_EPROM_IMG_MAJOR(img[i].version), VXGE_EPROM_IMG_MINOR(img[i].version), VXGE_EPROM_IMG_FIX(img[i].version), @@ -4643,8 +4771,9 @@ _exit6: _exit5: vxge_device_unregister(hldev); _exit4: - pci_disable_sriov(pdev); + pci_set_drvdata(pdev, NULL); vxge_hw_device_terminate(hldev); + pci_disable_sriov(pdev); _exit3: iounmap(attr.bar0); _exit2: @@ -4655,7 +4784,7 @@ _exit0: kfree(ll_config); kfree(device_config); driver_config->config_dev_cnt--; - pci_set_drvdata(pdev, NULL); + driver_config->total_dev_cnt--; return ret; } @@ -4668,45 +4797,34 @@ _exit0: static void __devexit vxge_remove(struct pci_dev *pdev) { struct __vxge_hw_device *hldev; - struct vxgedev *vdev = NULL; - struct net_device *dev; - int i = 0; + struct vxgedev *vdev; + int i; hldev = pci_get_drvdata(pdev); - if (hldev == NULL) return; - dev = hldev->ndev; - vdev = netdev_priv(dev); + vdev = netdev_priv(hldev->ndev); vxge_debug_entryexit(vdev->level_trace, "%s:%d", __func__, __LINE__); - vxge_debug_init(vdev->level_trace, "%s : removing PCI device...", __func__); - vxge_device_unregister(hldev); - for (i = 0; i < vdev->no_of_vpath; i++) { + for (i = 0; i < vdev->no_of_vpath; i++) vxge_free_mac_add_list(&vdev->vpaths[i]); - vdev->vpaths[i].mcast_addr_cnt = 0; - vdev->vpaths[i].mac_addr_cnt = 0; - } - - kfree(vdev->vpaths); + vxge_device_unregister(hldev); + pci_set_drvdata(pdev, NULL); + /* Do not call pci_disable_sriov here, as it will break child devices */ + vxge_hw_device_terminate(hldev); iounmap(vdev->bar0); - - /* we are safe to free it now */ - free_netdev(dev); + pci_release_region(pdev, 0); + pci_disable_device(pdev); + driver_config->config_dev_cnt--; + driver_config->total_dev_cnt--; vxge_debug_init(vdev->level_trace, "%s:%d Device unregistered", __func__, __LINE__); - - vxge_hw_device_terminate(hldev); - - pci_disable_device(pdev); - pci_release_region(pdev, 0); - pci_set_drvdata(pdev, NULL); vxge_debug_entryexit(vdev->level_trace, "%s:%d Exiting...", __func__, __LINE__); } diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index 5746fedc356f..40474f0da576 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -59,11 +59,13 @@ #define VXGE_TTI_LTIMER_VAL 1000 #define VXGE_T1A_TTI_LTIMER_VAL 80 #define VXGE_TTI_RTIMER_VAL 0 +#define VXGE_TTI_RTIMER_ADAPT_VAL 10 #define VXGE_T1A_TTI_RTIMER_VAL 400 #define VXGE_RTI_BTIMER_VAL 250 #define VXGE_RTI_LTIMER_VAL 100 #define VXGE_RTI_RTIMER_VAL 0 -#define VXGE_FIFO_INDICATE_MAX_PKTS VXGE_DEF_FIFO_LENGTH +#define VXGE_RTI_RTIMER_ADAPT_VAL 15 +#define VXGE_FIFO_INDICATE_MAX_PKTS VXGE_DEF_FIFO_LENGTH #define VXGE_ISR_POLLING_CNT 8 #define VXGE_MAX_CONFIG_DEV 0xFF #define VXGE_EXEC_MODE_DISABLE 0 @@ -107,6 +109,14 @@ #define RTI_T1A_RX_UFC_C 50 #define RTI_T1A_RX_UFC_D 60 +/* + * The interrupt rate is maintained at 3k per second with the moderation + * parameters for most traffic but not all. This is the maximum interrupt + * count allowed per function with INTA or per vector in the case of + * MSI-X in a 10 millisecond time period. Enabled only for Titan 1A. + */ +#define VXGE_T1A_MAX_INTERRUPT_COUNT 100 +#define VXGE_T1A_MAX_TX_INTERRUPT_COUNT 200 /* Milli secs timer period */ #define VXGE_TIMER_DELAY 10000 @@ -247,6 +257,11 @@ struct vxge_fifo { int tx_steering_type; int indicate_max_pkts; + /* Adaptive interrupt moderation parameters used in T1A */ + unsigned long interrupt_count; + unsigned long jiffies; + + u32 tx_vector_no; /* Tx stats */ struct vxge_fifo_stats stats; } ____cacheline_aligned; @@ -271,6 +286,10 @@ struct vxge_ring { */ int driver_id; + /* Adaptive interrupt moderation parameters used in T1A */ + unsigned long interrupt_count; + unsigned long jiffies; + /* copy of the flag indicating whether rx_csum is to be used */ u32 rx_csum:1, rx_hwts:1; @@ -286,7 +305,7 @@ struct vxge_ring { int vlan_tag_strip; struct vlan_group *vlgrp; - int rx_vector_no; + u32 rx_vector_no; enum vxge_hw_status last_status; /* Rx stats */ diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c index 4c10d6c4075f..8674f331311c 100644 --- a/drivers/net/vxge/vxge-traffic.c +++ b/drivers/net/vxge/vxge-traffic.c @@ -218,6 +218,68 @@ exit: return status; } +void vxge_hw_vpath_tti_ci_set(struct __vxge_hw_fifo *fifo) +{ + struct vxge_hw_vpath_reg __iomem *vp_reg; + struct vxge_hw_vp_config *config; + u64 val64; + + if (fifo->config->enable != VXGE_HW_FIFO_ENABLE) + return; + + vp_reg = fifo->vp_reg; + config = container_of(fifo->config, struct vxge_hw_vp_config, fifo); + + if (config->tti.timer_ci_en != VXGE_HW_TIM_TIMER_CI_ENABLE) { + config->tti.timer_ci_en = VXGE_HW_TIM_TIMER_CI_ENABLE; + val64 = readq(&vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_TX]); + val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI; + fifo->tim_tti_cfg1_saved = val64; + writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_TX]); + } +} + +void vxge_hw_vpath_dynamic_rti_ci_set(struct __vxge_hw_ring *ring) +{ + u64 val64 = ring->tim_rti_cfg1_saved; + + val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI; + ring->tim_rti_cfg1_saved = val64; + writeq(val64, &ring->vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_RX]); +} + +void vxge_hw_vpath_dynamic_tti_rtimer_set(struct __vxge_hw_fifo *fifo) +{ + u64 val64 = fifo->tim_tti_cfg3_saved; + u64 timer = (fifo->rtimer * 1000) / 272; + + val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL(0x3ffffff); + if (timer) + val64 |= VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL(timer) | + VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_EVENT_SF(5); + + writeq(val64, &fifo->vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_TX]); + /* tti_cfg3_saved is not updated again because it is + * initialized at one place only - init time. + */ +} + +void vxge_hw_vpath_dynamic_rti_rtimer_set(struct __vxge_hw_ring *ring) +{ + u64 val64 = ring->tim_rti_cfg3_saved; + u64 timer = (ring->rtimer * 1000) / 272; + + val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL(0x3ffffff); + if (timer) + val64 |= VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL(timer) | + VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_EVENT_SF(4); + + writeq(val64, &ring->vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_RX]); + /* rti_cfg3_saved is not updated again because it is + * initialized at one place only - init time. + */ +} + /** * vxge_hw_channel_msix_mask - Mask MSIX Vector. * @channeh: Channel for rx or tx handle @@ -254,6 +316,23 @@ vxge_hw_channel_msix_unmask(struct __vxge_hw_channel *channel, int msix_id) } /** + * vxge_hw_channel_msix_clear - Unmask the MSIX Vector. + * @channel: Channel for rx or tx handle + * @msix_id: MSI ID + * + * The function unmasks the msix interrupt for the given msix_id + * if configured in MSIX oneshot mode + * + * Returns: 0 + */ +void vxge_hw_channel_msix_clear(struct __vxge_hw_channel *channel, int msix_id) +{ + __vxge_hw_pio_mem_write32_upper( + (u32) vxge_bVALn(vxge_mBIT(msix_id >> 2), 0, 32), + &channel->common_reg->clr_msix_one_shot_vec[msix_id % 4]); +} + +/** * vxge_hw_device_set_intr_type - Updates the configuration * with new interrupt type. * @hldev: HW device handle. @@ -2191,19 +2270,14 @@ vxge_hw_vpath_msix_set(struct __vxge_hw_vpath_handle *vp, int *tim_msix_id, if (vpath->hldev->config.intr_mode == VXGE_HW_INTR_MODE_MSIX_ONE_SHOT) { __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn( + VXGE_HW_ONE_SHOT_VECT0_EN_ONE_SHOT_VECT0_EN, + 0, 32), &vp_reg->one_shot_vect0_en); + __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn( VXGE_HW_ONE_SHOT_VECT1_EN_ONE_SHOT_VECT1_EN, 0, 32), &vp_reg->one_shot_vect1_en); - } - - if (vpath->hldev->config.intr_mode == - VXGE_HW_INTR_MODE_MSIX_ONE_SHOT) { __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn( VXGE_HW_ONE_SHOT_VECT2_EN_ONE_SHOT_VECT2_EN, 0, 32), &vp_reg->one_shot_vect2_en); - - __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn( - VXGE_HW_ONE_SHOT_VECT3_EN_ONE_SHOT_VECT3_EN, - 0, 32), &vp_reg->one_shot_vect3_en); } } @@ -2229,6 +2303,32 @@ vxge_hw_vpath_msix_mask(struct __vxge_hw_vpath_handle *vp, int msix_id) } /** + * vxge_hw_vpath_msix_clear - Clear MSIX Vector. + * @vp: Virtual Path handle. + * @msix_id: MSI ID + * + * The function clears the msix interrupt for the given msix_id + * + * Returns: 0, + * Otherwise, VXGE_HW_ERR_WRONG_IRQ if the msix index is out of range + * status. + * See also: + */ +void vxge_hw_vpath_msix_clear(struct __vxge_hw_vpath_handle *vp, int msix_id) +{ + struct __vxge_hw_device *hldev = vp->vpath->hldev; + + if ((hldev->config.intr_mode == VXGE_HW_INTR_MODE_MSIX_ONE_SHOT)) + __vxge_hw_pio_mem_write32_upper( + (u32) vxge_bVALn(vxge_mBIT((msix_id >> 2)), 0, 32), + &hldev->common_reg->clr_msix_one_shot_vec[msix_id % 4]); + else + __vxge_hw_pio_mem_write32_upper( + (u32) vxge_bVALn(vxge_mBIT((msix_id >> 2)), 0, 32), + &hldev->common_reg->clear_msix_mask_vect[msix_id % 4]); +} + +/** * vxge_hw_vpath_msix_unmask - Unmask the MSIX Vector. * @vp: Virtual Path handle. * @msix_id: MSI ID diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h index d48486d6afa1..9d9dfda4c7ab 100644 --- a/drivers/net/vxge/vxge-traffic.h +++ b/drivers/net/vxge/vxge-traffic.h @@ -2142,6 +2142,10 @@ void vxge_hw_device_clear_tx_rx( * Virtual Paths */ +void vxge_hw_vpath_dynamic_rti_rtimer_set(struct __vxge_hw_ring *ring); + +void vxge_hw_vpath_dynamic_tti_rtimer_set(struct __vxge_hw_fifo *fifo); + u32 vxge_hw_vpath_id( struct __vxge_hw_vpath_handle *vpath_handle); @@ -2245,6 +2249,8 @@ void vxge_hw_vpath_msix_mask(struct __vxge_hw_vpath_handle *vpath_handle, int msix_id); +void vxge_hw_vpath_msix_clear(struct __vxge_hw_vpath_handle *vp, int msix_id); + void vxge_hw_device_flush_io(struct __vxge_hw_device *devh); void @@ -2270,6 +2276,9 @@ void vxge_hw_channel_msix_unmask(struct __vxge_hw_channel *channelh, int msix_id); void +vxge_hw_channel_msix_clear(struct __vxge_hw_channel *channelh, int msix_id); + +void vxge_hw_channel_dtr_try_complete(struct __vxge_hw_channel *channel, void **dtrh); @@ -2282,7 +2291,8 @@ vxge_hw_channel_dtr_free(struct __vxge_hw_channel *channel, void *dtrh); int vxge_hw_channel_dtr_count(struct __vxge_hw_channel *channel); -void -vxge_hw_vpath_tti_ci_set(struct __vxge_hw_device *hldev, u32 vp_id); +void vxge_hw_vpath_tti_ci_set(struct __vxge_hw_fifo *fifo); + +void vxge_hw_vpath_dynamic_rti_ci_set(struct __vxge_hw_ring *ring); #endif diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h index ad2f99b9bcf3..581e21525e85 100644 --- a/drivers/net/vxge/vxge-version.h +++ b/drivers/net/vxge/vxge-version.h @@ -16,8 +16,8 @@ #define VXGE_VERSION_MAJOR "2" #define VXGE_VERSION_MINOR "5" -#define VXGE_VERSION_FIX "1" -#define VXGE_VERSION_BUILD "22082" +#define VXGE_VERSION_FIX "2" +#define VXGE_VERSION_BUILD "22259" #define VXGE_VERSION_FOR "k" #define VXGE_FW_VER(maj, min, bld) (((maj) << 16) + ((min) << 8) + (bld)) diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 32bf79e6a320..a9111e1161fd 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -1945,7 +1945,8 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, static int ar9170_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn) + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size) { switch (action) { case IEEE80211_AMPDU_RX_START: diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index e43210c8585c..a6c6a466000f 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -108,12 +108,14 @@ enum ath_cipher { * struct ath_ops - Register read/write operations * * @read: Register read + * @multi_read: Multiple register read * @write: Register write * @enable_write_buffer: Enable multiple register writes * @write_flush: flush buffered register writes and disable buffering */ struct ath_ops { unsigned int (*read)(void *, u32 reg_offset); + void (*multi_read)(void *, u32 *addr, u32 *val, u16 count); void (*write)(void *, u32 val, u32 reg_offset); void (*enable_write_buffer)(void *); void (*write_flush) (void *); diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index e0793319389d..e18a9aa7b6ca 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -40,6 +40,17 @@ config ATH5K_DEBUG modprobe ath5k debug=0x00000400 +config ATH5K_TRACER + bool "Atheros 5xxx tracer" + depends on ATH5K + depends on EVENT_TRACING + ---help--- + Say Y here to enable tracepoints for the ath5k driver + using the kernel tracing infrastructure. Select this + option if you are interested in debugging the driver. + + If unsure, say N. + config ATH5K_AHB bool "Atheros 5xxx AHB bus support" depends on (ATHEROS_AR231X && !PCI) diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index 707cde149248..ae84b86c3bf2 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -31,7 +31,8 @@ static void ath5k_ahb_read_cachesize(struct ath_common *common, int *csz) *csz = L1_CACHE_BYTES >> 2; } -bool ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data) +static bool +ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data) { struct ath5k_softc *sc = common->priv; struct platform_device *pdev = to_platform_device(sc->dev); @@ -46,10 +47,10 @@ bool ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data) eeprom += off; if (eeprom > eeprom_end) - return -EINVAL; + return false; *data = *eeprom; - return 0; + return true; } int ath5k_hw_read_srev(struct ath5k_hw *ah) diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 407e39c2b10b..e43175a89d67 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -210,14 +210,9 @@ /* Initial values */ #define AR5K_INIT_CYCRSSI_THR1 2 -/* Tx retry limits */ -#define AR5K_INIT_SH_RETRY 10 -#define AR5K_INIT_LG_RETRY AR5K_INIT_SH_RETRY -/* For station mode */ -#define AR5K_INIT_SSH_RETRY 32 -#define AR5K_INIT_SLG_RETRY AR5K_INIT_SSH_RETRY -#define AR5K_INIT_TX_RETRY 10 - +/* Tx retry limit defaults from standard */ +#define AR5K_INIT_RETRY_SHORT 7 +#define AR5K_INIT_RETRY_LONG 4 /* Slot time */ #define AR5K_INIT_SLOT_TIME_TURBO 6 @@ -1057,7 +1052,9 @@ struct ath5k_hw { #define ah_modes ah_capabilities.cap_mode #define ah_ee_version ah_capabilities.cap_eeprom.ee_version - u32 ah_limit_tx_retries; + u8 ah_retry_long; + u8 ah_retry_short; + u8 ah_coverage_class; bool ah_ack_bitrate_high; u8 ah_bwmode; @@ -1067,7 +1064,6 @@ struct ath5k_hw { u8 ah_ant_mode; u8 ah_tx_ant; u8 ah_def_ant; - bool ah_software_retry; struct ath5k_capabilities ah_capabilities; @@ -1250,6 +1246,8 @@ int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue, int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, struct ath5k_txq_info *queue_info); +void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah, + unsigned int queue); u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue); void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue); int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue); diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index cdac5cff0177..c71fdbb4c439 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -118,8 +118,8 @@ int ath5k_hw_init(struct ath5k_softc *sc) ah->ah_bwmode = AR5K_BWMODE_DEFAULT; ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; ah->ah_imr = 0; - ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY; - ah->ah_software_retry = false; + ah->ah_retry_short = AR5K_INIT_RETRY_SHORT; + ah->ah_retry_long = AR5K_INIT_RETRY_LONG; ah->ah_ant_mode = AR5K_ANTMODE_DEFAULT; ah->ah_noise_floor = -95; /* until first NF calibration is run */ sc->ani_state.ani_mode = ATH5K_ANI_MODE_AUTO; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 09ae4ef0fd51..dbc45e085434 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -61,6 +61,9 @@ #include "debug.h" #include "ani.h" +#define CREATE_TRACE_POINTS +#include "trace.h" + int ath5k_modparam_nohwcrypt; module_param_named(nohwcrypt, ath5k_modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); @@ -242,73 +245,68 @@ static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *re \********************/ /* - * Convert IEEE channel number to MHz frequency. - */ -static inline short -ath5k_ieee2mhz(short chan) -{ - if (chan <= 14 || chan >= 27) - return ieee80211chan2mhz(chan); - else - return 2212 + chan * 20; -} - -/* * Returns true for the channel numbers used without all_channels modparam. */ -static bool ath5k_is_standard_channel(short chan) +static bool ath5k_is_standard_channel(short chan, enum ieee80211_band band) { - return ((chan <= 14) || - /* UNII 1,2 */ - ((chan & 3) == 0 && chan >= 36 && chan <= 64) || + if (band == IEEE80211_BAND_2GHZ && chan <= 14) + return true; + + return /* UNII 1,2 */ + (((chan & 3) == 0 && chan >= 36 && chan <= 64) || /* midband */ ((chan & 3) == 0 && chan >= 100 && chan <= 140) || /* UNII-3 */ - ((chan & 3) == 1 && chan >= 149 && chan <= 165)); + ((chan & 3) == 1 && chan >= 149 && chan <= 165) || + /* 802.11j 5.030-5.080 GHz (20MHz) */ + (chan == 8 || chan == 12 || chan == 16) || + /* 802.11j 4.9GHz (20MHz) */ + (chan == 184 || chan == 188 || chan == 192 || chan == 196)); } static unsigned int -ath5k_copy_channels(struct ath5k_hw *ah, - struct ieee80211_channel *channels, - unsigned int mode, - unsigned int max) +ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, + unsigned int mode, unsigned int max) { - unsigned int i, count, size, chfreq, freq, ch; - - if (!test_bit(mode, ah->ah_modes)) - return 0; + unsigned int count, size, chfreq, freq, ch; + enum ieee80211_band band; switch (mode) { case AR5K_MODE_11A: /* 1..220, but 2GHz frequencies are filtered by check_channel */ - size = 220 ; + size = 220; chfreq = CHANNEL_5GHZ; + band = IEEE80211_BAND_5GHZ; break; case AR5K_MODE_11B: case AR5K_MODE_11G: size = 26; chfreq = CHANNEL_2GHZ; + band = IEEE80211_BAND_2GHZ; break; default: ATH5K_WARN(ah->ah_sc, "bad mode, not copying channels\n"); return 0; } - for (i = 0, count = 0; i < size && max > 0; i++) { - ch = i + 1 ; - freq = ath5k_ieee2mhz(ch); + count = 0; + for (ch = 1; ch <= size && count < max; ch++) { + freq = ieee80211_channel_to_frequency(ch, band); + + if (freq == 0) /* mapping failed - not a standard channel */ + continue; /* Check if channel is supported by the chipset */ if (!ath5k_channel_ok(ah, freq, chfreq)) continue; - if (!modparam_all_channels && !ath5k_is_standard_channel(ch)) + if (!modparam_all_channels && + !ath5k_is_standard_channel(ch, band)) continue; /* Write channel info and increment counter */ channels[count].center_freq = freq; - channels[count].band = (chfreq == CHANNEL_2GHZ) ? - IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + channels[count].band = band; switch (mode) { case AR5K_MODE_11A: case AR5K_MODE_11G: @@ -319,7 +317,6 @@ ath5k_copy_channels(struct ath5k_hw *ah, } count++; - max--; } return count; @@ -364,7 +361,7 @@ ath5k_setup_bands(struct ieee80211_hw *hw) sband->n_bitrates = 12; sband->channels = sc->channels; - sband->n_channels = ath5k_copy_channels(ah, sband->channels, + sband->n_channels = ath5k_setup_channels(ah, sband->channels, AR5K_MODE_11G, max_c); hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; @@ -390,7 +387,7 @@ ath5k_setup_bands(struct ieee80211_hw *hw) } sband->channels = sc->channels; - sband->n_channels = ath5k_copy_channels(ah, sband->channels, + sband->n_channels = ath5k_setup_channels(ah, sband->channels, AR5K_MODE_11B, max_c); hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; @@ -410,7 +407,7 @@ ath5k_setup_bands(struct ieee80211_hw *hw) sband->n_bitrates = 8; sband->channels = &sc->channels[count_c]; - sband->n_channels = ath5k_copy_channels(ah, sband->channels, + sband->n_channels = ath5k_setup_channels(ah, sband->channels, AR5K_MODE_11A, max_c); hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; @@ -445,18 +442,6 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) return ath5k_reset(sc, chan, true); } -static void -ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode) -{ - sc->curmode = mode; - - if (mode == AR5K_MODE_11A) { - sc->curband = &sc->sbands[IEEE80211_BAND_5GHZ]; - } else { - sc->curband = &sc->sbands[IEEE80211_BAND_2GHZ]; - } -} - struct ath_vif_iter_data { const u8 *hw_macaddr; u8 mask[ETH_ALEN]; @@ -569,7 +554,7 @@ ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix) "hw_rix out of bounds: %x\n", hw_rix)) return 0; - rix = sc->rate_idx[sc->curband->band][hw_rix]; + rix = sc->rate_idx[sc->curchan->band][hw_rix]; if (WARN(rix < 0, "invalid hw_rix: %x\n", hw_rix)) rix = 0; @@ -1379,7 +1364,7 @@ ath5k_receive_frame(struct ath5k_softc *sc, struct sk_buff *skb, rxs->flag |= RX_FLAG_TSFT; rxs->freq = sc->curchan->center_freq; - rxs->band = sc->curband->band; + rxs->band = sc->curchan->band; rxs->signal = sc->ah->ah_noise_floor + rs->rs_rssi; @@ -1394,10 +1379,10 @@ ath5k_receive_frame(struct ath5k_softc *sc, struct sk_buff *skb, rxs->flag |= ath5k_rx_decrypted(sc, skb, rs); if (rxs->rate_idx >= 0 && rs->rs_rate == - sc->curband->bitrates[rxs->rate_idx].hw_value_short) + sc->sbands[sc->curchan->band].bitrates[rxs->rate_idx].hw_value_short) rxs->flag |= RX_FLAG_SHORTPRE; - ath5k_debug_dump_skb(sc, skb, "RX ", 0); + trace_ath5k_rx(sc, skb); ath5k_update_beacon_rssi(sc, skb, rs->rs_rssi); @@ -1542,7 +1527,7 @@ ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, unsigned long flags; int padsize; - ath5k_debug_dump_skb(sc, skb, "TX ", 1); + trace_ath5k_tx(sc, skb, txq); /* * The hardware expects the header padded to 4 byte boundaries. @@ -1591,7 +1576,7 @@ drop_packet: static void ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb, - struct ath5k_tx_status *ts) + struct ath5k_txq *txq, struct ath5k_tx_status *ts) { struct ieee80211_tx_info *info; int i; @@ -1643,6 +1628,7 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb, else sc->stats.antenna_tx[0]++; /* invalid */ + trace_ath5k_tx_complete(sc, skb, txq, ts); ieee80211_tx_status(sc->hw, skb); } @@ -1679,7 +1665,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) dma_unmap_single(sc->dev, bf->skbaddr, skb->len, DMA_TO_DEVICE); - ath5k_tx_frame_completed(sc, skb, &ts); + ath5k_tx_frame_completed(sc, skb, txq, &ts); } /* @@ -1821,8 +1807,6 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) goto out; } - ath5k_debug_dump_skb(sc, skb, "BC ", 1); - ath5k_txbuf_free_skb(sc, avf->bbuf); avf->bbuf->skb = skb; ret = ath5k_beacon_setup(sc, avf->bbuf); @@ -1917,6 +1901,8 @@ ath5k_beacon_send(struct ath5k_softc *sc) sc->opmode == NL80211_IFTYPE_MESH_POINT) ath5k_beacon_update(sc->hw, vif); + trace_ath5k_tx(sc, bf->skb, &sc->txqs[sc->bhalq]); + ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr); ath5k_hw_start_tx_dma(ah, sc->bhalq); ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n", @@ -2417,7 +2403,8 @@ ath5k_init_softc(struct ath5k_softc *sc, const struct ath_bus_ops *bus_ops) /* set up multi-rate retry capabilities */ if (sc->ah->ah_version == AR5K_AR5212) { hw->max_rates = 4; - hw->max_rate_tries = 11; + hw->max_rate_tries = max(AR5K_INIT_RETRY_SHORT, + AR5K_INIT_RETRY_LONG); } hw->vif_data_size = sizeof(struct ath5k_vif); @@ -2554,7 +2541,6 @@ ath5k_init_hw(struct ath5k_softc *sc) * and then setup of the interrupt mask. */ sc->curchan = sc->hw->conf.channel; - sc->curband = &sc->sbands[sc->curchan->band]; sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB; @@ -2681,10 +2667,8 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan, * so we should also free any remaining * tx buffers */ ath5k_drain_tx_buffs(sc); - if (chan) { + if (chan) sc->curchan = chan; - sc->curband = &sc->sbands[chan->band]; - } ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL, skip_pcu); if (ret) { @@ -2782,12 +2766,6 @@ ath5k_init(struct ieee80211_hw *hw) goto err; } - /* NB: setup here so ath5k_rate_update is happy */ - if (test_bit(AR5K_MODE_11A, ah->ah_modes)) - ath5k_setcurmode(sc, AR5K_MODE_11A); - else - ath5k_setcurmode(sc, AR5K_MODE_11B); - /* * Allocate tx+rx descriptors and populate the lists. */ diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 6d511476e4d2..8f919dca95f1 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -183,8 +183,6 @@ struct ath5k_softc { enum nl80211_iftype opmode; struct ath5k_hw *ah; /* Atheros HW */ - struct ieee80211_supported_band *curband; - #ifdef CONFIG_ATH5K_DEBUG struct ath5k_dbg_info debug; /* debug info */ #endif /* CONFIG_ATH5K_DEBUG */ @@ -202,7 +200,6 @@ struct ath5k_softc { #define ATH_STAT_STARTED 4 /* opened & irqs enabled */ unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ - unsigned int curmode; /* current phy mode */ struct ieee80211_channel *curchan; /* current h/w channel */ u16 nvifs; diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c index 31cad80e9b01..f77e8a703c5c 100644 --- a/drivers/net/wireless/ath/ath5k/caps.c +++ b/drivers/net/wireless/ath/ath5k/caps.c @@ -32,23 +32,24 @@ */ int ath5k_hw_set_capabilities(struct ath5k_hw *ah) { + struct ath5k_capabilities *caps = &ah->ah_capabilities; u16 ee_header; /* Capabilities stored in the EEPROM */ - ee_header = ah->ah_capabilities.cap_eeprom.ee_header; + ee_header = caps->cap_eeprom.ee_header; if (ah->ah_version == AR5K_AR5210) { /* * Set radio capabilities * (The AR5110 only supports the middle 5GHz band) */ - ah->ah_capabilities.cap_range.range_5ghz_min = 5120; - ah->ah_capabilities.cap_range.range_5ghz_max = 5430; - ah->ah_capabilities.cap_range.range_2ghz_min = 0; - ah->ah_capabilities.cap_range.range_2ghz_max = 0; + caps->cap_range.range_5ghz_min = 5120; + caps->cap_range.range_5ghz_max = 5430; + caps->cap_range.range_2ghz_min = 0; + caps->cap_range.range_2ghz_max = 0; /* Set supported modes */ - __set_bit(AR5K_MODE_11A, ah->ah_capabilities.cap_mode); + __set_bit(AR5K_MODE_11A, caps->cap_mode); } else { /* * XXX The tranceiver supports frequencies from 4920 to 6100GHz @@ -56,9 +57,8 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah) * XXX current ieee80211 implementation because the IEEE * XXX channel mapping does not support negative channel * XXX numbers (2312MHz is channel -19). Of course, this - * XXX doesn't matter because these channels are out of range - * XXX but some regulation domains like MKK (Japan) will - * XXX support frequencies somewhere around 4.8GHz. + * XXX doesn't matter because these channels are out of the + * XXX legal range. */ /* @@ -66,13 +66,14 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah) */ if (AR5K_EEPROM_HDR_11A(ee_header)) { - /* 4920 */ - ah->ah_capabilities.cap_range.range_5ghz_min = 5005; - ah->ah_capabilities.cap_range.range_5ghz_max = 6100; + if (ath_is_49ghz_allowed(caps->cap_eeprom.ee_regdomain)) + caps->cap_range.range_5ghz_min = 4920; + else + caps->cap_range.range_5ghz_min = 5005; + caps->cap_range.range_5ghz_max = 6100; /* Set supported modes */ - __set_bit(AR5K_MODE_11A, - ah->ah_capabilities.cap_mode); + __set_bit(AR5K_MODE_11A, caps->cap_mode); } /* Enable 802.11b if a 2GHz capable radio (2111/5112) is @@ -81,32 +82,29 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah) (AR5K_EEPROM_HDR_11G(ee_header) && ah->ah_version != AR5K_AR5211)) { /* 2312 */ - ah->ah_capabilities.cap_range.range_2ghz_min = 2412; - ah->ah_capabilities.cap_range.range_2ghz_max = 2732; + caps->cap_range.range_2ghz_min = 2412; + caps->cap_range.range_2ghz_max = 2732; if (AR5K_EEPROM_HDR_11B(ee_header)) - __set_bit(AR5K_MODE_11B, - ah->ah_capabilities.cap_mode); + __set_bit(AR5K_MODE_11B, caps->cap_mode); if (AR5K_EEPROM_HDR_11G(ee_header) && ah->ah_version != AR5K_AR5211) - __set_bit(AR5K_MODE_11G, - ah->ah_capabilities.cap_mode); + __set_bit(AR5K_MODE_11G, caps->cap_mode); } } /* Set number of supported TX queues */ if (ah->ah_version == AR5K_AR5210) - ah->ah_capabilities.cap_queues.q_tx_num = - AR5K_NUM_TX_QUEUES_NOQCU; + caps->cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES_NOQCU; else - ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES; + caps->cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES; /* newer hardware has PHY error counters */ if (ah->ah_mac_srev >= AR5K_SREV_AR5213A) - ah->ah_capabilities.cap_has_phyerr_counters = true; + caps->cap_has_phyerr_counters = true; else - ah->ah_capabilities.cap_has_phyerr_counters = false; + caps->cap_has_phyerr_counters = false; return 0; } diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index d2f84d76bb07..0230f30e9e9a 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -308,8 +308,6 @@ static const struct { { ATH5K_DEBUG_CALIBRATE, "calib", "periodic calibration" }, { ATH5K_DEBUG_TXPOWER, "txpower", "transmit power setting" }, { ATH5K_DEBUG_LED, "led", "LED management" }, - { ATH5K_DEBUG_DUMP_RX, "dumprx", "print received skb content" }, - { ATH5K_DEBUG_DUMP_TX, "dumptx", "print transmit skb content" }, { ATH5K_DEBUG_DUMPBANDS, "dumpbands", "dump bands" }, { ATH5K_DEBUG_DMA, "dma", "dma start/stop" }, { ATH5K_DEBUG_ANI, "ani", "adaptive noise immunity" }, @@ -1036,24 +1034,6 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) } void -ath5k_debug_dump_skb(struct ath5k_softc *sc, - struct sk_buff *skb, const char *prefix, int tx) -{ - char buf[16]; - - if (likely(!((tx && (sc->debug.level & ATH5K_DEBUG_DUMP_TX)) || - (!tx && (sc->debug.level & ATH5K_DEBUG_DUMP_RX))))) - return; - - snprintf(buf, sizeof(buf), "%s %s", wiphy_name(sc->hw->wiphy), prefix); - - print_hex_dump_bytes(buf, DUMP_PREFIX_NONE, skb->data, - min(200U, skb->len)); - - printk(KERN_DEBUG "\n"); -} - -void ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf) { struct ath5k_desc *ds = bf->desc; diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h index 3e34428d5126..b0355aef68d3 100644 --- a/drivers/net/wireless/ath/ath5k/debug.h +++ b/drivers/net/wireless/ath/ath5k/debug.h @@ -116,8 +116,6 @@ enum ath5k_debug_level { ATH5K_DEBUG_CALIBRATE = 0x00000020, ATH5K_DEBUG_TXPOWER = 0x00000040, ATH5K_DEBUG_LED = 0x00000080, - ATH5K_DEBUG_DUMP_RX = 0x00000100, - ATH5K_DEBUG_DUMP_TX = 0x00000200, ATH5K_DEBUG_DUMPBANDS = 0x00000400, ATH5K_DEBUG_DMA = 0x00000800, ATH5K_DEBUG_ANI = 0x00002000, @@ -152,10 +150,6 @@ void ath5k_debug_dump_bands(struct ath5k_softc *sc); void -ath5k_debug_dump_skb(struct ath5k_softc *sc, - struct sk_buff *skb, const char *prefix, int tx); - -void ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf); #else /* no debugging */ @@ -182,10 +176,6 @@ static inline void ath5k_debug_dump_bands(struct ath5k_softc *sc) {} static inline void -ath5k_debug_dump_skb(struct ath5k_softc *sc, - struct sk_buff *skb, const char *prefix, int tx) {} - -static inline void ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf) {} #endif /* ifdef CONFIG_ATH5K_DEBUG */ diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index 80e625608bac..b6561f785c6e 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -72,7 +72,6 @@ static int ath5k_eeprom_init_header(struct ath5k_hw *ah) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - int ret; u16 val; u32 cksum, offset, eep_max = AR5K_EEPROM_INFO_MAX; @@ -192,7 +191,7 @@ static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset, struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; u32 o = *offset; u16 val; - int ret, i = 0; + int i = 0; AR5K_EEPROM_READ(o++, val); ee->ee_switch_settling[mode] = (val >> 8) & 0x7f; @@ -252,7 +251,6 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; u32 o = *offset; u16 val; - int ret; ee->ee_n_piers[mode] = 0; AR5K_EEPROM_READ(o++, val); @@ -515,7 +513,6 @@ ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max, int o = *offset; int i = 0; u8 freq1, freq2; - int ret; u16 val; ee->ee_n_piers[mode] = 0; @@ -551,7 +548,7 @@ ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; struct ath5k_chan_pcal_info *pcal = ee->ee_pwr_cal_a; - int i, ret; + int i; u16 val; u8 mask; @@ -970,7 +967,6 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) u32 offset; u8 i, c; u16 val; - int ret; u8 pd_gains = 0; /* Count how many curves we have and @@ -1228,7 +1224,7 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) struct ath5k_chan_pcal_info *chinfo; u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; u32 offset; - int idx, i, ret; + int idx, i; u16 val; u8 pd_gains = 0; @@ -1419,7 +1415,7 @@ ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode) u8 *rate_target_pwr_num; u32 offset; u16 val; - int ret, i; + int i; offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1); rate_target_pwr_num = &ee->ee_rate_target_pwr_num[mode]; @@ -1593,7 +1589,7 @@ ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) struct ath5k_edge_power *rep; unsigned int fmask, pmask; unsigned int ctl_mode; - int ret, i, j; + int i, j; u32 offset; u16 val; @@ -1733,16 +1729,12 @@ int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) u8 mac_d[ETH_ALEN] = {}; u32 total, offset; u16 data; - int octet, ret; + int octet; - ret = ath5k_hw_nvram_read(ah, 0x20, &data); - if (ret) - return ret; + AR5K_EEPROM_READ(0x20, data); for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) { - ret = ath5k_hw_nvram_read(ah, offset, &data); - if (ret) - return ret; + AR5K_EEPROM_READ(offset, data); total += data; mac_d[octet + 1] = data & 0xff; diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h index 7c09e150dbdc..6511c27d938e 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.h +++ b/drivers/net/wireless/ath/ath5k/eeprom.h @@ -241,9 +241,8 @@ enum ath5k_eeprom_freq_bands{ #define AR5K_SPUR_SYMBOL_WIDTH_TURBO_100Hz 6250 #define AR5K_EEPROM_READ(_o, _v) do { \ - ret = ath5k_hw_nvram_read(ah, (_o), &(_v)); \ - if (ret) \ - return ret; \ + if (!ath5k_hw_nvram_read(ah, (_o), &(_v))) \ + return -EIO; \ } while (0) #define AR5K_EEPROM_READ_HDR(_o, _v) \ @@ -269,29 +268,6 @@ enum ath5k_ctl_mode { AR5K_CTL_MODE_M = 15, }; -/* Default CTL ids for the 3 main reg domains. - * Atheros only uses these by default but vendors - * can have up to 32 different CTLs for different - * scenarios. Note that theese values are ORed with - * the mode id (above) so we can have up to 24 CTL - * datasets out of these 3 main regdomains. That leaves - * 8 ids that can be used by vendors and since 0x20 is - * missing from HAL sources i guess this is the set of - * custom CTLs vendors can use. */ -#define AR5K_CTL_FCC 0x10 -#define AR5K_CTL_CUSTOM 0x20 -#define AR5K_CTL_ETSI 0x30 -#define AR5K_CTL_MKK 0x40 - -/* Indicates a CTL with only mode set and - * no reg domain mapping, such CTLs are used - * for world roaming domains or simply when - * a reg domain is not set */ -#define AR5K_CTL_NO_REGDOMAIN 0xf0 - -/* Indicates an empty (invalid) CTL */ -#define AR5K_CTL_NO_CTL 0xff - /* Per channel calibration data, used for power table setup */ struct ath5k_chan_pcal_info_rf5111 { /* Power levels in half dbm units diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index d76d68c99f72..36a51995a7bc 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -226,6 +226,7 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) struct ath5k_hw *ah = sc->ah; struct ieee80211_conf *conf = &hw->conf; int ret = 0; + int i; mutex_lock(&sc->lock); @@ -243,6 +244,14 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2)); } + if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { + ah->ah_retry_long = conf->long_frame_max_tx_count; + ah->ah_retry_short = conf->short_frame_max_tx_count; + + for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) + ath5k_hw_set_tx_retry_limits(ah, i); + } + /* TODO: * 1) Move this on config_interface and handle each case * separately eg. when we have only one STA vif, use diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index 7f8c5b0e9d2a..66598a0d1df0 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -69,7 +69,8 @@ static void ath5k_pci_read_cachesize(struct ath_common *common, int *csz) /* * Read from eeprom */ -bool ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data) +static bool +ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data) { struct ath5k_hw *ah = (struct ath5k_hw *) common->ah; u32 status, timeout; @@ -90,15 +91,15 @@ bool ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data) status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS); if (status & AR5K_EEPROM_STAT_RDDONE) { if (status & AR5K_EEPROM_STAT_RDERR) - return -EIO; + return false; *data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) & 0xffff); - return 0; + return true; } udelay(15); } - return -ETIMEDOUT; + return false; } int ath5k_hw_read_srev(struct ath5k_hw *ah) diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 78c26fdccad1..d673ab2f6cda 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -282,6 +282,34 @@ int ath5k_hw_phy_disable(struct ath5k_hw *ah) return 0; } +/* + * Wait for synth to settle + */ +static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + /* + * On 5211+ read activation -> rx delay + * and use it (100ns steps). + */ + if (ah->ah_version != AR5K_AR5210) { + u32 delay; + delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) & + AR5K_PHY_RX_DELAY_M; + delay = (channel->hw_value & CHANNEL_CCK) ? + ((delay << 2) / 22) : (delay / 10); + if (ah->ah_bwmode == AR5K_BWMODE_10MHZ) + delay = delay << 1; + if (ah->ah_bwmode == AR5K_BWMODE_5MHZ) + delay = delay << 2; + /* XXX: /2 on turbo ? Let's be safe + * for now */ + udelay(100 + delay); + } else { + mdelay(1); + } +} + /**********************\ * RF Gain optimization * @@ -3237,6 +3265,13 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, /* Failed */ if (i >= 100) return -EIO; + + /* Set channel and wait for synth */ + ret = ath5k_hw_channel(ah, channel); + if (ret) + return ret; + + ath5k_hw_wait_for_synth(ah, channel); } /* @@ -3251,13 +3286,53 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, if (ret) return ret; + /* Write OFDM timings on 5212*/ + if (ah->ah_version == AR5K_AR5212 && + channel->hw_value & CHANNEL_OFDM) { + + ret = ath5k_hw_write_ofdm_timings(ah, channel); + if (ret) + return ret; + + /* Spur info is available only from EEPROM versions + * greater than 5.3, but the EEPROM routines will use + * static values for older versions */ + if (ah->ah_mac_srev >= AR5K_SREV_AR5424) + ath5k_hw_set_spur_mitigation_filter(ah, + channel); + } + + /* If we used fast channel switching + * we are done, release RF bus and + * fire up NF calibration. + * + * Note: Only NF calibration due to + * channel change, not AGC calibration + * since AGC is still running ! + */ + if (fast) { + /* + * Release RF Bus grant + */ + AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_RFBUS_REQ, + AR5K_PHY_RFBUS_REQ_REQUEST); + + /* + * Start NF calibration + */ + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_NF); + + return ret; + } + /* * For 5210 we do all initialization using * initvals, so we don't have to modify * any settings (5210 also only supports * a/aturbo modes) */ - if ((ah->ah_version != AR5K_AR5210) && !fast) { + if (ah->ah_version != AR5K_AR5210) { /* * Write initial RF gain settings @@ -3276,22 +3351,6 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, if (ret) return ret; - /* Write OFDM timings on 5212*/ - if (ah->ah_version == AR5K_AR5212 && - channel->hw_value & CHANNEL_OFDM) { - - ret = ath5k_hw_write_ofdm_timings(ah, channel); - if (ret) - return ret; - - /* Spur info is available only from EEPROM versions - * greater than 5.3, but the EEPROM routines will use - * static values for older versions */ - if (ah->ah_mac_srev >= AR5K_SREV_AR5424) - ath5k_hw_set_spur_mitigation_filter(ah, - channel); - } - /*Enable/disable 802.11b mode on 5111 (enable 2111 frequency converter + CCK)*/ if (ah->ah_radio == AR5K_RF5111) { @@ -3322,47 +3381,20 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, */ ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); + ath5k_hw_wait_for_synth(ah, channel); + /* - * On 5211+ read activation -> rx delay - * and use it. + * Perform ADC test to see if baseband is ready + * Set tx hold and check adc test register */ - if (ah->ah_version != AR5K_AR5210) { - u32 delay; - delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) & - AR5K_PHY_RX_DELAY_M; - delay = (channel->hw_value & CHANNEL_CCK) ? - ((delay << 2) / 22) : (delay / 10); - if (ah->ah_bwmode == AR5K_BWMODE_10MHZ) - delay = delay << 1; - if (ah->ah_bwmode == AR5K_BWMODE_5MHZ) - delay = delay << 2; - /* XXX: /2 on turbo ? Let's be safe - * for now */ - udelay(100 + delay); - } else { - mdelay(1); - } - - if (fast) - /* - * Release RF Bus grant - */ - AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_RFBUS_REQ, - AR5K_PHY_RFBUS_REQ_REQUEST); - else { - /* - * Perform ADC test to see if baseband is ready - * Set tx hold and check adc test register - */ - phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1); - ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1); - for (i = 0; i <= 20; i++) { - if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10)) - break; - udelay(200); - } - ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1); + phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1); + ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1); + for (i = 0; i <= 20; i++) { + if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10)) + break; + udelay(200); } + ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1); /* * Start automatic gain control calibration diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 2c9c9e793d4e..3343fb9e4940 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -228,24 +228,9 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, /* * Set tx retry limits on DCU */ -static void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah, - unsigned int queue) +void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah, + unsigned int queue) { - u32 retry_lg, retry_sh; - - /* - * Calculate and set retry limits - */ - if (ah->ah_software_retry) { - /* XXX Need to test this */ - retry_lg = ah->ah_limit_tx_retries; - retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ? - AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg; - } else { - retry_lg = AR5K_INIT_LG_RETRY; - retry_sh = AR5K_INIT_SH_RETRY; - } - /* Single data queue on AR5210 */ if (ah->ah_version == AR5K_AR5210) { struct ath5k_txq_info *tq = &ah->ah_txq[queue]; @@ -255,25 +240,26 @@ static void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah, ath5k_hw_reg_write(ah, (tq->tqi_cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S) - | AR5K_REG_SM(AR5K_INIT_SLG_RETRY, - AR5K_NODCU_RETRY_LMT_SLG_RETRY) - | AR5K_REG_SM(AR5K_INIT_SSH_RETRY, - AR5K_NODCU_RETRY_LMT_SSH_RETRY) - | AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY) - | AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY), + | AR5K_REG_SM(ah->ah_retry_long, + AR5K_NODCU_RETRY_LMT_SLG_RETRY) + | AR5K_REG_SM(ah->ah_retry_short, + AR5K_NODCU_RETRY_LMT_SSH_RETRY) + | AR5K_REG_SM(ah->ah_retry_long, + AR5K_NODCU_RETRY_LMT_LG_RETRY) + | AR5K_REG_SM(ah->ah_retry_short, + AR5K_NODCU_RETRY_LMT_SH_RETRY), AR5K_NODCU_RETRY_LMT); /* DCU on AR5211+ */ } else { ath5k_hw_reg_write(ah, - AR5K_REG_SM(AR5K_INIT_SLG_RETRY, - AR5K_DCU_RETRY_LMT_SLG_RETRY) | - AR5K_REG_SM(AR5K_INIT_SSH_RETRY, - AR5K_DCU_RETRY_LMT_SSH_RETRY) | - AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) | - AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY), + AR5K_REG_SM(ah->ah_retry_long, + AR5K_DCU_RETRY_LMT_RTS) + | AR5K_REG_SM(ah->ah_retry_long, + AR5K_DCU_RETRY_LMT_STA_RTS) + | AR5K_REG_SM(max(ah->ah_retry_long, ah->ah_retry_short), + AR5K_DCU_RETRY_LMT_STA_DATA), AR5K_QUEUE_DFS_RETRY_LIMIT(queue)); } - return; } /** diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index fd14b9103951..e1c9abd8c879 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -686,16 +686,15 @@ /* * DCU retry limit registers + * all these fields don't allow zero values */ #define AR5K_DCU_RETRY_LMT_BASE 0x1080 /* Register Address -Queue0 DCU_RETRY_LMT */ -#define AR5K_DCU_RETRY_LMT_SH_RETRY 0x0000000f /* Short retry limit mask */ -#define AR5K_DCU_RETRY_LMT_SH_RETRY_S 0 -#define AR5K_DCU_RETRY_LMT_LG_RETRY 0x000000f0 /* Long retry limit mask */ -#define AR5K_DCU_RETRY_LMT_LG_RETRY_S 4 -#define AR5K_DCU_RETRY_LMT_SSH_RETRY 0x00003f00 /* Station short retry limit mask (?) */ -#define AR5K_DCU_RETRY_LMT_SSH_RETRY_S 8 -#define AR5K_DCU_RETRY_LMT_SLG_RETRY 0x000fc000 /* Station long retry limit mask (?) */ -#define AR5K_DCU_RETRY_LMT_SLG_RETRY_S 14 +#define AR5K_DCU_RETRY_LMT_RTS 0x0000000f /* RTS failure limit. Transmission fails if no CTS is received for this number of times */ +#define AR5K_DCU_RETRY_LMT_RTS_S 0 +#define AR5K_DCU_RETRY_LMT_STA_RTS 0x00003f00 /* STA RTS failure limit. If exceeded CW reset */ +#define AR5K_DCU_RETRY_LMT_STA_RTS_S 8 +#define AR5K_DCU_RETRY_LMT_STA_DATA 0x000fc000 /* STA data failure limit. If exceeded CW reset. */ +#define AR5K_DCU_RETRY_LMT_STA_DATA_S 14 #define AR5K_QUEUE_DFS_RETRY_LIMIT(_q) AR5K_QUEUE_REG(AR5K_DCU_RETRY_LMT_BASE, _q) /* diff --git a/drivers/net/wireless/ath/ath5k/trace.h b/drivers/net/wireless/ath/ath5k/trace.h new file mode 100644 index 000000000000..2de68adb6240 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/trace.h @@ -0,0 +1,107 @@ +#if !defined(__TRACE_ATH5K_H) || defined(TRACE_HEADER_MULTI_READ) +#define __TRACE_ATH5K_H + +#include <linux/tracepoint.h> +#include "base.h" + +#ifndef CONFIG_ATH5K_TRACER +#undef TRACE_EVENT +#define TRACE_EVENT(name, proto, ...) \ +static inline void trace_ ## name(proto) {} +#endif + +struct sk_buff; + +#define PRIV_ENTRY __field(struct ath5k_softc *, priv) +#define PRIV_ASSIGN __entry->priv = priv + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM ath5k + +TRACE_EVENT(ath5k_rx, + TP_PROTO(struct ath5k_softc *priv, struct sk_buff *skb), + TP_ARGS(priv, skb), + TP_STRUCT__entry( + PRIV_ENTRY + __field(unsigned long, skbaddr) + __dynamic_array(u8, frame, skb->len) + ), + TP_fast_assign( + PRIV_ASSIGN; + __entry->skbaddr = (unsigned long) skb; + memcpy(__get_dynamic_array(frame), skb->data, skb->len); + ), + TP_printk( + "[%p] RX skb=%lx", __entry->priv, __entry->skbaddr + ) +); + +TRACE_EVENT(ath5k_tx, + TP_PROTO(struct ath5k_softc *priv, struct sk_buff *skb, + struct ath5k_txq *q), + + TP_ARGS(priv, skb, q), + + TP_STRUCT__entry( + PRIV_ENTRY + __field(unsigned long, skbaddr) + __field(u8, qnum) + __dynamic_array(u8, frame, skb->len) + ), + + TP_fast_assign( + PRIV_ASSIGN; + __entry->skbaddr = (unsigned long) skb; + __entry->qnum = (u8) q->qnum; + memcpy(__get_dynamic_array(frame), skb->data, skb->len); + ), + + TP_printk( + "[%p] TX skb=%lx q=%d", __entry->priv, __entry->skbaddr, + __entry->qnum + ) +); + +TRACE_EVENT(ath5k_tx_complete, + TP_PROTO(struct ath5k_softc *priv, struct sk_buff *skb, + struct ath5k_txq *q, struct ath5k_tx_status *ts), + + TP_ARGS(priv, skb, q, ts), + + TP_STRUCT__entry( + PRIV_ENTRY + __field(unsigned long, skbaddr) + __field(u8, qnum) + __field(u8, ts_status) + __field(s8, ts_rssi) + __field(u8, ts_antenna) + ), + + TP_fast_assign( + PRIV_ASSIGN; + __entry->skbaddr = (unsigned long) skb; + __entry->qnum = (u8) q->qnum; + __entry->ts_status = ts->ts_status; + __entry->ts_rssi = ts->ts_rssi; + __entry->ts_antenna = ts->ts_antenna; + ), + + TP_printk( + "[%p] TX end skb=%lx q=%d stat=%x rssi=%d ant=%x", + __entry->priv, __entry->skbaddr, __entry->qnum, + __entry->ts_status, __entry->ts_rssi, __entry->ts_antenna + ) +); + +#endif /* __TRACE_ATH5K_H */ + +#ifdef CONFIG_ATH5K_TRACER + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH ../../drivers/net/wireless/ath/ath5k +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +#include <trace/define_trace.h> + +#endif diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index aca01621c205..4d66ca8042eb 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -4,7 +4,6 @@ ath9k-y += beacon.o \ main.o \ recv.o \ xmit.o \ - virtual.o \ ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o ath9k-$(CONFIG_PCI) += pci.o diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 25a6e4417cdb..993672105963 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -54,7 +54,6 @@ static struct ath_bus_ops ath_ahb_bus_ops = { static int ath_ahb_probe(struct platform_device *pdev) { void __iomem *mem; - struct ath_wiphy *aphy; struct ath_softc *sc; struct ieee80211_hw *hw; struct resource *res; @@ -92,8 +91,7 @@ static int ath_ahb_probe(struct platform_device *pdev) irq = res->start; - hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) + - sizeof(struct ath_softc), &ath9k_ops); + hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); if (hw == NULL) { dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); ret = -ENOMEM; @@ -103,11 +101,7 @@ static int ath_ahb_probe(struct platform_device *pdev) SET_IEEE80211_DEV(hw, &pdev->dev); platform_set_drvdata(pdev, hw); - aphy = hw->priv; - sc = (struct ath_softc *) (aphy + 1); - aphy->sc = sc; - aphy->hw = hw; - sc->pri_wiphy = aphy; + sc = hw->priv; sc->hw = hw; sc->dev = &pdev->dev; sc->mem = mem; @@ -151,8 +145,7 @@ static int ath_ahb_remove(struct platform_device *pdev) struct ieee80211_hw *hw = platform_get_drvdata(pdev); if (hw) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; void __iomem *mem = sc->mem; ath9k_deinit_device(sc); diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index 5e300bd3d264..76388c6d6692 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -805,7 +805,10 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); - if (AR_SREV_9271(ah) || AR_SREV_9285_12_OR_LATER(ah)) { + if (AR_SREV_9271(ah)) { + if (!ar9285_hw_cl_cal(ah, chan)) + return false; + } else if (AR_SREV_9285_12_OR_LATER(ah)) { if (!ar9285_hw_clc(ah, chan)) return false; } else { diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 4819747fa4c3..4a9271802991 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3673,7 +3673,7 @@ static void ar9003_hw_internal_regulator_apply(struct ath_hw *ah) return; reg_pmu_set = (5 << 1) | (7 << 4) | (1 << 8) | - (7 << 14) | (6 << 17) | (1 << 20) | + (2 << 14) | (6 << 17) | (1 << 20) | (3 << 24) | (1 << 28); REG_WRITE(ah, AR_PHY_PMU1, reg_pmu_set); @@ -3959,19 +3959,19 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) { #define POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) /* make sure forced gain is not set */ - REG_WRITE(ah, 0xa458, 0); + REG_WRITE(ah, AR_PHY_TX_FORCED_GAIN, 0); /* Write the OFDM power per rate set */ /* 6 (LSB), 9, 12, 18 (MSB) */ - REG_WRITE(ah, 0xa3c0, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(0), POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 24) | POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 16) | POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 8) | POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 0)); /* 24 (LSB), 36, 48, 54 (MSB) */ - REG_WRITE(ah, 0xa3c4, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(1), POW_SM(pPwrArray[ALL_TARGET_LEGACY_54], 24) | POW_SM(pPwrArray[ALL_TARGET_LEGACY_48], 16) | POW_SM(pPwrArray[ALL_TARGET_LEGACY_36], 8) | @@ -3980,14 +3980,14 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) /* Write the CCK power per rate set */ /* 1L (LSB), reserved, 2L, 2S (MSB) */ - REG_WRITE(ah, 0xa3c8, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(2), POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 24) | POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 16) | /* POW_SM(txPowerTimes2, 8) | this is reserved for AR9003 */ POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 0)); /* 5.5L (LSB), 5.5S, 11L, 11S (MSB) */ - REG_WRITE(ah, 0xa3cc, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(3), POW_SM(pPwrArray[ALL_TARGET_LEGACY_11S], 24) | POW_SM(pPwrArray[ALL_TARGET_LEGACY_11L], 16) | POW_SM(pPwrArray[ALL_TARGET_LEGACY_5S], 8) | @@ -3997,7 +3997,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) /* Write the HT20 power per rate set */ /* 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) */ - REG_WRITE(ah, 0xa3d0, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(4), POW_SM(pPwrArray[ALL_TARGET_HT20_5], 24) | POW_SM(pPwrArray[ALL_TARGET_HT20_4], 16) | POW_SM(pPwrArray[ALL_TARGET_HT20_1_3_9_11_17_19], 8) | @@ -4005,7 +4005,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) ); /* 6 (LSB), 7, 12, 13 (MSB) */ - REG_WRITE(ah, 0xa3d4, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(5), POW_SM(pPwrArray[ALL_TARGET_HT20_13], 24) | POW_SM(pPwrArray[ALL_TARGET_HT20_12], 16) | POW_SM(pPwrArray[ALL_TARGET_HT20_7], 8) | @@ -4013,7 +4013,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) ); /* 14 (LSB), 15, 20, 21 */ - REG_WRITE(ah, 0xa3e4, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(9), POW_SM(pPwrArray[ALL_TARGET_HT20_21], 24) | POW_SM(pPwrArray[ALL_TARGET_HT20_20], 16) | POW_SM(pPwrArray[ALL_TARGET_HT20_15], 8) | @@ -4023,7 +4023,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) /* Mixed HT20 and HT40 rates */ /* HT20 22 (LSB), HT20 23, HT40 22, HT40 23 (MSB) */ - REG_WRITE(ah, 0xa3e8, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(10), POW_SM(pPwrArray[ALL_TARGET_HT40_23], 24) | POW_SM(pPwrArray[ALL_TARGET_HT40_22], 16) | POW_SM(pPwrArray[ALL_TARGET_HT20_23], 8) | @@ -4035,7 +4035,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) * correct PAR difference between HT40 and HT20/LEGACY * 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) */ - REG_WRITE(ah, 0xa3d8, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(6), POW_SM(pPwrArray[ALL_TARGET_HT40_5], 24) | POW_SM(pPwrArray[ALL_TARGET_HT40_4], 16) | POW_SM(pPwrArray[ALL_TARGET_HT40_1_3_9_11_17_19], 8) | @@ -4043,7 +4043,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) ); /* 6 (LSB), 7, 12, 13 (MSB) */ - REG_WRITE(ah, 0xa3dc, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(7), POW_SM(pPwrArray[ALL_TARGET_HT40_13], 24) | POW_SM(pPwrArray[ALL_TARGET_HT40_12], 16) | POW_SM(pPwrArray[ALL_TARGET_HT40_7], 8) | @@ -4051,7 +4051,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) ); /* 14 (LSB), 15, 20, 21 */ - REG_WRITE(ah, 0xa3ec, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(11), POW_SM(pPwrArray[ALL_TARGET_HT40_21], 24) | POW_SM(pPwrArray[ALL_TARGET_HT40_20], 16) | POW_SM(pPwrArray[ALL_TARGET_HT40_15], 8) | diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 4ceddbbdfcee..038a0cbfc6e7 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -615,7 +615,7 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, */ if (rxsp->status11 & AR_CRCErr) rxs->rs_status |= ATH9K_RXERR_CRC; - if (rxsp->status11 & AR_PHYErr) { + else if (rxsp->status11 & AR_PHYErr) { phyerr = MS(rxsp->status11, AR_PHYErrCode); /* * If we reach a point here where AR_PostDelimCRCErr is @@ -638,11 +638,11 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, rxs->rs_phyerr = phyerr; } - } - if (rxsp->status11 & AR_DecryptCRCErr) + } else if (rxsp->status11 & AR_DecryptCRCErr) rxs->rs_status |= ATH9K_RXERR_DECRYPT; - if (rxsp->status11 & AR_MichaelErr) + else if (rxsp->status11 & AR_MichaelErr) rxs->rs_status |= ATH9K_RXERR_MIC; + if (rxsp->status11 & AR_KeyMiss) rxs->rs_status |= ATH9K_RXERR_DECRYPT; } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 59bab6bd8a74..8bdda2cf9dd7 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -486,6 +486,8 @@ #define AR_PHY_HEAVYCLIP_40 (AR_SM_BASE + 0x1ac) #define AR_PHY_ILLEGAL_TXRATE (AR_SM_BASE + 0x1b0) +#define AR_PHY_POWER_TX_RATE(_d) (AR_SM_BASE + 0x1c0 + ((_d) << 2)) + #define AR_PHY_PWRTX_MAX (AR_SM_BASE + 0x1f0) #define AR_PHY_POWER_TX_SUB (AR_SM_BASE + 0x1f4) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 23838e37d45f..9272278aff5e 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -95,9 +95,9 @@ struct ath_config { * @BUF_XRETRY: To denote excessive retries of the buffer */ enum buffer_type { - BUF_AMPDU = BIT(2), - BUF_AGGR = BIT(3), - BUF_XRETRY = BIT(5), + BUF_AMPDU = BIT(0), + BUF_AGGR = BIT(1), + BUF_XRETRY = BIT(2), }; #define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU) @@ -137,7 +137,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ WME_AC_VO) -#define ADDBA_EXCHANGE_ATTEMPTS 10 #define ATH_AGGR_DELIM_SZ 4 #define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ /* number of delimiters for encryption padding */ @@ -184,7 +183,8 @@ enum ATH_AGGR_STATUS { #define ATH_TXFIFO_DEPTH 8 struct ath_txq { - u32 axq_qnum; + int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */ + u32 axq_qnum; /* ath9k hardware queue number */ u32 *axq_link; struct list_head axq_q; spinlock_t axq_lock; @@ -234,7 +234,6 @@ struct ath_buf { bool bf_stale; u16 bf_flags; struct ath_buf_state bf_state; - struct ath_wiphy *aphy; }; struct ath_atx_tid { @@ -255,7 +254,10 @@ struct ath_atx_tid { }; struct ath_node { - struct ath_common *common; +#ifdef CONFIG_ATH9K_DEBUGFS + struct list_head list; /* for sc->nodes */ + struct ieee80211_sta *sta; /* station struct we're part of */ +#endif struct ath_atx_tid tid[WME_NUM_TID]; struct ath_atx_ac ac[WME_NUM_AC]; u16 maxampdu; @@ -278,6 +280,11 @@ struct ath_tx_control { #define ATH_TX_XRETRY 0x02 #define ATH_TX_BAR 0x04 +/** + * @txq_map: Index is mac80211 queue number. This is + * not necessarily the same as the hardware queue number + * (axq_qnum). + */ struct ath_tx { u16 seq_no; u32 txqsetup; @@ -304,6 +311,8 @@ struct ath_rx { struct ath_descdma rxdma; struct ath_buf *rx_bufptr; struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX]; + + struct sk_buff *frag; }; int ath_startrecv(struct ath_softc *sc); @@ -343,7 +352,6 @@ struct ath_vif { __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ enum nl80211_iftype av_opmode; struct ath_buf *av_bcbuf; - struct ath_tx_control av_btxctl; u8 bssid[ETH_ALEN]; /* current BSSID from config_interface */ }; @@ -382,7 +390,6 @@ struct ath_beacon { u32 ast_be_xmit; u64 bc_tstamp; struct ieee80211_vif *bslot[ATH_BCBUF]; - struct ath_wiphy *bslot_aphy[ATH_BCBUF]; int slottime; int slotupdate; struct ath9k_tx_queue_info beacon_qi; @@ -393,7 +400,7 @@ struct ath_beacon { void ath_beacon_tasklet(unsigned long data); void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif); -int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif); +int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif); void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); int ath_beaconq_config(struct ath_softc *sc); @@ -530,7 +537,6 @@ struct ath_ant_comb { #define ATH_CABQ_READY_TIME 80 /* % of beacon interval */ #define ATH_MAX_SW_RETRIES 10 #define ATH_CHAN_MAX 255 -#define IEEE80211_WEP_NKID 4 /* number of key ids */ #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ #define ATH_RATE_DUMMY_MARKER 0 @@ -558,27 +564,28 @@ struct ath_ant_comb { #define PS_WAIT_FOR_TX_ACK BIT(3) #define PS_BEACON_SYNC BIT(4) -struct ath_wiphy; struct ath_rate_table; +struct ath9k_vif_iter_data { + const u8 *hw_macaddr; /* phy's hardware address, set + * before starting iteration for + * valid bssid mask. + */ + u8 mask[ETH_ALEN]; /* bssid mask */ + int naps; /* number of AP vifs */ + int nmeshes; /* number of mesh vifs */ + int nstations; /* number of station vifs */ + int nwds; /* number of nwd vifs */ + int nadhocs; /* number of adhoc vifs */ + int nothers; /* number of vifs not specified above. */ +}; + struct ath_softc { struct ieee80211_hw *hw; struct device *dev; - spinlock_t wiphy_lock; /* spinlock to protect ath_wiphy data */ - struct ath_wiphy *pri_wiphy; - struct ath_wiphy **sec_wiphy; /* secondary wiphys (virtual radios); may - * have NULL entries */ - int num_sec_wiphy; /* number of sec_wiphy pointers in the array */ int chan_idx; int chan_is_ht; - struct ath_wiphy *next_wiphy; - struct work_struct chan_work; - int wiphy_select_failures; - unsigned long wiphy_select_first_fail; - struct delayed_work wiphy_work; - unsigned long wiphy_scheduler_int; - int wiphy_scheduler_index; struct survey_info *cur_survey; struct survey_info survey[ATH9K_NUM_CHANNELS]; @@ -595,14 +602,16 @@ struct ath_softc { struct work_struct hw_check_work; struct completion paprd_complete; + unsigned int hw_busy_count; + u32 intrstatus; u32 sc_flags; /* SC_OP_* */ u16 ps_flags; /* PS_* */ u16 curtxpow; - u8 nbcnvifs; - u16 nvifs; bool ps_enabled; bool ps_idle; + short nbcnvifs; + short nvifs; unsigned long ps_usecount; struct ath_config config; @@ -621,13 +630,20 @@ struct ath_softc { int led_on_cnt; int led_off_cnt; + struct ath9k_hw_cal_data caldata; + int last_rssi; + int beacon_interval; #ifdef CONFIG_ATH9K_DEBUGFS struct ath9k_debug debug; + spinlock_t nodes_lock; + struct list_head nodes; /* basically, stations */ + unsigned int tx_complete_poll_work_seen; #endif struct ath_beacon_config cur_beacon_conf; struct delayed_work tx_complete_work; + struct delayed_work hw_pll_work; struct ath_btcoex btcoex; struct ath_descdma txsdma; @@ -637,23 +653,6 @@ struct ath_softc { struct pm_qos_request_list pm_qos_req; }; -struct ath_wiphy { - struct ath_softc *sc; /* shared for all virtual wiphys */ - struct ieee80211_hw *hw; - struct ath9k_hw_cal_data caldata; - enum ath_wiphy_state { - ATH_WIPHY_INACTIVE, - ATH_WIPHY_ACTIVE, - ATH_WIPHY_PAUSING, - ATH_WIPHY_PAUSED, - ATH_WIPHY_SCAN, - } state; - bool idle; - int chan_idx; - int chan_is_ht; - int last_rssi; -}; - void ath9k_tasklet(unsigned long data); int ath_reset(struct ath_softc *sc, bool retry_tx); int ath_cabq_update(struct ath_softc *); @@ -675,14 +674,13 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, const struct ath_bus_ops *bus_ops); void ath9k_deinit_device(struct ath_softc *sc); void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); -void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, - struct ath9k_channel *ichan); int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, struct ath9k_channel *hchan); void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw); void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw); bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode); +bool ath9k_uses_beacons(int type); #ifdef CONFIG_PCI int ath_pci_init(void); @@ -706,26 +704,12 @@ void ath9k_ps_restore(struct ath_softc *sc); u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate); void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -int ath9k_wiphy_add(struct ath_softc *sc); -int ath9k_wiphy_del(struct ath_wiphy *aphy); -void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, int ftype); -int ath9k_wiphy_pause(struct ath_wiphy *aphy); -int ath9k_wiphy_unpause(struct ath_wiphy *aphy); -int ath9k_wiphy_select(struct ath_wiphy *aphy); -void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int); -void ath9k_wiphy_chan_work(struct work_struct *work); -bool ath9k_wiphy_started(struct ath_softc *sc); -void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, - struct ath_wiphy *selected); -bool ath9k_wiphy_scanning(struct ath_softc *sc); -void ath9k_wiphy_work(struct work_struct *work); -bool ath9k_all_wiphys_idle(struct ath_softc *sc); -void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle); - -void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue); -bool ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue); void ath_start_rfkill_poll(struct ath_softc *sc); extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw); +void ath9k_calculate_iter_data(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ath9k_vif_iter_data *iter_data); + #endif /* ATH9K_H */ diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 385ba03134ba..fcb36abfc309 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -112,8 +112,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_tx_control txctl; @@ -132,8 +131,7 @@ static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_buf *bf; struct ath_vif *avp; @@ -142,9 +140,6 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, struct ieee80211_tx_info *info; int cabq_depth; - if (aphy->state != ATH_WIPHY_ACTIVE) - return NULL; - avp = (void *)vif->drv_priv; cabq = sc->beacon.cabq; @@ -225,9 +220,8 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, return bf; } -int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) +int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif) { - struct ath_softc *sc = aphy->sc; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_vif *avp; struct ath_buf *bf; @@ -244,9 +238,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) struct ath_buf, list); list_del(&avp->av_bcbuf->list); - if (sc->sc_ah->opmode == NL80211_IFTYPE_AP || - sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC || - sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) { + if (ath9k_uses_beacons(vif->type)) { int slot; /* * Assign the vif to a beacon xmit slot. As @@ -263,7 +255,6 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) } BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL); sc->beacon.bslot[avp->av_bslot] = vif; - sc->beacon.bslot_aphy[avp->av_bslot] = aphy; sc->nbcnvifs++; } } @@ -281,10 +272,8 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) /* NB: the beacon data buffer must be 32-bit aligned. */ skb = ieee80211_beacon_get(sc->hw, vif); - if (skb == NULL) { - ath_dbg(common, ATH_DBG_BEACON, "cannot get skb\n"); + if (skb == NULL) return -ENOMEM; - } tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; sc->beacon.bc_tstamp = le64_to_cpu(tstamp); @@ -336,7 +325,6 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp) if (avp->av_bslot != -1) { sc->beacon.bslot[avp->av_bslot] = NULL; - sc->beacon.bslot_aphy[avp->av_bslot] = NULL; sc->nbcnvifs--; } @@ -362,7 +350,6 @@ void ath_beacon_tasklet(unsigned long data) struct ath_common *common = ath9k_hw_common(ah); struct ath_buf *bf = NULL; struct ieee80211_vif *vif; - struct ath_wiphy *aphy; int slot; u32 bfaddr, bc = 0, tsftu; u64 tsf; @@ -420,7 +407,6 @@ void ath_beacon_tasklet(unsigned long data) */ slot = ATH_BCBUF - slot - 1; vif = sc->beacon.bslot[slot]; - aphy = sc->beacon.bslot_aphy[slot]; ath_dbg(common, ATH_DBG_BEACON, "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", @@ -428,7 +414,7 @@ void ath_beacon_tasklet(unsigned long data) bfaddr = 0; if (vif) { - bf = ath_beacon_generate(aphy->hw, vif); + bf = ath_beacon_generate(sc->hw, vif); if (bf != NULL) { bfaddr = bf->bf_daddr; bc = 1; @@ -720,10 +706,10 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) iftype = sc->sc_ah->opmode; } - cur_conf->listen_interval = 1; - cur_conf->dtim_count = 1; - cur_conf->bmiss_timeout = - ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; + cur_conf->listen_interval = 1; + cur_conf->dtim_count = 1; + cur_conf->bmiss_timeout = + ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; /* * It looks like mac80211 may end up using beacon interval of zero in @@ -735,8 +721,9 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) cur_conf->beacon_interval = 100; /* - * Some times we dont parse dtim period from mac80211, in that case - * use a default value + * We don't parse dtim period from mac80211 during the driver + * initialization as it breaks association with hidden-ssid + * AP and it causes latency in roaming */ if (cur_conf->dtim_period == 0) cur_conf->dtim_period = 1; diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index b68a1acbddd0..b4a92a4313f6 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -382,9 +382,8 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, s16 default_nf; int i, j; - if (!ah->caldata) - return; - + ah->caldata->channel = chan->channel; + ah->caldata->channelFlags = chan->channelFlags & ~CHANNEL_CW_INT; h = ah->caldata->nfCalHist; default_nf = ath9k_hw_get_default_nf(ah, chan); for (i = 0; i < NUM_NF_READINGS; i++) { diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index df1998d48253..615e68276e72 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -189,6 +189,17 @@ void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common, } EXPORT_SYMBOL(ath9k_cmn_btcoex_bt_stomp); +void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow, + u16 new_txpow, u16 *txpower) +{ + if (cur_txpow != new_txpow) { + ath9k_hw_set_txpowerlimit(ah, new_txpow, false); + /* read back in case value is clamped */ + *txpower = ath9k_hw_regulatory(ah)->power_limit; + } +} +EXPORT_SYMBOL(ath9k_cmn_update_txpow); + static int __init ath9k_cmn_init(void) { return 0; diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index a126bddebb0a..b2f7b5f89097 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -23,8 +23,6 @@ /* Common header for Atheros 802.11n base driver cores */ -#define IEEE80211_WEP_NKID 4 - #define WME_NUM_TID 16 #define WME_BA_BMP_SIZE 64 #define WME_MAX_BA WME_BA_BMP_SIZE @@ -70,3 +68,5 @@ struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw, int ath9k_cmn_count_streams(unsigned int chainmask, int max); void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common, enum ath_stomp_type stomp_type); +void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow, + u16 new_txpow, u16 *txpower); diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 3586c43077a7..5cfcf8c235a4 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -381,41 +381,40 @@ static const struct file_operations fops_interrupt = { .llseek = default_llseek, }; -static const char * ath_wiphy_state_str(enum ath_wiphy_state state) +static const char *channel_type_str(enum nl80211_channel_type t) { - switch (state) { - case ATH_WIPHY_INACTIVE: - return "INACTIVE"; - case ATH_WIPHY_ACTIVE: - return "ACTIVE"; - case ATH_WIPHY_PAUSING: - return "PAUSING"; - case ATH_WIPHY_PAUSED: - return "PAUSED"; - case ATH_WIPHY_SCAN: - return "SCAN"; + switch (t) { + case NL80211_CHAN_NO_HT: + return "no ht"; + case NL80211_CHAN_HT20: + return "ht20"; + case NL80211_CHAN_HT40MINUS: + return "ht40-"; + case NL80211_CHAN_HT40PLUS: + return "ht40+"; + default: + return "???"; } - return "?"; } static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; - struct ath_wiphy *aphy = sc->pri_wiphy; - struct ieee80211_channel *chan = aphy->hw->conf.channel; + struct ieee80211_channel *chan = sc->hw->conf.channel; + struct ieee80211_conf *conf = &(sc->hw->conf); char buf[512]; unsigned int len = 0; - int i; u8 addr[ETH_ALEN]; u32 tmp; len += snprintf(buf + len, sizeof(buf) - len, - "primary: %s (%s chan=%d ht=%d)\n", - wiphy_name(sc->pri_wiphy->hw->wiphy), - ath_wiphy_state_str(sc->pri_wiphy->state), + "%s (chan=%d center-freq: %d MHz channel-type: %d (%s))\n", + wiphy_name(sc->hw->wiphy), ieee80211_frequency_to_channel(chan->center_freq), - aphy->chan_is_ht); + chan->center_freq, + conf->channel_type, + channel_type_str(conf->channel_type)); put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr); put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4); @@ -457,156 +456,82 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, else len += snprintf(buf + len, sizeof(buf) - len, "\n"); - /* Put variable-length stuff down here, and check for overflows. */ - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy_tmp = sc->sec_wiphy[i]; - if (aphy_tmp == NULL) - continue; - chan = aphy_tmp->hw->conf.channel; - len += snprintf(buf + len, sizeof(buf) - len, - "secondary: %s (%s chan=%d ht=%d)\n", - wiphy_name(aphy_tmp->hw->wiphy), - ath_wiphy_state_str(aphy_tmp->state), - ieee80211_frequency_to_channel(chan->center_freq), - aphy_tmp->chan_is_ht); - } if (len > sizeof(buf)) len = sizeof(buf); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } -static struct ath_wiphy * get_wiphy(struct ath_softc *sc, const char *name) -{ - int i; - if (strcmp(name, wiphy_name(sc->pri_wiphy->hw->wiphy)) == 0) - return sc->pri_wiphy; - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - if (aphy && strcmp(name, wiphy_name(aphy->hw->wiphy)) == 0) - return aphy; - } - return NULL; -} - -static int del_wiphy(struct ath_softc *sc, const char *name) -{ - struct ath_wiphy *aphy = get_wiphy(sc, name); - if (!aphy) - return -ENOENT; - return ath9k_wiphy_del(aphy); -} - -static int pause_wiphy(struct ath_softc *sc, const char *name) -{ - struct ath_wiphy *aphy = get_wiphy(sc, name); - if (!aphy) - return -ENOENT; - return ath9k_wiphy_pause(aphy); -} - -static int unpause_wiphy(struct ath_softc *sc, const char *name) -{ - struct ath_wiphy *aphy = get_wiphy(sc, name); - if (!aphy) - return -ENOENT; - return ath9k_wiphy_unpause(aphy); -} - -static int select_wiphy(struct ath_softc *sc, const char *name) -{ - struct ath_wiphy *aphy = get_wiphy(sc, name); - if (!aphy) - return -ENOENT; - return ath9k_wiphy_select(aphy); -} - -static int schedule_wiphy(struct ath_softc *sc, const char *msec) -{ - ath9k_wiphy_set_scheduler(sc, simple_strtoul(msec, NULL, 0)); - return 0; -} - -static ssize_t write_file_wiphy(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[50]; - size_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - if (len > 0 && buf[len - 1] == '\n') - buf[len - 1] = '\0'; - - if (strncmp(buf, "add", 3) == 0) { - int res = ath9k_wiphy_add(sc); - if (res < 0) - return res; - } else if (strncmp(buf, "del=", 4) == 0) { - int res = del_wiphy(sc, buf + 4); - if (res < 0) - return res; - } else if (strncmp(buf, "pause=", 6) == 0) { - int res = pause_wiphy(sc, buf + 6); - if (res < 0) - return res; - } else if (strncmp(buf, "unpause=", 8) == 0) { - int res = unpause_wiphy(sc, buf + 8); - if (res < 0) - return res; - } else if (strncmp(buf, "select=", 7) == 0) { - int res = select_wiphy(sc, buf + 7); - if (res < 0) - return res; - } else if (strncmp(buf, "schedule=", 9) == 0) { - int res = schedule_wiphy(sc, buf + 9); - if (res < 0) - return res; - } else - return -EOPNOTSUPP; - - return count; -} - static const struct file_operations fops_wiphy = { .read = read_file_wiphy, - .write = write_file_wiphy, .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, }; +#define PR_QNUM(_n) sc->tx.txq_map[_n]->axq_qnum #define PR(str, elem) \ do { \ len += snprintf(buf + len, size - len, \ "%s%13u%11u%10u%10u\n", str, \ - sc->debug.stats.txstats[WME_AC_BE].elem, \ - sc->debug.stats.txstats[WME_AC_BK].elem, \ - sc->debug.stats.txstats[WME_AC_VI].elem, \ - sc->debug.stats.txstats[WME_AC_VO].elem); \ + sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].elem, \ + sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].elem, \ + sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].elem, \ + sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].elem); \ + if (len >= size) \ + goto done; \ +} while(0) + +#define PRX(str, elem) \ +do { \ + len += snprintf(buf + len, size - len, \ + "%s%13u%11u%10u%10u\n", str, \ + (unsigned int)(sc->tx.txq_map[WME_AC_BE]->elem), \ + (unsigned int)(sc->tx.txq_map[WME_AC_BK]->elem), \ + (unsigned int)(sc->tx.txq_map[WME_AC_VI]->elem), \ + (unsigned int)(sc->tx.txq_map[WME_AC_VO]->elem)); \ + if (len >= size) \ + goto done; \ } while(0) +#define PRQLE(str, elem) \ +do { \ + len += snprintf(buf + len, size - len, \ + "%s%13i%11i%10i%10i\n", str, \ + list_empty(&sc->tx.txq_map[WME_AC_BE]->elem), \ + list_empty(&sc->tx.txq_map[WME_AC_BK]->elem), \ + list_empty(&sc->tx.txq_map[WME_AC_VI]->elem), \ + list_empty(&sc->tx.txq_map[WME_AC_VO]->elem)); \ + if (len >= size) \ + goto done; \ +} while (0) + static ssize_t read_file_xmit(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; char *buf; - unsigned int len = 0, size = 2048; + unsigned int len = 0, size = 8000; + int i; ssize_t retval = 0; + char tmp[32]; buf = kzalloc(size, GFP_KERNEL); if (buf == NULL) return -ENOMEM; - len += sprintf(buf, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO"); + len += sprintf(buf, "Num-Tx-Queues: %i tx-queues-setup: 0x%x" + " poll-work-seen: %u\n" + "%30s %10s%10s%10s\n\n", + ATH9K_NUM_TX_QUEUES, sc->tx.txqsetup, + sc->tx_complete_poll_work_seen, + "BE", "BK", "VI", "VO"); PR("MPDUs Queued: ", queued); PR("MPDUs Completed: ", completed); PR("Aggregates: ", a_aggr); - PR("AMPDUs Queued: ", a_queued); + PR("AMPDUs Queued HW:", a_queued_hw); + PR("AMPDUs Queued SW:", a_queued_sw); PR("AMPDUs Completed:", a_completed); PR("AMPDUs Retried: ", a_retries); PR("AMPDUs XRetried: ", a_xretries); @@ -618,6 +543,223 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, PR("DELIM Underrun: ", delim_underrun); PR("TX-Pkts-All: ", tx_pkts_all); PR("TX-Bytes-All: ", tx_bytes_all); + PR("hw-put-tx-buf: ", puttxbuf); + PR("hw-tx-start: ", txstart); + PR("hw-tx-proc-desc: ", txprocdesc); + len += snprintf(buf + len, size - len, + "%s%11p%11p%10p%10p\n", "txq-memory-address:", + &(sc->tx.txq_map[WME_AC_BE]), + &(sc->tx.txq_map[WME_AC_BK]), + &(sc->tx.txq_map[WME_AC_VI]), + &(sc->tx.txq_map[WME_AC_VO])); + if (len >= size) + goto done; + + PRX("axq-qnum: ", axq_qnum); + PRX("axq-depth: ", axq_depth); + PRX("axq-ampdu_depth: ", axq_ampdu_depth); + PRX("axq-stopped ", stopped); + PRX("tx-in-progress ", axq_tx_inprogress); + PRX("pending-frames ", pending_frames); + PRX("txq_headidx: ", txq_headidx); + PRX("txq_tailidx: ", txq_headidx); + + PRQLE("axq_q empty: ", axq_q); + PRQLE("axq_acq empty: ", axq_acq); + PRQLE("txq_fifo_pending: ", txq_fifo_pending); + for (i = 0; i < ATH_TXFIFO_DEPTH; i++) { + snprintf(tmp, sizeof(tmp) - 1, "txq_fifo[%i] empty: ", i); + PRQLE(tmp, txq_fifo[i]); + } + + /* Print out more detailed queue-info */ + for (i = 0; i <= WME_AC_BK; i++) { + struct ath_txq *txq = &(sc->tx.txq[i]); + struct ath_atx_ac *ac; + struct ath_atx_tid *tid; + if (len >= size) + goto done; + spin_lock_bh(&txq->axq_lock); + if (!list_empty(&txq->axq_acq)) { + ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, + list); + len += snprintf(buf + len, size - len, + "txq[%i] first-ac: %p sched: %i\n", + i, ac, ac->sched); + if (list_empty(&ac->tid_q) || (len >= size)) + goto done_for; + tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, + list); + len += snprintf(buf + len, size - len, + " first-tid: %p sched: %i paused: %i\n", + tid, tid->sched, tid->paused); + } + done_for: + spin_unlock_bh(&txq->axq_lock); + } + +done: + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static ssize_t read_file_stations(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char *buf; + unsigned int len = 0, size = 64000; + struct ath_node *an = NULL; + ssize_t retval = 0; + int q; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + len += snprintf(buf + len, size - len, + "Stations:\n" + " tid: addr sched paused buf_q-empty an ac\n" + " ac: addr sched tid_q-empty txq\n"); + + spin_lock(&sc->nodes_lock); + list_for_each_entry(an, &sc->nodes, list) { + len += snprintf(buf + len, size - len, + "%pM\n", an->sta->addr); + if (len >= size) + goto done; + + for (q = 0; q < WME_NUM_TID; q++) { + struct ath_atx_tid *tid = &(an->tid[q]); + len += snprintf(buf + len, size - len, + " tid: %p %s %s %i %p %p\n", + tid, tid->sched ? "sched" : "idle", + tid->paused ? "paused" : "running", + list_empty(&tid->buf_q), + tid->an, tid->ac); + if (len >= size) + goto done; + } + + for (q = 0; q < WME_NUM_AC; q++) { + struct ath_atx_ac *ac = &(an->ac[q]); + len += snprintf(buf + len, size - len, + " ac: %p %s %i %p\n", + ac, ac->sched ? "sched" : "idle", + list_empty(&ac->tid_q), ac->txq); + if (len >= size) + goto done; + } + } + +done: + spin_unlock(&sc->nodes_lock); + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static ssize_t read_file_misc(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; + struct ieee80211_hw *hw = sc->hw; + char *buf; + unsigned int len = 0, size = 8000; + ssize_t retval = 0; + const char *tmp; + unsigned int reg; + struct ath9k_vif_iter_data iter_data; + + ath9k_calculate_iter_data(hw, NULL, &iter_data); + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + switch (sc->sc_ah->opmode) { + case NL80211_IFTYPE_ADHOC: + tmp = "ADHOC"; + break; + case NL80211_IFTYPE_MESH_POINT: + tmp = "MESH"; + break; + case NL80211_IFTYPE_AP: + tmp = "AP"; + break; + case NL80211_IFTYPE_STATION: + tmp = "STATION"; + break; + default: + tmp = "???"; + break; + } + + len += snprintf(buf + len, size - len, + "curbssid: %pM\n" + "OP-Mode: %s(%i)\n" + "Beacon-Timer-Register: 0x%x\n", + common->curbssid, + tmp, (int)(sc->sc_ah->opmode), + REG_READ(ah, AR_BEACON_PERIOD)); + + reg = REG_READ(ah, AR_TIMER_MODE); + len += snprintf(buf + len, size - len, "Timer-Mode-Register: 0x%x (", + reg); + if (reg & AR_TBTT_TIMER_EN) + len += snprintf(buf + len, size - len, "TBTT "); + if (reg & AR_DBA_TIMER_EN) + len += snprintf(buf + len, size - len, "DBA "); + if (reg & AR_SWBA_TIMER_EN) + len += snprintf(buf + len, size - len, "SWBA "); + if (reg & AR_HCF_TIMER_EN) + len += snprintf(buf + len, size - len, "HCF "); + if (reg & AR_TIM_TIMER_EN) + len += snprintf(buf + len, size - len, "TIM "); + if (reg & AR_DTIM_TIMER_EN) + len += snprintf(buf + len, size - len, "DTIM "); + len += snprintf(buf + len, size - len, ")\n"); + + reg = sc->sc_ah->imask; + len += snprintf(buf + len, size - len, "imask: 0x%x (", reg); + if (reg & ATH9K_INT_SWBA) + len += snprintf(buf + len, size - len, "SWBA "); + if (reg & ATH9K_INT_BMISS) + len += snprintf(buf + len, size - len, "BMISS "); + if (reg & ATH9K_INT_CST) + len += snprintf(buf + len, size - len, "CST "); + if (reg & ATH9K_INT_RX) + len += snprintf(buf + len, size - len, "RX "); + if (reg & ATH9K_INT_RXHP) + len += snprintf(buf + len, size - len, "RXHP "); + if (reg & ATH9K_INT_RXLP) + len += snprintf(buf + len, size - len, "RXLP "); + if (reg & ATH9K_INT_BB_WATCHDOG) + len += snprintf(buf + len, size - len, "BB_WATCHDOG "); + /* there are other IRQs if one wanted to add them. */ + len += snprintf(buf + len, size - len, ")\n"); + + len += snprintf(buf + len, size - len, + "VIF Counts: AP: %i STA: %i MESH: %i WDS: %i" + " ADHOC: %i OTHER: %i nvifs: %hi beacon-vifs: %hi\n", + iter_data.naps, iter_data.nstations, iter_data.nmeshes, + iter_data.nwds, iter_data.nadhocs, iter_data.nothers, + sc->nvifs, sc->nbcnvifs); + + len += snprintf(buf + len, size - len, + "Calculated-BSSID-Mask: %pM\n", + iter_data.mask); if (len > size) len = size; @@ -629,9 +771,9 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, } void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, - struct ath_tx_status *ts) + struct ath_tx_status *ts, struct ath_txq *txq) { - int qnum = skb_get_queue_mapping(bf->bf_mpdu); + int qnum = txq->axq_qnum; TX_STAT_INC(qnum, tx_pkts_all); sc->debug.stats.txstats[qnum].tx_bytes_all += bf->bf_mpdu->len; @@ -666,6 +808,20 @@ static const struct file_operations fops_xmit = { .llseek = default_llseek, }; +static const struct file_operations fops_stations = { + .read = read_file_stations, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static const struct file_operations fops_misc = { + .read = read_file_misc, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + static ssize_t read_file_recv(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -903,6 +1059,14 @@ int ath9k_init_debug(struct ath_hw *ah) sc, &fops_xmit)) goto err; + if (!debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, + sc, &fops_stations)) + goto err; + + if (!debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, + sc, &fops_misc)) + goto err; + if (!debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_recv)) goto err; diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 1e5078bd0344..59338de0ce19 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -89,7 +89,8 @@ struct ath_interrupt_stats { * @queued: Total MPDUs (non-aggr) queued * @completed: Total MPDUs (non-aggr) completed * @a_aggr: Total no. of aggregates queued - * @a_queued: Total AMPDUs queued + * @a_queued_hw: Total AMPDUs queued to hardware + * @a_queued_sw: Total AMPDUs queued to software queues * @a_completed: Total AMPDUs completed * @a_retries: No. of AMPDUs retried (SW) * @a_xretries: No. of AMPDUs dropped due to xretries @@ -102,6 +103,9 @@ struct ath_interrupt_stats { * @desc_cfg_err: Descriptor configuration errors * @data_urn: TX data underrun errors * @delim_urn: TX delimiter underrun errors + * @puttxbuf: Number of times hardware was given txbuf to write. + * @txstart: Number of times hardware was told to start tx. + * @txprocdesc: Number of times tx descriptor was processed */ struct ath_tx_stats { u32 tx_pkts_all; @@ -109,7 +113,8 @@ struct ath_tx_stats { u32 queued; u32 completed; u32 a_aggr; - u32 a_queued; + u32 a_queued_hw; + u32 a_queued_sw; u32 a_completed; u32 a_retries; u32 a_xretries; @@ -119,6 +124,9 @@ struct ath_tx_stats { u32 desc_cfg_err; u32 data_underrun; u32 delim_underrun; + u32 puttxbuf; + u32 txstart; + u32 txprocdesc; }; /** @@ -167,7 +175,7 @@ int ath9k_init_debug(struct ath_hw *ah); void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, - struct ath_tx_status *ts); + struct ath_tx_status *ts, struct ath_txq *txq); void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs); #else @@ -184,7 +192,8 @@ static inline void ath_debug_stat_interrupt(struct ath_softc *sc, static inline void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, - struct ath_tx_status *ts) + struct ath_tx_status *ts, + struct ath_txq *txq) { } diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index d05163159572..8c18bed3a558 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -89,6 +89,38 @@ bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize, return false; } +void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data, + int eep_start_loc, int size) +{ + int i = 0, j, addr; + u32 addrdata[8]; + u32 data[8]; + + for (addr = 0; addr < size; addr++) { + addrdata[i] = AR5416_EEPROM_OFFSET + + ((addr + eep_start_loc) << AR5416_EEPROM_S); + i++; + if (i == 8) { + REG_READ_MULTI(ah, addrdata, data, i); + + for (j = 0; j < i; j++) { + *eep_data = data[j]; + eep_data++; + } + i = 0; + } + } + + if (i != 0) { + REG_READ_MULTI(ah, addrdata, data, i); + + for (j = 0; j < i; j++) { + *eep_data = data[j]; + eep_data++; + } + } +} + bool ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data) { return common->bus_ops->eeprom_read(common, off, data); diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 58e2ddc927a9..bd82447f5b78 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -665,6 +665,8 @@ int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight, bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize, u16 *indexL, u16 *indexR); bool ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data); +void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data, + int eep_start_loc, int size); void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, u8 *pVpdList, u16 numIntercepts, u8 *pRetVpdList); diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index fbdff7e47952..bc77a308c901 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -27,19 +27,13 @@ static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah) return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF); } -static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) -{ #define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) + +static bool __ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) +{ struct ath_common *common = ath9k_hw_common(ah); u16 *eep_data = (u16 *)&ah->eeprom.map4k; - int addr, eep_start_loc = 0; - - eep_start_loc = 64; - - if (!ath9k_hw_use_flash(ah)) { - ath_dbg(common, ATH_DBG_EEPROM, - "Reading from EEPROM, not flash\n"); - } + int addr, eep_start_loc = 64; for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, eep_data)) { @@ -51,9 +45,34 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) } return true; -#undef SIZE_EEPROM_4K } +static bool __ath9k_hw_usb_4k_fill_eeprom(struct ath_hw *ah) +{ + u16 *eep_data = (u16 *)&ah->eeprom.map4k; + + ath9k_hw_usb_gen_fill_eeprom(ah, eep_data, 64, SIZE_EEPROM_4K); + + return true; +} + +static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (!ath9k_hw_use_flash(ah)) { + ath_dbg(common, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); + } + + if (common->bus_ops->ath_bus_type == ATH_USB) + return __ath9k_hw_usb_4k_fill_eeprom(ah); + else + return __ath9k_hw_4k_fill_eeprom(ah); +} + +#undef SIZE_EEPROM_4K + static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) { #define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 9b6bc8a953bc..8cd8333cc086 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -17,7 +17,7 @@ #include "hw.h" #include "ar9002_phy.h" -#define NUM_EEP_WORDS (sizeof(struct ar9287_eeprom) / sizeof(u16)) +#define SIZE_EEPROM_AR9287 (sizeof(struct ar9287_eeprom) / sizeof(u16)) static int ath9k_hw_ar9287_get_eeprom_ver(struct ath_hw *ah) { @@ -29,25 +29,15 @@ static int ath9k_hw_ar9287_get_eeprom_rev(struct ath_hw *ah) return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF; } -static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) +static bool __ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) { struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct ath_common *common = ath9k_hw_common(ah); u16 *eep_data; - int addr, eep_start_loc; + int addr, eep_start_loc = AR9287_EEP_START_LOC; eep_data = (u16 *)eep; - if (common->bus_ops->ath_bus_type == ATH_USB) - eep_start_loc = AR9287_HTC_EEP_START_LOC; - else - eep_start_loc = AR9287_EEP_START_LOC; - - if (!ath9k_hw_use_flash(ah)) { - ath_dbg(common, ATH_DBG_EEPROM, - "Reading from EEPROM, not flash\n"); - } - - for (addr = 0; addr < NUM_EEP_WORDS; addr++) { + for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) { if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, eep_data)) { ath_dbg(common, ATH_DBG_EEPROM, @@ -60,6 +50,31 @@ static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) return true; } +static bool __ath9k_hw_usb_ar9287_fill_eeprom(struct ath_hw *ah) +{ + u16 *eep_data = (u16 *)&ah->eeprom.map9287; + + ath9k_hw_usb_gen_fill_eeprom(ah, eep_data, + AR9287_HTC_EEP_START_LOC, + SIZE_EEPROM_AR9287); + return true; +} + +static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (!ath9k_hw_use_flash(ah)) { + ath_dbg(common, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); + } + + if (common->bus_ops->ath_bus_type == ATH_USB) + return __ath9k_hw_usb_ar9287_fill_eeprom(ah); + else + return __ath9k_hw_ar9287_fill_eeprom(ah); +} + static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah) { u32 sum = 0, el, integer; @@ -86,7 +101,7 @@ static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah) need_swap = true; eepdata = (u16 *)(&ah->eeprom); - for (addr = 0; addr < NUM_EEP_WORDS; addr++) { + for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) { temp = swab16(*eepdata); *eepdata = temp; eepdata++; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 749a93608664..fccd87df7300 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -86,9 +86,10 @@ static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah) return ((ah->eeprom.def.baseEepHeader.version) & 0xFFF); } -static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) -{ #define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16)) + +static bool __ath9k_hw_def_fill_eeprom(struct ath_hw *ah) +{ struct ath_common *common = ath9k_hw_common(ah); u16 *eep_data = (u16 *)&ah->eeprom.def; int addr, ar5416_eep_start_loc = 0x100; @@ -103,9 +104,34 @@ static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) eep_data++; } return true; -#undef SIZE_EEPROM_DEF } +static bool __ath9k_hw_usb_def_fill_eeprom(struct ath_hw *ah) +{ + u16 *eep_data = (u16 *)&ah->eeprom.def; + + ath9k_hw_usb_gen_fill_eeprom(ah, eep_data, + 0x100, SIZE_EEPROM_DEF); + return true; +} + +static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (!ath9k_hw_use_flash(ah)) { + ath_dbg(common, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); + } + + if (common->bus_ops->ath_bus_type == ATH_USB) + return __ath9k_hw_usb_def_fill_eeprom(ah); + else + return __ath9k_hw_def_fill_eeprom(ah); +} + +#undef SIZE_EEPROM_DEF + static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) { struct ar5416_eeprom_def *eep = @@ -221,9 +247,9 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) } /* Enable fixup for AR_AN_TOP2 if necessary */ - if (AR_SREV_9280_20_OR_LATER(ah) && - (eep->baseEepHeader.version & 0xff) > 0x0a && - eep->baseEepHeader.pwdclkind == 0) + if ((ah->hw_version.devid == AR9280_DEVID_PCI) && + ((eep->baseEepHeader.version & 0xff) > 0x0a) && + (eep->baseEepHeader.pwdclkind == 0)) ah->need_an_top2_fixup = 1; if ((common->bus_ops->ath_bus_type == ATH_USB) && diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 133764069246..fb4f17a5183d 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -201,8 +201,7 @@ static bool ath_is_rfkill_set(struct ath_softc *sc) void ath9k_rfkill_poll_state(struct ieee80211_hw *hw) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; bool blocked = !!ath_is_rfkill_set(sc); wiphy_rfkill_set_hw_state(hw->wiphy, blocked); diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 780ac5eac501..0cb504d7b8c4 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -366,7 +366,7 @@ struct ath9k_htc_priv { u16 seq_no; u32 bmiss_cnt; - struct ath9k_hw_cal_data caldata[ATH9K_NUM_CHANNELS]; + struct ath9k_hw_cal_data caldata; spinlock_t beacon_lock; @@ -460,7 +460,6 @@ void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv); void ath9k_ps_work(struct work_struct *work); bool ath9k_htc_setpower(struct ath9k_htc_priv *priv, enum ath9k_power_mode mode); -void ath_update_txpow(struct ath9k_htc_priv *priv); void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv); void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index fe70f67aa088..7e630a81b453 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -389,7 +389,8 @@ void ath9k_htc_radio_enable(struct ieee80211_hw *hw) ret, ah->curchan->channel); } - ath_update_txpow(priv); + ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit, + &priv->curtxpow); /* Start RX */ WMI_CMD(WMI_START_RECV_CMDID); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 0352f0994caa..a7bc26d1bd66 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -294,6 +294,34 @@ static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset) return be32_to_cpu(val); } +static void ath9k_multi_regread(void *hw_priv, u32 *addr, + u32 *val, u16 count) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + __be32 tmpaddr[8]; + __be32 tmpval[8]; + int i, ret; + + for (i = 0; i < count; i++) { + tmpaddr[i] = cpu_to_be32(addr[i]); + } + + ret = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID, + (u8 *)tmpaddr , sizeof(u32) * count, + (u8 *)tmpval, sizeof(u32) * count, + 100); + if (unlikely(ret)) { + ath_dbg(common, ATH_DBG_WMI, + "Multiple REGISTER READ FAILED (count: %d)\n", count); + } + + for (i = 0; i < count; i++) { + val[i] = be32_to_cpu(tmpval[i]); + } +} + static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset) { struct ath_hw *ah = (struct ath_hw *) hw_priv; @@ -404,6 +432,7 @@ static void ath9k_regwrite_flush(void *hw_priv) static const struct ath_ops ath9k_common_ops = { .read = ath9k_regread, + .multi_read = ath9k_multi_regread, .write = ath9k_regwrite, .enable_write_buffer = ath9k_enable_regwrite_buffer, .write_flush = ath9k_regwrite_flush, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 6bb59958f71e..953036a4ed53 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -24,17 +24,6 @@ static struct dentry *ath9k_debugfs_root; /* Utilities */ /*************/ -void ath_update_txpow(struct ath9k_htc_priv *priv) -{ - struct ath_hw *ah = priv->ah; - - if (priv->curtxpow != priv->txpowlimit) { - ath9k_hw_set_txpowerlimit(ah, priv->txpowlimit, false); - /* read back in case value is clamped */ - priv->curtxpow = ath9k_hw_regulatory(ah)->power_limit; - } -} - /* HACK Alert: Use 11NG for 2.4, use 11NA for 5 */ static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv, struct ath9k_channel *ichan) @@ -121,7 +110,7 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv) struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_channel *channel = priv->hw->conf.channel; - struct ath9k_hw_cal_data *caldata; + struct ath9k_hw_cal_data *caldata = NULL; enum htc_phymode mode; __be16 htc_mode; u8 cmd_rsp; @@ -139,7 +128,7 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv) WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); WMI_CMD(WMI_STOP_RECV_CMDID); - caldata = &priv->caldata[channel->hw_value]; + caldata = &priv->caldata; ret = ath9k_hw_reset(ah, ah->curchan, caldata, false); if (ret) { ath_err(common, @@ -147,7 +136,8 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv) channel->center_freq, ret); } - ath_update_txpow(priv); + ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit, + &priv->curtxpow); WMI_CMD(WMI_START_RECV_CMDID); ath9k_host_rx_init(priv); @@ -202,7 +192,8 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf), fastcc); - caldata = &priv->caldata[channel->hw_value]; + if (!fastcc) + caldata = &priv->caldata; ret = ath9k_hw_reset(ah, hchan, caldata, fastcc); if (ret) { ath_err(common, @@ -211,7 +202,8 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, goto err; } - ath_update_txpow(priv); + ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit, + &priv->curtxpow); WMI_CMD(WMI_START_RECV_CMDID); if (ret) @@ -987,7 +979,8 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) return ret; } - ath_update_txpow(priv); + ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit, + &priv->curtxpow); mode = ath9k_htc_get_curmode(priv, init_channel); htc_mode = cpu_to_be16(mode); @@ -1051,6 +1044,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) cancel_work_sync(&priv->fatal_work); cancel_work_sync(&priv->ps_work); cancel_delayed_work_sync(&priv->ath9k_led_blink_work); + cancel_delayed_work_sync(&priv->ath9k_ani_work); ath9k_led_stop_brightness(priv); mutex_lock(&priv->mutex); @@ -1252,7 +1246,8 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_POWER) { priv->txpowlimit = 2 * conf->power_level; - ath_update_txpow(priv); + ath9k_cmn_update_txpow(priv->ah, priv->curtxpow, + priv->txpowlimit, &priv->curtxpow); } if (changed & IEEE80211_CONF_CHANGE_IDLE) { @@ -1557,7 +1552,7 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, - u16 tid, u16 *ssn) + u16 tid, u16 *ssn, u8 buf_size) { struct ath9k_htc_priv *priv = hw->priv; struct ath9k_htc_sta *ista; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 9f01e50d5cda..f9cf81551817 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -495,6 +495,17 @@ static int __ath9k_hw_init(struct ath_hw *ah) if (ah->hw_version.devid == AR5416_AR9100_DEVID) ah->hw_version.macVersion = AR_SREV_VERSION_9100; + ath9k_hw_read_revisions(ah); + + /* + * Read back AR_WA into a permanent copy and set bits 14 and 17. + * We need to do this to avoid RMW of this register. We cannot + * read the reg when chip is asleep. + */ + ah->WARegVal = REG_READ(ah, AR_WA); + ah->WARegVal |= (AR_WA_D3_L1_DISABLE | + AR_WA_ASPM_TIMER_BASED_DISABLE); + if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { ath_err(common, "Couldn't reset chip\n"); return -EIO; @@ -563,14 +574,6 @@ static int __ath9k_hw_init(struct ath_hw *ah) ath9k_hw_init_mode_regs(ah); - /* - * Read back AR_WA into a permanent copy and set bits 14 and 17. - * We need to do this to avoid RMW of this register. We cannot - * read the reg when chip is asleep. - */ - ah->WARegVal = REG_READ(ah, AR_WA); - ah->WARegVal |= (AR_WA_D3_L1_DISABLE | - AR_WA_ASPM_TIMER_BASED_DISABLE); if (ah->is_pciexpress) ath9k_hw_configpcipowersave(ah, 0, 0); @@ -668,14 +671,51 @@ static void ath9k_hw_init_qos(struct ath_hw *ah) REGWRITE_BUFFER_FLUSH(ah); } +unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah) +{ + REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) & ~(PLL3_DO_MEAS_MASK))); + udelay(100); + REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) | PLL3_DO_MEAS_MASK)); + + while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0) + udelay(100); + + return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3; +} +EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc); + +#define DPLL2_KD_VAL 0x3D +#define DPLL2_KI_VAL 0x06 +#define DPLL3_PHASE_SHIFT_VAL 0x1 + static void ath9k_hw_init_pll(struct ath_hw *ah, struct ath9k_channel *chan) { u32 pll; - if (AR_SREV_9485(ah)) + if (AR_SREV_9485(ah)) { + REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666); + REG_WRITE(ah, AR_CH0_DDR_DPLL2, 0x19e82f01); + + REG_RMW_FIELD(ah, AR_CH0_DDR_DPLL3, + AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); + + REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); + udelay(100); + REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666); + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, + AR_CH0_DPLL2_KD, DPLL2_KD_VAL); + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, + AR_CH0_DPLL2_KI, DPLL2_KI_VAL); + + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3, + AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); + REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c); + udelay(110); + } + pll = ath9k_hw_compute_pll_control(ah, chan); REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); @@ -1082,8 +1122,6 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) return false; } - ath9k_hw_read_revisions(ah); - return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM); } @@ -1348,8 +1386,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_spur_mitigate_freq(ah, chan); ah->eep_ops->set_board_values(ah, chan); - ath9k_hw_set_operating_mode(ah, ah->opmode); - ENABLE_REGWRITE_BUFFER(ah); REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr)); @@ -1367,6 +1403,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REGWRITE_BUFFER_FLUSH(ah); + ath9k_hw_set_operating_mode(ah, ah->opmode); + r = ath9k_hw_rf_set_freq(ah, chan); if (r) return r; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index ea9fde670646..ef79f4c876ca 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -70,6 +70,9 @@ #define REG_READ(_ah, _reg) \ ath9k_hw_common(_ah)->ops->read((_ah), (_reg)) +#define REG_READ_MULTI(_ah, _addr, _val, _cnt) \ + ath9k_hw_common(_ah)->ops->multi_read((_ah), (_addr), (_val), (_cnt)) + #define ENABLE_REGWRITE_BUFFER(_ah) \ do { \ if (ath9k_hw_common(_ah)->ops->enable_write_buffer) \ @@ -926,6 +929,7 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); void ath9k_hw_reset_tsf(struct ath_hw *ah); void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); void ath9k_hw_init_global_settings(struct ath_hw *ah); +unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah); void ath9k_hw_set11nmac2040(struct ath_hw *ah); void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 087a6a95edd5..e5c1eead98a2 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -254,8 +254,7 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah); return ath_reg_notifier_apply(wiphy, request, reg); @@ -442,9 +441,10 @@ static int ath9k_init_queues(struct ath_softc *sc) sc->config.cabqReadytime = ATH_CABQ_READY_TIME; ath_cabq_update(sc); - for (i = 0; i < WME_NUM_AC; i++) + for (i = 0; i < WME_NUM_AC; i++) { sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i); - + sc->tx.txq_map[i]->mac80211_qnum = i; + } return 0; } @@ -516,10 +516,8 @@ static void ath9k_init_misc(struct ath_softc *sc) sc->beacon.slottime = ATH9K_SLOT_TIME_9; - for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { + for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) sc->beacon.bslot[i] = NULL; - sc->beacon.bslot_aphy[i] = NULL; - } if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT; @@ -537,6 +535,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, if (!ah) return -ENOMEM; + ah->hw = sc->hw; ah->hw_version.devid = devid; ah->hw_version.subsysid = subsysid; sc->sc_ah = ah; @@ -554,10 +553,13 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, common->btcoex_enabled = ath9k_btcoex_enable == 1; spin_lock_init(&common->cc_lock); - spin_lock_init(&sc->wiphy_lock); spin_lock_init(&sc->sc_serial_rw); spin_lock_init(&sc->sc_pm_lock); mutex_init(&sc->mutex); +#ifdef CONFIG_ATH9K_DEBUGFS + spin_lock_init(&sc->nodes_lock); + INIT_LIST_HEAD(&sc->nodes); +#endif tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, (unsigned long)sc); @@ -699,7 +701,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, const struct ath_bus_ops *bus_ops) { struct ieee80211_hw *hw = sc->hw; - struct ath_wiphy *aphy = hw->priv; struct ath_common *common; struct ath_hw *ah; int error = 0; @@ -754,10 +755,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, INIT_WORK(&sc->hw_check_work, ath_hw_check); INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); - INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); - INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); - sc->wiphy_scheduler_int = msecs_to_jiffies(500); - aphy->last_rssi = ATH_RSSI_DUMMY_MARKER; + sc->last_rssi = ATH_RSSI_DUMMY_MARKER; ath_init_leds(sc); ath_start_rfkill_poll(sc); @@ -812,7 +810,6 @@ static void ath9k_deinit_softc(struct ath_softc *sc) void ath9k_deinit_device(struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; - int i = 0; ath9k_ps_wakeup(sc); @@ -821,21 +818,11 @@ void ath9k_deinit_device(struct ath_softc *sc) ath9k_ps_restore(sc); - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - if (aphy == NULL) - continue; - sc->sec_wiphy[i] = NULL; - ieee80211_unregister_hw(aphy->hw); - ieee80211_free_hw(aphy->hw); - } - ieee80211_unregister_hw(hw); pm_qos_remove_request(&sc->pm_qos_req); ath_rx_cleanup(sc); ath_tx_cleanup(sc); ath9k_deinit_softc(sc); - kfree(sc->sec_wiphy); } void ath_descdma_cleanup(struct ath_softc *sc, diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 180170d3ce25..c75d40fb86f1 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -690,17 +690,23 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, rs->rs_flags |= ATH9K_RX_DECRYPT_BUSY; if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) { + /* + * Treat these errors as mutually exclusive to avoid spurious + * extra error reports from the hardware. If a CRC error is + * reported, then decryption and MIC errors are irrelevant, + * the frame is going to be dropped either way + */ if (ads.ds_rxstatus8 & AR_CRCErr) rs->rs_status |= ATH9K_RXERR_CRC; - if (ads.ds_rxstatus8 & AR_PHYErr) { + else if (ads.ds_rxstatus8 & AR_PHYErr) { rs->rs_status |= ATH9K_RXERR_PHY; phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode); rs->rs_phyerr = phyerr; - } - if (ads.ds_rxstatus8 & AR_DecryptCRCErr) + } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) rs->rs_status |= ATH9K_RXERR_DECRYPT; - if (ads.ds_rxstatus8 & AR_MichaelErr) + else if (ads.ds_rxstatus8 & AR_MichaelErr) rs->rs_status |= ATH9K_RXERR_MIC; + if (ads.ds_rxstatus8 & AR_KeyMiss) rs->rs_status |= ATH9K_RXERR_DECRYPT; } diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 7512f97e8f49..04d58ae923bb 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -639,6 +639,8 @@ enum ath9k_rx_filter { ATH9K_RX_FILTER_PHYERR = 0x00000100, ATH9K_RX_FILTER_MYBEACON = 0x00000200, ATH9K_RX_FILTER_COMP_BAR = 0x00000400, + ATH9K_RX_FILTER_COMP_BA = 0x00000800, + ATH9K_RX_FILTER_UNCOMP_BA_BAR = 0x00001000, ATH9K_RX_FILTER_PSPOLL = 0x00004000, ATH9K_RX_FILTER_PHYRADAR = 0x00002000, ATH9K_RX_FILTER_MCAST_BCAST_ALL = 0x00008000, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index da5c64597c1f..4ed43b2b8df6 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -18,17 +18,6 @@ #include "ath9k.h" #include "btcoex.h" -static void ath_update_txpow(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - - if (sc->curtxpow != sc->config.txpowlimit) { - ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false); - /* read back in case value is clamped */ - sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit; - } -} - static u8 parse_mpdudensity(u8 mpdudensity) { /* @@ -64,19 +53,6 @@ static u8 parse_mpdudensity(u8 mpdudensity) } } -static struct ath9k_channel *ath_get_curchannel(struct ath_softc *sc, - struct ieee80211_hw *hw) -{ - struct ieee80211_channel *curchan = hw->conf.channel; - struct ath9k_channel *channel; - u8 chan_idx; - - chan_idx = curchan->hw_value; - channel = &sc->sc_ah->channels[chan_idx]; - ath9k_update_ichannel(sc, hw, channel); - return channel; -} - bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) { unsigned long flags; @@ -177,7 +153,12 @@ static void ath_update_survey_nf(struct ath_softc *sc, int channel) } } -static void ath_update_survey_stats(struct ath_softc *sc) +/* + * Updates the survey statistics and returns the busy time since last + * update in %, if the measurement duration was long enough for the + * result to be useful, -1 otherwise. + */ +static int ath_update_survey_stats(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); @@ -185,9 +166,10 @@ static void ath_update_survey_stats(struct ath_softc *sc) struct survey_info *survey = &sc->survey[pos]; struct ath_cycle_counters *cc = &common->cc_survey; unsigned int div = common->clockrate * 1000; + int ret = 0; if (!ah->curchan) - return; + return -1; if (ah->power_mode == ATH9K_PM_AWAKE) ath_hw_cycle_counters_update(common); @@ -202,9 +184,18 @@ static void ath_update_survey_stats(struct ath_softc *sc) survey->channel_time_rx += cc->rx_frame / div; survey->channel_time_tx += cc->tx_frame / div; } + + if (cc->cycles < div) + return -1; + + if (cc->cycles > 0) + ret = cc->rx_busy * 100 / cc->cycles; + memset(cc, 0, sizeof(*cc)); ath_update_survey_nf(sc, pos); + + return ret; } /* @@ -215,7 +206,6 @@ static void ath_update_survey_stats(struct ath_softc *sc) int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, struct ath9k_channel *hchan) { - struct ath_wiphy *aphy = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &common->hw->conf; @@ -227,10 +217,13 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, if (sc->sc_flags & SC_OP_INVALID) return -EIO; + sc->hw_busy_count = 0; + del_timer_sync(&common->ani.timer); cancel_work_sync(&sc->paprd_work); cancel_work_sync(&sc->hw_check_work); cancel_delayed_work_sync(&sc->tx_complete_work); + cancel_delayed_work_sync(&sc->hw_pll_work); ath9k_ps_wakeup(sc); @@ -251,6 +244,9 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, if (!ath_stoprecv(sc)) stopped = false; + if (!ath9k_hw_check_alive(ah)) + stopped = false; + /* XXX: do not flush receive queue here. We don't want * to flush data frames already in queue because of * changing channel. */ @@ -259,7 +255,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, fastcc = false; if (!(sc->sc_flags & SC_OP_OFFCHANNEL)) - caldata = &aphy->caldata; + caldata = &sc->caldata; ath_dbg(common, ATH_DBG_CONFIG, "(%u MHz) -> (%u MHz), conf_is_ht40: %d fastcc: %d\n", @@ -281,17 +277,21 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, goto ps_restore; } - ath_update_txpow(sc); + ath9k_cmn_update_txpow(ah, sc->curtxpow, + sc->config.txpowlimit, &sc->curtxpow); ath9k_hw_set_interrupts(ah, ah->imask); if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) { if (sc->sc_flags & SC_OP_BEACONS) ath_beacon_config(sc, NULL); ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); + ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2); ath_start_ani(common); } ps_restore: + ieee80211_wake_queues(hw); + spin_unlock_bh(&sc->sc_pcu_lock); ath9k_ps_restore(sc); @@ -549,6 +549,12 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) struct ath_hw *ah = sc->sc_ah; an = (struct ath_node *)sta->drv_priv; +#ifdef CONFIG_ATH9K_DEBUGFS + spin_lock(&sc->nodes_lock); + list_add(&an->list, &sc->nodes); + spin_unlock(&sc->nodes_lock); + an->sta = sta; +#endif if ((ah->caps.hw_caps) & ATH9K_HW_CAP_APM) sc->sc_flags |= SC_OP_ENABLE_APM; @@ -564,6 +570,13 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) { struct ath_node *an = (struct ath_node *)sta->drv_priv; +#ifdef CONFIG_ATH9K_DEBUGFS + spin_lock(&sc->nodes_lock); + list_del(&an->list); + spin_unlock(&sc->nodes_lock); + an->sta = NULL; +#endif + if (sc->sc_flags & SC_OP_TXAGGR) ath_tx_node_cleanup(sc, an); } @@ -571,17 +584,25 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) void ath_hw_check(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work); - int i; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + unsigned long flags; + int busy; ath9k_ps_wakeup(sc); + if (ath9k_hw_check_alive(sc->sc_ah)) + goto out; - for (i = 0; i < 3; i++) { - if (ath9k_hw_check_alive(sc->sc_ah)) - goto out; + spin_lock_irqsave(&common->cc_lock, flags); + busy = ath_update_survey_stats(sc); + spin_unlock_irqrestore(&common->cc_lock, flags); - msleep(1); - } - ath_reset(sc, true); + ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, " + "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1); + if (busy >= 99) { + if (++sc->hw_busy_count >= 3) + ath_reset(sc, true); + } else if (busy >= 0) + sc->hw_busy_count = 0; out: ath9k_ps_restore(sc); @@ -604,7 +625,15 @@ void ath9k_tasklet(unsigned long data) ath9k_ps_wakeup(sc); spin_lock(&sc->sc_pcu_lock); - if (!ath9k_hw_check_alive(ah)) + /* + * Only run the baseband hang check if beacons stop working in AP or + * IBSS mode, because it has a high false positive rate. For station + * mode it should not be necessary, since the upper layers will detect + * this through a beacon miss automatically and the following channel + * change will trigger a hardware reset anyway + */ + if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0 && + !ath9k_hw_check_alive(ah)) ieee80211_queue_work(sc->hw, &sc->hw_check_work); if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) @@ -783,54 +812,11 @@ chip_reset: #undef SCHED_INTR } -static u32 ath_get_extchanmode(struct ath_softc *sc, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) -{ - u32 chanmode = 0; - - switch (chan->band) { - case IEEE80211_BAND_2GHZ: - switch(channel_type) { - case NL80211_CHAN_NO_HT: - case NL80211_CHAN_HT20: - chanmode = CHANNEL_G_HT20; - break; - case NL80211_CHAN_HT40PLUS: - chanmode = CHANNEL_G_HT40PLUS; - break; - case NL80211_CHAN_HT40MINUS: - chanmode = CHANNEL_G_HT40MINUS; - break; - } - break; - case IEEE80211_BAND_5GHZ: - switch(channel_type) { - case NL80211_CHAN_NO_HT: - case NL80211_CHAN_HT20: - chanmode = CHANNEL_A_HT20; - break; - case NL80211_CHAN_HT40PLUS: - chanmode = CHANNEL_A_HT40PLUS; - break; - case NL80211_CHAN_HT40MINUS: - chanmode = CHANNEL_A_HT40MINUS; - break; - } - break; - default: - break; - } - - return chanmode; -} - static void ath9k_bss_assoc_info(struct ath_softc *sc, struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf) { - struct ath_wiphy *aphy = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); @@ -854,7 +840,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, ath_beacon_config(sc, vif); /* Reset rssi stats */ - aphy->last_rssi = ATH_RSSI_DUMMY_MARKER; + sc->last_rssi = ATH_RSSI_DUMMY_MARKER; sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; sc->sc_flags |= SC_OP_ANI_RUN; @@ -881,7 +867,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) ath9k_hw_configpcipowersave(ah, 0, 0); if (!ah->curchan) - ah->curchan = ath_get_curchannel(sc, sc->hw); + ah->curchan = ath9k_cmn_get_curchannel(sc->hw, ah); r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); if (r) { @@ -890,7 +876,8 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) channel->center_freq, r); } - ath_update_txpow(sc); + ath9k_cmn_update_txpow(ah, sc->curtxpow, + sc->config.txpowlimit, &sc->curtxpow); if (ath_startrecv(sc) != 0) { ath_err(common, "Unable to restart recv logic\n"); goto out; @@ -942,7 +929,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) ath_flushrecv(sc); /* flush recv queue */ if (!ah->curchan) - ah->curchan = ath_get_curchannel(sc, hw); + ah->curchan = ath9k_cmn_get_curchannel(hw, ah); r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); if (r) { @@ -966,6 +953,8 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) struct ieee80211_hw *hw = sc->hw; int r; + sc->hw_busy_count = 0; + /* Stop ANI */ del_timer_sync(&common->ani.timer); @@ -993,7 +982,8 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) * that changes the channel so update any state that * might change as a result. */ - ath_update_txpow(sc); + ath9k_cmn_update_txpow(ah, sc->curtxpow, + sc->config.txpowlimit, &sc->curtxpow); if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL))) ath_beacon_config(sc, NULL); /* restart beacons */ @@ -1021,38 +1011,13 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) return r; } -/* XXX: Remove me once we don't depend on ath9k_channel for all - * this redundant data */ -void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, - struct ath9k_channel *ichan) -{ - struct ieee80211_channel *chan = hw->conf.channel; - struct ieee80211_conf *conf = &hw->conf; - - ichan->channel = chan->center_freq; - ichan->chan = chan; - - if (chan->band == IEEE80211_BAND_2GHZ) { - ichan->chanmode = CHANNEL_G; - ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G; - } else { - ichan->chanmode = CHANNEL_A; - ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; - } - - if (conf_is_ht(conf)) - ichan->chanmode = ath_get_extchanmode(sc, chan, - conf->channel_type); -} - /**********************/ /* mac80211 callbacks */ /**********************/ static int ath9k_start(struct ieee80211_hw *hw) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_channel *curchan = hw->conf.channel; @@ -1065,32 +1030,10 @@ static int ath9k_start(struct ieee80211_hw *hw) mutex_lock(&sc->mutex); - if (ath9k_wiphy_started(sc)) { - if (sc->chan_idx == curchan->hw_value) { - /* - * Already on the operational channel, the new wiphy - * can be marked active. - */ - aphy->state = ATH_WIPHY_ACTIVE; - ieee80211_wake_queues(hw); - } else { - /* - * Another wiphy is on another channel, start the new - * wiphy in paused state. - */ - aphy->state = ATH_WIPHY_PAUSED; - ieee80211_stop_queues(hw); - } - mutex_unlock(&sc->mutex); - return 0; - } - aphy->state = ATH_WIPHY_ACTIVE; - /* setup initial channel */ - sc->chan_idx = curchan->hw_value; - init_channel = ath_get_curchannel(sc, hw); + init_channel = ath9k_cmn_get_curchannel(hw, ah); /* Reset SERDES registers */ ath9k_hw_configpcipowersave(ah, 0, 0); @@ -1116,7 +1059,8 @@ static int ath9k_start(struct ieee80211_hw *hw) * This is needed only to setup initial state * but it's best done after a reset. */ - ath_update_txpow(sc); + ath9k_cmn_update_txpow(ah, sc->curtxpow, + sc->config.txpowlimit, &sc->curtxpow); /* * Setup the hardware after reset: @@ -1191,19 +1135,11 @@ mutex_unlock: static int ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_tx_control txctl; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) { - ath_dbg(common, ATH_DBG_XMIT, - "ath9k: %s: TX in unexpected wiphy state %d\n", - wiphy_name(hw->wiphy), aphy->state); - goto exit; - } - if (sc->ps_enabled) { /* * mac80211 does not set PM field for normal data frames, so we @@ -1262,44 +1198,26 @@ exit: static void ath9k_stop(struct ieee80211_hw *hw) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - int i; mutex_lock(&sc->mutex); - aphy->state = ATH_WIPHY_INACTIVE; - if (led_blink) cancel_delayed_work_sync(&sc->ath_led_blink_work); cancel_delayed_work_sync(&sc->tx_complete_work); + cancel_delayed_work_sync(&sc->hw_pll_work); cancel_work_sync(&sc->paprd_work); cancel_work_sync(&sc->hw_check_work); - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i]) - break; - } - - if (i == sc->num_sec_wiphy) { - cancel_delayed_work_sync(&sc->wiphy_work); - cancel_work_sync(&sc->chan_work); - } - if (sc->sc_flags & SC_OP_INVALID) { ath_dbg(common, ATH_DBG_ANY, "Device not present\n"); mutex_unlock(&sc->mutex); return; } - if (ath9k_wiphy_started(sc)) { - mutex_unlock(&sc->mutex); - return; /* another wiphy still in use */ - } - /* Ensure HW is awake when we try to shut it down. */ ath9k_ps_wakeup(sc); @@ -1325,6 +1243,11 @@ static void ath9k_stop(struct ieee80211_hw *hw) } else sc->rx.rxlink = NULL; + if (sc->rx.frag) { + dev_kfree_skb_any(sc->rx.frag); + sc->rx.frag = NULL; + } + /* disable HAL and put h/w to sleep */ ath9k_hw_disable(ah); ath9k_hw_configpcipowersave(ah, 1, 1); @@ -1340,7 +1263,6 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath9k_ps_restore(sc); sc->ps_idle = true; - ath9k_set_wiphy_idle(aphy, true); ath_radio_disable(sc, hw); sc->sc_flags |= SC_OP_INVALID; @@ -1352,112 +1274,238 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath_dbg(common, ATH_DBG_CONFIG, "Driver halt\n"); } -static int ath9k_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +bool ath9k_uses_beacons(int type) +{ + switch (type) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + return true; + default: + return false; + } +} + +static void ath9k_reclaim_beacon(struct ath_softc *sc, + struct ieee80211_vif *vif) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp = (void *)vif->drv_priv; - enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED; - int ret = 0; - mutex_lock(&sc->mutex); + /* Disable SWBA interrupt */ + sc->sc_ah->imask &= ~ATH9K_INT_SWBA; + ath9k_ps_wakeup(sc); + ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask); + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); + tasklet_kill(&sc->bcon_tasklet); + ath9k_ps_restore(sc); + + ath_beacon_return(sc, avp); + sc->sc_flags &= ~SC_OP_BEACONS; + + if (sc->nbcnvifs > 0) { + /* Re-enable beaconing */ + sc->sc_ah->imask |= ATH9K_INT_SWBA; + ath9k_ps_wakeup(sc); + ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask); + ath9k_ps_restore(sc); + } +} + +static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct ath9k_vif_iter_data *iter_data = data; + int i; + + if (iter_data->hw_macaddr) + for (i = 0; i < ETH_ALEN; i++) + iter_data->mask[i] &= + ~(iter_data->hw_macaddr[i] ^ mac[i]); switch (vif->type) { - case NL80211_IFTYPE_STATION: - ic_opmode = NL80211_IFTYPE_STATION; + case NL80211_IFTYPE_AP: + iter_data->naps++; break; - case NL80211_IFTYPE_WDS: - ic_opmode = NL80211_IFTYPE_WDS; + case NL80211_IFTYPE_STATION: + iter_data->nstations++; break; case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_AP: + iter_data->nadhocs++; + break; case NL80211_IFTYPE_MESH_POINT: - if (sc->nbcnvifs >= ATH_BCBUF) { - ret = -ENOBUFS; - goto out; - } - ic_opmode = vif->type; + iter_data->nmeshes++; + break; + case NL80211_IFTYPE_WDS: + iter_data->nwds++; break; default: - ath_err(common, "Interface type %d not yet supported\n", - vif->type); - ret = -EOPNOTSUPP; - goto out; + iter_data->nothers++; + break; } +} - ath_dbg(common, ATH_DBG_CONFIG, - "Attach a VIF of type: %d\n", ic_opmode); +/* Called with sc->mutex held. */ +void ath9k_calculate_iter_data(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ath9k_vif_iter_data *iter_data) +{ + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); - /* Set the VIF opmode */ - avp->av_opmode = ic_opmode; - avp->av_bslot = -1; + /* + * Use the hardware MAC address as reference, the hardware uses it + * together with the BSSID mask when matching addresses. + */ + memset(iter_data, 0, sizeof(*iter_data)); + iter_data->hw_macaddr = common->macaddr; + memset(&iter_data->mask, 0xff, ETH_ALEN); - sc->nvifs++; + if (vif) + ath9k_vif_iter(iter_data, vif->addr, vif); - ath9k_set_bssid_mask(hw, vif); + /* Get list of all active MAC addresses */ + ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter, + iter_data); +} - if (sc->nvifs > 1) - goto out; /* skip global settings for secondary vif */ +/* Called with sc->mutex held. */ +static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_vif_iter_data iter_data; + + ath9k_calculate_iter_data(hw, vif, &iter_data); + + ath9k_ps_wakeup(sc); + /* Set BSSID mask. */ + memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); + ath_hw_setbssidmask(common); - if (ic_opmode == NL80211_IFTYPE_AP) { + /* Set op-mode & TSF */ + if (iter_data.naps > 0) { ath9k_hw_set_tsfadjust(ah, 1); sc->sc_flags |= SC_OP_TSF_RESET; - } + ah->opmode = NL80211_IFTYPE_AP; + } else { + ath9k_hw_set_tsfadjust(ah, 0); + sc->sc_flags &= ~SC_OP_TSF_RESET; - /* Set the device opmode */ - ah->opmode = ic_opmode; + if (iter_data.nwds + iter_data.nmeshes) + ah->opmode = NL80211_IFTYPE_AP; + else if (iter_data.nadhocs) + ah->opmode = NL80211_IFTYPE_ADHOC; + else + ah->opmode = NL80211_IFTYPE_STATION; + } /* * Enable MIB interrupts when there are hardware phy counters. - * Note we only do this (at the moment) for station mode. */ - if ((vif->type == NL80211_IFTYPE_STATION) || - (vif->type == NL80211_IFTYPE_ADHOC) || - (vif->type == NL80211_IFTYPE_MESH_POINT)) { + if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0) { if (ah->config.enable_ani) ah->imask |= ATH9K_INT_MIB; ah->imask |= ATH9K_INT_TSFOOR; + } else { + ah->imask &= ~ATH9K_INT_MIB; + ah->imask &= ~ATH9K_INT_TSFOOR; } ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_ps_restore(sc); - if (vif->type == NL80211_IFTYPE_AP || - vif->type == NL80211_IFTYPE_ADHOC) { + /* Set up ANI */ + if ((iter_data.naps + iter_data.nadhocs) > 0) { sc->sc_flags |= SC_OP_ANI_RUN; ath_start_ani(common); + } else { + sc->sc_flags &= ~SC_OP_ANI_RUN; + del_timer_sync(&common->ani.timer); } +} -out: - mutex_unlock(&sc->mutex); - return ret; +/* Called with sc->mutex held, vif counts set up properly. */ +static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath_softc *sc = hw->priv; + + ath9k_calculate_summary_state(hw, vif); + + if (ath9k_uses_beacons(vif->type)) { + int error; + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); + /* This may fail because upper levels do not have beacons + * properly configured yet. That's OK, we assume it + * will be properly configured and then we will be notified + * in the info_changed method and set up beacons properly + * there. + */ + error = ath_beacon_alloc(sc, vif); + if (!error) + ath_beacon_config(sc, vif); + } } -static void ath9k_reclaim_beacon(struct ath_softc *sc, - struct ieee80211_vif *vif) + +static int ath9k_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp = (void *)vif->drv_priv; + int ret = 0; - /* Disable SWBA interrupt */ - sc->sc_ah->imask &= ~ATH9K_INT_SWBA; - ath9k_ps_wakeup(sc); - ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask); - ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); - tasklet_kill(&sc->bcon_tasklet); - ath9k_ps_restore(sc); + mutex_lock(&sc->mutex); - ath_beacon_return(sc, avp); - sc->sc_flags &= ~SC_OP_BEACONS; + switch (vif->type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: + break; + default: + ath_err(common, "Interface type %d not yet supported\n", + vif->type); + ret = -EOPNOTSUPP; + goto out; + } - if (sc->nbcnvifs > 0) { - /* Re-enable beaconing */ - sc->sc_ah->imask |= ATH9K_INT_SWBA; - ath9k_ps_wakeup(sc); - ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask); - ath9k_ps_restore(sc); + if (ath9k_uses_beacons(vif->type)) { + if (sc->nbcnvifs >= ATH_BCBUF) { + ath_err(common, "Not enough beacon buffers when adding" + " new interface of type: %i\n", + vif->type); + ret = -ENOBUFS; + goto out; + } + } + + if ((vif->type == NL80211_IFTYPE_ADHOC) && + sc->nvifs > 0) { + ath_err(common, "Cannot create ADHOC interface when other" + " interfaces already exist.\n"); + ret = -EINVAL; + goto out; } + + ath_dbg(common, ATH_DBG_CONFIG, + "Attach a VIF of type: %d\n", vif->type); + + /* Set the VIF opmode */ + avp->av_opmode = vif->type; + avp->av_bslot = -1; + + sc->nvifs++; + + ath9k_do_vif_add_setup(hw, vif); +out: + mutex_unlock(&sc->mutex); + return ret; } static int ath9k_change_interface(struct ieee80211_hw *hw, @@ -1465,40 +1513,40 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, enum nl80211_iftype new_type, bool p2p) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); int ret = 0; ath_dbg(common, ATH_DBG_CONFIG, "Change Interface\n"); mutex_lock(&sc->mutex); - switch (new_type) { - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_ADHOC: + /* See if new interface type is valid. */ + if ((new_type == NL80211_IFTYPE_ADHOC) && + (sc->nvifs > 1)) { + ath_err(common, "When using ADHOC, it must be the only" + " interface.\n"); + ret = -EINVAL; + goto out; + } + + if (ath9k_uses_beacons(new_type) && + !ath9k_uses_beacons(vif->type)) { if (sc->nbcnvifs >= ATH_BCBUF) { ath_err(common, "No beacon slot available\n"); ret = -ENOBUFS; goto out; } - break; - case NL80211_IFTYPE_STATION: - /* Stop ANI */ - sc->sc_flags &= ~SC_OP_ANI_RUN; - del_timer_sync(&common->ani.timer); - if ((vif->type == NL80211_IFTYPE_AP) || - (vif->type == NL80211_IFTYPE_ADHOC)) - ath9k_reclaim_beacon(sc, vif); - break; - default: - ath_err(common, "Interface type %d not yet supported\n", - vif->type); - ret = -ENOTSUPP; - goto out; } + + /* Clean up old vif stuff */ + if (ath9k_uses_beacons(vif->type)) + ath9k_reclaim_beacon(sc, vif); + + /* Add new settings */ vif->type = new_type; vif->p2p = p2p; + ath9k_do_vif_add_setup(hw, vif); out: mutex_unlock(&sc->mutex); return ret; @@ -1507,25 +1555,20 @@ out: static void ath9k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n"); mutex_lock(&sc->mutex); - /* Stop ANI */ - sc->sc_flags &= ~SC_OP_ANI_RUN; - del_timer_sync(&common->ani.timer); + sc->nvifs--; /* Reclaim beacon resources */ - if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || - (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || - (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) + if (ath9k_uses_beacons(vif->type)) ath9k_reclaim_beacon(sc, vif); - sc->nvifs--; + ath9k_calculate_summary_state(hw, NULL); mutex_unlock(&sc->mutex); } @@ -1566,12 +1609,11 @@ static void ath9k_disable_ps(struct ath_softc *sc) static int ath9k_config(struct ieee80211_hw *hw, u32 changed) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &hw->conf; - bool disable_radio; + bool disable_radio = false; mutex_lock(&sc->mutex); @@ -1582,29 +1624,13 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) * the end. */ if (changed & IEEE80211_CONF_CHANGE_IDLE) { - bool enable_radio; - bool all_wiphys_idle; - bool idle = !!(conf->flags & IEEE80211_CONF_IDLE); - - spin_lock_bh(&sc->wiphy_lock); - all_wiphys_idle = ath9k_all_wiphys_idle(sc); - ath9k_set_wiphy_idle(aphy, idle); - - enable_radio = (!idle && all_wiphys_idle); - - /* - * After we unlock here its possible another wiphy - * can be re-renabled so to account for that we will - * only disable the radio toward the end of this routine - * if by then all wiphys are still idle. - */ - spin_unlock_bh(&sc->wiphy_lock); - - if (enable_radio) { - sc->ps_idle = false; + sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE); + if (!sc->ps_idle) { ath_radio_enable(sc, hw); ath_dbg(common, ATH_DBG_CONFIG, "not-idle: enabling radio\n"); + } else { + disable_radio = true; } } @@ -1645,29 +1671,16 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (ah->curchan) old_pos = ah->curchan - &ah->channels[0]; - aphy->chan_idx = pos; - aphy->chan_is_ht = conf_is_ht(conf); if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) sc->sc_flags |= SC_OP_OFFCHANNEL; else sc->sc_flags &= ~SC_OP_OFFCHANNEL; - if (aphy->state == ATH_WIPHY_SCAN || - aphy->state == ATH_WIPHY_ACTIVE) - ath9k_wiphy_pause_all_forced(sc, aphy); - else { - /* - * Do not change operational channel based on a paused - * wiphy changes. - */ - goto skip_chan_change; - } - ath_dbg(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n", curchan->center_freq); - /* XXX: remove me eventualy */ - ath9k_update_ichannel(sc, hw, &sc->sc_ah->channels[pos]); + ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos], + curchan, conf->channel_type); /* update survey stats for the old channel before switching */ spin_lock_irqsave(&common->cc_lock, flags); @@ -1709,21 +1722,16 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) ath_update_survey_nf(sc, old_pos); } -skip_chan_change: if (changed & IEEE80211_CONF_CHANGE_POWER) { sc->config.txpowlimit = 2 * conf->power_level; ath9k_ps_wakeup(sc); - ath_update_txpow(sc); + ath9k_cmn_update_txpow(ah, sc->curtxpow, + sc->config.txpowlimit, &sc->curtxpow); ath9k_ps_restore(sc); } - spin_lock_bh(&sc->wiphy_lock); - disable_radio = ath9k_all_wiphys_idle(sc); - spin_unlock_bh(&sc->wiphy_lock); - if (disable_radio) { ath_dbg(common, ATH_DBG_CONFIG, "idle: disabling radio\n"); - sc->ps_idle = true; ath_radio_disable(sc, hw); } @@ -1748,8 +1756,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, unsigned int *total_flags, u64 multicast) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; u32 rfilt; changed_flags &= SUPPORTED_FILTERS; @@ -1769,8 +1776,7 @@ static int ath9k_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; ath_node_attach(sc, sta); @@ -1781,8 +1787,7 @@ static int ath9k_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; ath_node_detach(sc, sta); @@ -1792,8 +1797,7 @@ static int ath9k_sta_remove(struct ieee80211_hw *hw, static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_txq *txq; struct ath9k_tx_queue_info qi; @@ -1837,8 +1841,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); int ret = 0; @@ -1882,8 +1885,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, u32 changed) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp = (void *)vif->drv_priv; @@ -1913,7 +1915,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, if ((changed & BSS_CHANGED_BEACON) || ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon)) { ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); - error = ath_beacon_alloc(aphy, vif); + error = ath_beacon_alloc(sc, vif); if (!error) ath_beacon_config(sc, vif); } @@ -1950,7 +1952,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, if (vif->type == NL80211_IFTYPE_AP) { sc->sc_flags |= SC_OP_TSF_RESET; ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); - error = ath_beacon_alloc(aphy, vif); + error = ath_beacon_alloc(sc, vif); if (!error) ath_beacon_config(sc, vif); } else { @@ -1988,9 +1990,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, static u64 ath9k_get_tsf(struct ieee80211_hw *hw) { + struct ath_softc *sc = hw->priv; u64 tsf; - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); @@ -2003,8 +2004,7 @@ static u64 ath9k_get_tsf(struct ieee80211_hw *hw) static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); @@ -2015,8 +2015,7 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf) static void ath9k_reset_tsf(struct ieee80211_hw *hw) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; mutex_lock(&sc->mutex); @@ -2031,10 +2030,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, - u16 tid, u16 *ssn) + u16 tid, u16 *ssn, u8 buf_size) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; int ret = 0; local_bh_disable(); @@ -2079,8 +2077,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; @@ -2114,47 +2111,9 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, return 0; } -static void ath9k_sw_scan_start(struct ieee80211_hw *hw) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - - mutex_lock(&sc->mutex); - if (ath9k_wiphy_scanning(sc)) { - /* - * There is a race here in mac80211 but fixing it requires - * we revisit how we handle the scan complete callback. - * After mac80211 fixes we will not have configured hardware - * to the home channel nor would we have configured the RX - * filter yet. - */ - mutex_unlock(&sc->mutex); - return; - } - - aphy->state = ATH_WIPHY_SCAN; - ath9k_wiphy_pause_all_forced(sc, aphy); - mutex_unlock(&sc->mutex); -} - -/* - * XXX: this requires a revisit after the driver - * scan_complete gets moved to another place/removed in mac80211. - */ -static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - - mutex_lock(&sc->mutex); - aphy->state = ATH_WIPHY_ACTIVE; - mutex_unlock(&sc->mutex); -} - static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; mutex_lock(&sc->mutex); @@ -2182,8 +2141,6 @@ struct ieee80211_ops ath9k_ops = { .reset_tsf = ath9k_reset_tsf, .ampdu_action = ath9k_ampdu_action, .get_survey = ath9k_get_survey, - .sw_scan_start = ath9k_sw_scan_start, - .sw_scan_complete = ath9k_sw_scan_complete, .rfkill_poll = ath9k_rfkill_poll_state, .set_coverage_class = ath9k_set_coverage_class, }; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 78ef1f13386f..e83128c50f7b 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -126,7 +126,6 @@ static const struct ath_bus_ops ath_pci_bus_ops = { static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { void __iomem *mem; - struct ath_wiphy *aphy; struct ath_softc *sc; struct ieee80211_hw *hw; u8 csz; @@ -198,8 +197,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_iomap; } - hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) + - sizeof(struct ath_softc), &ath9k_ops); + hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); if (!hw) { dev_err(&pdev->dev, "No memory for ieee80211_hw\n"); ret = -ENOMEM; @@ -209,11 +207,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) SET_IEEE80211_DEV(hw, &pdev->dev); pci_set_drvdata(pdev, hw); - aphy = hw->priv; - sc = (struct ath_softc *) (aphy + 1); - aphy->sc = sc; - aphy->hw = hw; - sc->pri_wiphy = aphy; + sc = hw->priv; sc->hw = hw; sc->dev = &pdev->dev; sc->mem = mem; @@ -260,8 +254,7 @@ err_dma: static void ath_pci_remove(struct pci_dev *pdev) { struct ieee80211_hw *hw = pci_get_drvdata(pdev); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; void __iomem *mem = sc->mem; if (!is_ath9k_unloaded) @@ -281,8 +274,7 @@ static int ath_pci_suspend(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct ieee80211_hw *hw = pci_get_drvdata(pdev); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); @@ -293,8 +285,7 @@ static int ath_pci_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct ieee80211_hw *hw = pci_get_drvdata(pdev); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; u32 val; /* @@ -320,7 +311,6 @@ static int ath_pci_resume(struct device *device) ath9k_ps_restore(sc); sc->ps_idle = true; - ath9k_set_wiphy_idle(aphy, true); ath_radio_disable(sc, hw); return 0; diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index e45147820eae..960d717ca7c2 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1560,8 +1560,7 @@ static void ath_rate_add_sta_debugfs(void *priv, void *priv_sta, static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) { - struct ath_wiphy *aphy = hw->priv; - return aphy->sc; + return hw->priv; } static void ath_rate_free(void *priv) diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index b2497b8601e5..daf171d2f610 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -34,27 +34,6 @@ static inline bool ath9k_check_auto_sleep(struct ath_softc *sc) (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP); } -static struct ieee80211_hw * ath_get_virt_hw(struct ath_softc *sc, - struct ieee80211_hdr *hdr) -{ - struct ieee80211_hw *hw = sc->pri_wiphy->hw; - int i; - - spin_lock_bh(&sc->wiphy_lock); - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - if (aphy == NULL) - continue; - if (compare_ether_addr(hdr->addr1, aphy->hw->wiphy->perm_addr) - == 0) { - hw = aphy->hw; - break; - } - } - spin_unlock_bh(&sc->wiphy_lock); - return hw; -} - /* * Setup and link descriptors. * @@ -230,11 +209,6 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs) int error = 0, i; u32 size; - - common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN + - ah->caps.rx_status_len, - min(common->cachelsz, (u16)64)); - ath9k_hw_set_rx_bufsize(ah, common->rx_bufsize - ah->caps.rx_status_len); @@ -321,12 +295,12 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) sc->sc_flags &= ~SC_OP_RXFLUSH; spin_lock_init(&sc->rx.rxbuflock); + common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 + + sc->sc_ah->caps.rx_status_len; + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { return ath_rx_edma_init(sc, nbufs); } else { - common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN, - min(common->cachelsz, (u16)64)); - ath_dbg(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", common->cachelsz, common->rx_bufsize); @@ -463,8 +437,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) if (conf_is_ht(&sc->hw->conf)) rfilt |= ATH9K_RX_FILTER_COMP_BAR; - if (sc->sec_wiphy || (sc->nvifs > 1) || - (sc->rx.rxfilter & FIF_OTHER_BSS)) { + if (sc->nvifs > 1 || (sc->rx.rxfilter & FIF_OTHER_BSS)) { /* The following may also be needed for other older chips */ if (sc->sc_ah->hw_version.macVersion == AR_SREV_VERSION_9160) rfilt |= ATH9K_RX_FILTER_PROM; @@ -588,8 +561,14 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) return; mgmt = (struct ieee80211_mgmt *)skb->data; - if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0) + if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0) { + /* TODO: This doesn't work well if you have stations + * associated to two different APs because curbssid + * is just the last AP that any of the stations associated + * with. + */ return; /* not from our current AP */ + } sc->ps_flags &= ~PS_WAIT_FOR_BEACON; @@ -662,37 +641,6 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) } } -static void ath_rx_send_to_mac80211(struct ieee80211_hw *hw, - struct ath_softc *sc, struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr; - - hdr = (struct ieee80211_hdr *)skb->data; - - /* Send the frame to mac80211 */ - if (is_multicast_ether_addr(hdr->addr1)) { - int i; - /* - * Deliver broadcast/multicast frames to all suitable - * virtual wiphys. - */ - /* TODO: filter based on channel configuration */ - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - struct sk_buff *nskb; - if (aphy == NULL) - continue; - nskb = skb_copy(skb, GFP_ATOMIC); - if (!nskb) - continue; - ieee80211_rx(aphy->hw, nskb); - } - ieee80211_rx(sc->hw, skb); - } else - /* Deliver unicast frames based on receiver address */ - ieee80211_rx(hw, skb); -} - static bool ath_edma_get_buffers(struct ath_softc *sc, enum ath9k_rx_qtype qtype) { @@ -862,15 +810,9 @@ static bool ath9k_rx_accept(struct ath_common *common, if (rx_stats->rs_datalen > (common->rx_bufsize - rx_status_len)) return false; - /* - * rs_more indicates chained descriptors which can be used - * to link buffers together for a sort of scatter-gather - * operation. - * reject the frame, we don't support scatter-gather yet and - * the frame is probably corrupt anyway - */ + /* Only use error bits from the last fragment */ if (rx_stats->rs_more) - return false; + return true; /* * The rx_stats->rs_status will not be set until the end of the @@ -974,7 +916,7 @@ static void ath9k_process_rssi(struct ath_common *common, struct ieee80211_hdr *hdr, struct ath_rx_status *rx_stats) { - struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = hw->priv; struct ath_hw *ah = common->ah; int last_rssi; __le16 fc; @@ -984,13 +926,19 @@ static void ath9k_process_rssi(struct ath_common *common, fc = hdr->frame_control; if (!ieee80211_is_beacon(fc) || - compare_ether_addr(hdr->addr3, common->curbssid)) + compare_ether_addr(hdr->addr3, common->curbssid)) { + /* TODO: This doesn't work well if you have stations + * associated to two different APs because curbssid + * is just the last AP that any of the stations associated + * with. + */ return; + } if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && !rx_stats->rs_moreaggr) - ATH_RSSI_LPF(aphy->last_rssi, rx_stats->rs_rssi); + ATH_RSSI_LPF(sc->last_rssi, rx_stats->rs_rssi); - last_rssi = aphy->last_rssi; + last_rssi = sc->last_rssi; if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) rx_stats->rs_rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); @@ -1022,6 +970,10 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common, if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) return -EINVAL; + /* Only use status info from the last fragment */ + if (rx_stats->rs_more) + return 0; + ath9k_process_rssi(common, hw, hdr, rx_stats); if (ath9k_process_rate(common, hw, rx_stats, rx_status)) @@ -1623,7 +1575,7 @@ div_comb_done: int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) { struct ath_buf *bf; - struct sk_buff *skb = NULL, *requeue_skb; + struct sk_buff *skb = NULL, *requeue_skb, *hdr_skb; struct ieee80211_rx_status *rxs; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); @@ -1632,7 +1584,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) * virtual wiphy so to account for that we iterate over the active * wiphys and find the appropriate wiphy and therefore hw. */ - struct ieee80211_hw *hw = NULL; + struct ieee80211_hw *hw = sc->hw; struct ieee80211_hdr *hdr; int retval; bool decrypt_error = false; @@ -1674,10 +1626,17 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) if (!skb) continue; - hdr = (struct ieee80211_hdr *) (skb->data + rx_status_len); - rxs = IEEE80211_SKB_RXCB(skb); + /* + * Take frame header from the first fragment and RX status from + * the last one. + */ + if (sc->rx.frag) + hdr_skb = sc->rx.frag; + else + hdr_skb = skb; - hw = ath_get_virt_hw(sc, hdr); + hdr = (struct ieee80211_hdr *) (hdr_skb->data + rx_status_len); + rxs = IEEE80211_SKB_RXCB(hdr_skb); ath_debug_stat_rx(sc, &rs); @@ -1686,12 +1645,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) * chain it back at the queue without processing it. */ if (flush) - goto requeue; + goto requeue_drop_frag; retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs, rxs, &decrypt_error); if (retval) - goto requeue; + goto requeue_drop_frag; rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp; if (rs.rs_tstamp > tsf_lower && @@ -1711,7 +1670,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) * skb and put it at the tail of the sc->rx.rxbuf list for * processing. */ if (!requeue_skb) - goto requeue; + goto requeue_drop_frag; /* Unmap the frame */ dma_unmap_single(sc->dev, bf->bf_buf_addr, @@ -1722,8 +1681,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) if (ah->caps.rx_status_len) skb_pull(skb, ah->caps.rx_status_len); - ath9k_rx_skb_postprocess(common, skb, &rs, - rxs, decrypt_error); + if (!rs.rs_more) + ath9k_rx_skb_postprocess(common, hdr_skb, &rs, + rxs, decrypt_error); /* We will now give hardware our shiny new allocated skb */ bf->bf_mpdu = requeue_skb; @@ -1736,10 +1696,42 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) bf->bf_mpdu = NULL; bf->bf_buf_addr = 0; ath_err(common, "dma_mapping_error() on RX\n"); - ath_rx_send_to_mac80211(hw, sc, skb); + ieee80211_rx(hw, skb); break; } + if (rs.rs_more) { + /* + * rs_more indicates chained descriptors which can be + * used to link buffers together for a sort of + * scatter-gather operation. + */ + if (sc->rx.frag) { + /* too many fragments - cannot handle frame */ + dev_kfree_skb_any(sc->rx.frag); + dev_kfree_skb_any(skb); + skb = NULL; + } + sc->rx.frag = skb; + goto requeue; + } + + if (sc->rx.frag) { + int space = skb->len - skb_tailroom(hdr_skb); + + sc->rx.frag = NULL; + + if (pskb_expand_head(hdr_skb, 0, space, GFP_ATOMIC) < 0) { + dev_kfree_skb(skb); + goto requeue_drop_frag; + } + + skb_copy_from_linear_data(skb, skb_put(hdr_skb, skb->len), + skb->len); + dev_kfree_skb_any(skb); + skb = hdr_skb; + } + /* * change the default rx antenna if rx diversity chooses the * other antenna 3 times in a row. @@ -1763,8 +1755,13 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) ath_ant_comb_scan(sc, &rs); - ath_rx_send_to_mac80211(hw, sc, skb); + ieee80211_rx(hw, skb); +requeue_drop_frag: + if (sc->rx.frag) { + dev_kfree_skb_any(sc->rx.frag); + sc->rx.frag = NULL; + } requeue: if (edma) { list_add_tail(&bf->list, &sc->rx.rxbuf); diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 4df5659c6c16..b262e98709de 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1083,6 +1083,17 @@ enum { #define AR_ENT_OTP 0x40d8 #define AR_ENT_OTP_CHAIN2_DISABLE 0x00020000 #define AR_ENT_OTP_MPSD 0x00800000 +#define AR_CH0_BB_DPLL2 0x16184 +#define AR_CH0_BB_DPLL3 0x16188 +#define AR_CH0_DDR_DPLL2 0x16244 +#define AR_CH0_DDR_DPLL3 0x16248 +#define AR_CH0_DPLL2_KD 0x03F80000 +#define AR_CH0_DPLL2_KD_S 19 +#define AR_CH0_DPLL2_KI 0x3C000000 +#define AR_CH0_DPLL2_KI_S 26 +#define AR_CH0_DPLL3_PHASE_SHIFT 0x3F800000 +#define AR_CH0_DPLL3_PHASE_SHIFT_S 23 +#define AR_PHY_CCA_NOM_VAL_2GHZ -118 #define AR_RTC_9300_PLL_DIV 0x000003ff #define AR_RTC_9300_PLL_DIV_S 0 @@ -1129,6 +1140,12 @@ enum { #define AR_RTC_PLL_CLKSEL 0x00000300 #define AR_RTC_PLL_CLKSEL_S 8 +#define PLL3 0x16188 +#define PLL3_DO_MEAS_MASK 0x40000000 +#define PLL4 0x1618c +#define PLL4_MEAS_DONE 0x8 +#define SQSUM_DVC_MASK 0x007ffff8 + #define AR_RTC_RESET \ ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0040) : 0x7040) #define AR_RTC_RESET_EN (0x00000001) diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c deleted file mode 100644 index 2dc7095e56d1..000000000000 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ /dev/null @@ -1,717 +0,0 @@ -/* - * Copyright (c) 2008-2009 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <linux/slab.h> - -#include "ath9k.h" - -struct ath9k_vif_iter_data { - const u8 *hw_macaddr; - u8 mask[ETH_ALEN]; -}; - -static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) -{ - struct ath9k_vif_iter_data *iter_data = data; - int i; - - for (i = 0; i < ETH_ALEN; i++) - iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]); -} - -void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath9k_vif_iter_data iter_data; - int i; - - /* - * Use the hardware MAC address as reference, the hardware uses it - * together with the BSSID mask when matching addresses. - */ - iter_data.hw_macaddr = common->macaddr; - memset(&iter_data.mask, 0xff, ETH_ALEN); - - if (vif) - ath9k_vif_iter(&iter_data, vif->addr, vif); - - /* Get list of all active MAC addresses */ - spin_lock_bh(&sc->wiphy_lock); - ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter, - &iter_data); - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] == NULL) - continue; - ieee80211_iterate_active_interfaces_atomic( - sc->sec_wiphy[i]->hw, ath9k_vif_iter, &iter_data); - } - spin_unlock_bh(&sc->wiphy_lock); - - memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); - ath_hw_setbssidmask(common); -} - -int ath9k_wiphy_add(struct ath_softc *sc) -{ - int i, error; - struct ath_wiphy *aphy; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ieee80211_hw *hw; - u8 addr[ETH_ALEN]; - - hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy), &ath9k_ops); - if (hw == NULL) - return -ENOMEM; - - spin_lock_bh(&sc->wiphy_lock); - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] == NULL) - break; - } - - if (i == sc->num_sec_wiphy) { - /* No empty slot available; increase array length */ - struct ath_wiphy **n; - n = krealloc(sc->sec_wiphy, - (sc->num_sec_wiphy + 1) * - sizeof(struct ath_wiphy *), - GFP_ATOMIC); - if (n == NULL) { - spin_unlock_bh(&sc->wiphy_lock); - ieee80211_free_hw(hw); - return -ENOMEM; - } - n[i] = NULL; - sc->sec_wiphy = n; - sc->num_sec_wiphy++; - } - - SET_IEEE80211_DEV(hw, sc->dev); - - aphy = hw->priv; - aphy->sc = sc; - aphy->hw = hw; - sc->sec_wiphy[i] = aphy; - aphy->last_rssi = ATH_RSSI_DUMMY_MARKER; - spin_unlock_bh(&sc->wiphy_lock); - - memcpy(addr, common->macaddr, ETH_ALEN); - addr[0] |= 0x02; /* Locally managed address */ - /* - * XOR virtual wiphy index into the least significant bits to generate - * a different MAC address for each virtual wiphy. - */ - addr[5] ^= i & 0xff; - addr[4] ^= (i & 0xff00) >> 8; - addr[3] ^= (i & 0xff0000) >> 16; - - SET_IEEE80211_PERM_ADDR(hw, addr); - - ath9k_set_hw_capab(sc, hw); - - error = ieee80211_register_hw(hw); - - if (error == 0) { - /* Make sure wiphy scheduler is started (if enabled) */ - ath9k_wiphy_set_scheduler(sc, sc->wiphy_scheduler_int); - } - - return error; -} - -int ath9k_wiphy_del(struct ath_wiphy *aphy) -{ - struct ath_softc *sc = aphy->sc; - int i; - - spin_lock_bh(&sc->wiphy_lock); - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (aphy == sc->sec_wiphy[i]) { - sc->sec_wiphy[i] = NULL; - spin_unlock_bh(&sc->wiphy_lock); - ieee80211_unregister_hw(aphy->hw); - ieee80211_free_hw(aphy->hw); - return 0; - } - } - spin_unlock_bh(&sc->wiphy_lock); - return -ENOENT; -} - -static int ath9k_send_nullfunc(struct ath_wiphy *aphy, - struct ieee80211_vif *vif, const u8 *bssid, - int ps) -{ - struct ath_softc *sc = aphy->sc; - struct ath_tx_control txctl; - struct sk_buff *skb; - struct ieee80211_hdr *hdr; - __le16 fc; - struct ieee80211_tx_info *info; - - skb = dev_alloc_skb(24); - if (skb == NULL) - return -ENOMEM; - hdr = (struct ieee80211_hdr *) skb_put(skb, 24); - memset(hdr, 0, 24); - fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | - IEEE80211_FCTL_TODS); - if (ps) - fc |= cpu_to_le16(IEEE80211_FCTL_PM); - hdr->frame_control = fc; - memcpy(hdr->addr1, bssid, ETH_ALEN); - memcpy(hdr->addr2, aphy->hw->wiphy->perm_addr, ETH_ALEN); - memcpy(hdr->addr3, bssid, ETH_ALEN); - - info = IEEE80211_SKB_CB(skb); - memset(info, 0, sizeof(*info)); - info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS; - info->control.vif = vif; - info->control.rates[0].idx = 0; - info->control.rates[0].count = 4; - info->control.rates[1].idx = -1; - - memset(&txctl, 0, sizeof(struct ath_tx_control)); - txctl.txq = sc->tx.txq_map[WME_AC_VO]; - txctl.frame_type = ps ? ATH9K_IFT_PAUSE : ATH9K_IFT_UNPAUSE; - - if (ath_tx_start(aphy->hw, skb, &txctl) != 0) - goto exit; - - return 0; -exit: - dev_kfree_skb_any(skb); - return -1; -} - -static bool __ath9k_wiphy_pausing(struct ath_softc *sc) -{ - int i; - if (sc->pri_wiphy->state == ATH_WIPHY_PAUSING) - return true; - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] && - sc->sec_wiphy[i]->state == ATH_WIPHY_PAUSING) - return true; - } - return false; -} - -static bool ath9k_wiphy_pausing(struct ath_softc *sc) -{ - bool ret; - spin_lock_bh(&sc->wiphy_lock); - ret = __ath9k_wiphy_pausing(sc); - spin_unlock_bh(&sc->wiphy_lock); - return ret; -} - -static bool __ath9k_wiphy_scanning(struct ath_softc *sc) -{ - int i; - if (sc->pri_wiphy->state == ATH_WIPHY_SCAN) - return true; - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] && - sc->sec_wiphy[i]->state == ATH_WIPHY_SCAN) - return true; - } - return false; -} - -bool ath9k_wiphy_scanning(struct ath_softc *sc) -{ - bool ret; - spin_lock_bh(&sc->wiphy_lock); - ret = __ath9k_wiphy_scanning(sc); - spin_unlock_bh(&sc->wiphy_lock); - return ret; -} - -static int __ath9k_wiphy_unpause(struct ath_wiphy *aphy); - -/* caller must hold wiphy_lock */ -static void __ath9k_wiphy_unpause_ch(struct ath_wiphy *aphy) -{ - if (aphy == NULL) - return; - if (aphy->chan_idx != aphy->sc->chan_idx) - return; /* wiphy not on the selected channel */ - __ath9k_wiphy_unpause(aphy); -} - -static void ath9k_wiphy_unpause_channel(struct ath_softc *sc) -{ - int i; - spin_lock_bh(&sc->wiphy_lock); - __ath9k_wiphy_unpause_ch(sc->pri_wiphy); - for (i = 0; i < sc->num_sec_wiphy; i++) - __ath9k_wiphy_unpause_ch(sc->sec_wiphy[i]); - spin_unlock_bh(&sc->wiphy_lock); -} - -void ath9k_wiphy_chan_work(struct work_struct *work) -{ - struct ath_softc *sc = container_of(work, struct ath_softc, chan_work); - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_wiphy *aphy = sc->next_wiphy; - - if (aphy == NULL) - return; - - /* - * All pending interfaces paused; ready to change - * channels. - */ - - /* Change channels */ - mutex_lock(&sc->mutex); - /* XXX: remove me eventually */ - ath9k_update_ichannel(sc, aphy->hw, - &sc->sc_ah->channels[sc->chan_idx]); - - /* sync hw configuration for hw code */ - common->hw = aphy->hw; - - if (ath_set_channel(sc, aphy->hw, - &sc->sc_ah->channels[sc->chan_idx]) < 0) { - printk(KERN_DEBUG "ath9k: Failed to set channel for new " - "virtual wiphy\n"); - mutex_unlock(&sc->mutex); - return; - } - mutex_unlock(&sc->mutex); - - ath9k_wiphy_unpause_channel(sc); -} - -/* - * ath9k version of ieee80211_tx_status() for TX frames that are generated - * internally in the driver. - */ -void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, int ftype) -{ - struct ath_wiphy *aphy = hw->priv; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - - if (ftype == ATH9K_IFT_PAUSE && aphy->state == ATH_WIPHY_PAUSING) { - if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) { - printk(KERN_DEBUG "ath9k: %s: no ACK for pause " - "frame\n", wiphy_name(hw->wiphy)); - /* - * The AP did not reply; ignore this to allow us to - * continue. - */ - } - aphy->state = ATH_WIPHY_PAUSED; - if (!ath9k_wiphy_pausing(aphy->sc)) { - /* - * Drop from tasklet to work to allow mutex for channel - * change. - */ - ieee80211_queue_work(aphy->sc->hw, - &aphy->sc->chan_work); - } - } - - dev_kfree_skb(skb); -} - -static void ath9k_mark_paused(struct ath_wiphy *aphy) -{ - struct ath_softc *sc = aphy->sc; - aphy->state = ATH_WIPHY_PAUSED; - if (!__ath9k_wiphy_pausing(sc)) - ieee80211_queue_work(sc->hw, &sc->chan_work); -} - -static void ath9k_pause_iter(void *data, u8 *mac, struct ieee80211_vif *vif) -{ - struct ath_wiphy *aphy = data; - struct ath_vif *avp = (void *) vif->drv_priv; - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - if (!vif->bss_conf.assoc) { - ath9k_mark_paused(aphy); - break; - } - /* TODO: could avoid this if already in PS mode */ - if (ath9k_send_nullfunc(aphy, vif, avp->bssid, 1)) { - printk(KERN_DEBUG "%s: failed to send PS nullfunc\n", - __func__); - ath9k_mark_paused(aphy); - } - break; - case NL80211_IFTYPE_AP: - /* Beacon transmission is paused by aphy->state change */ - ath9k_mark_paused(aphy); - break; - default: - break; - } -} - -/* caller must hold wiphy_lock */ -static int __ath9k_wiphy_pause(struct ath_wiphy *aphy) -{ - ieee80211_stop_queues(aphy->hw); - aphy->state = ATH_WIPHY_PAUSING; - /* - * TODO: handle PAUSING->PAUSED for the case where there are multiple - * active vifs (now we do it on the first vif getting ready; should be - * on the last) - */ - ieee80211_iterate_active_interfaces_atomic(aphy->hw, ath9k_pause_iter, - aphy); - return 0; -} - -int ath9k_wiphy_pause(struct ath_wiphy *aphy) -{ - int ret; - spin_lock_bh(&aphy->sc->wiphy_lock); - ret = __ath9k_wiphy_pause(aphy); - spin_unlock_bh(&aphy->sc->wiphy_lock); - return ret; -} - -static void ath9k_unpause_iter(void *data, u8 *mac, struct ieee80211_vif *vif) -{ - struct ath_wiphy *aphy = data; - struct ath_vif *avp = (void *) vif->drv_priv; - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - if (!vif->bss_conf.assoc) - break; - ath9k_send_nullfunc(aphy, vif, avp->bssid, 0); - break; - case NL80211_IFTYPE_AP: - /* Beacon transmission is re-enabled by aphy->state change */ - break; - default: - break; - } -} - -/* caller must hold wiphy_lock */ -static int __ath9k_wiphy_unpause(struct ath_wiphy *aphy) -{ - ieee80211_iterate_active_interfaces_atomic(aphy->hw, - ath9k_unpause_iter, aphy); - aphy->state = ATH_WIPHY_ACTIVE; - ieee80211_wake_queues(aphy->hw); - return 0; -} - -int ath9k_wiphy_unpause(struct ath_wiphy *aphy) -{ - int ret; - spin_lock_bh(&aphy->sc->wiphy_lock); - ret = __ath9k_wiphy_unpause(aphy); - spin_unlock_bh(&aphy->sc->wiphy_lock); - return ret; -} - -static void __ath9k_wiphy_mark_all_paused(struct ath_softc *sc) -{ - int i; - if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) - sc->pri_wiphy->state = ATH_WIPHY_PAUSED; - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] && - sc->sec_wiphy[i]->state != ATH_WIPHY_INACTIVE) - sc->sec_wiphy[i]->state = ATH_WIPHY_PAUSED; - } -} - -/* caller must hold wiphy_lock */ -static void __ath9k_wiphy_pause_all(struct ath_softc *sc) -{ - int i; - if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) - __ath9k_wiphy_pause(sc->pri_wiphy); - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] && - sc->sec_wiphy[i]->state == ATH_WIPHY_ACTIVE) - __ath9k_wiphy_pause(sc->sec_wiphy[i]); - } -} - -int ath9k_wiphy_select(struct ath_wiphy *aphy) -{ - struct ath_softc *sc = aphy->sc; - bool now; - - spin_lock_bh(&sc->wiphy_lock); - if (__ath9k_wiphy_scanning(sc)) { - /* - * For now, we are using mac80211 sw scan and it expects to - * have full control over channel changes, so avoid wiphy - * scheduling during a scan. This could be optimized if the - * scanning control were moved into the driver. - */ - spin_unlock_bh(&sc->wiphy_lock); - return -EBUSY; - } - if (__ath9k_wiphy_pausing(sc)) { - if (sc->wiphy_select_failures == 0) - sc->wiphy_select_first_fail = jiffies; - sc->wiphy_select_failures++; - if (time_after(jiffies, sc->wiphy_select_first_fail + HZ / 2)) - { - printk(KERN_DEBUG "ath9k: Previous wiphy select timed " - "out; disable/enable hw to recover\n"); - __ath9k_wiphy_mark_all_paused(sc); - /* - * TODO: this workaround to fix hardware is unlikely to - * be specific to virtual wiphy changes. It can happen - * on normal channel change, too, and as such, this - * should really be made more generic. For example, - * tricker radio disable/enable on GTT interrupt burst - * (say, 10 GTT interrupts received without any TX - * frame being completed) - */ - spin_unlock_bh(&sc->wiphy_lock); - ath_radio_disable(sc, aphy->hw); - ath_radio_enable(sc, aphy->hw); - /* Only the primary wiphy hw is used for queuing work */ - ieee80211_queue_work(aphy->sc->hw, - &aphy->sc->chan_work); - return -EBUSY; /* previous select still in progress */ - } - spin_unlock_bh(&sc->wiphy_lock); - return -EBUSY; /* previous select still in progress */ - } - sc->wiphy_select_failures = 0; - - /* Store the new channel */ - sc->chan_idx = aphy->chan_idx; - sc->chan_is_ht = aphy->chan_is_ht; - sc->next_wiphy = aphy; - - __ath9k_wiphy_pause_all(sc); - now = !__ath9k_wiphy_pausing(aphy->sc); - spin_unlock_bh(&sc->wiphy_lock); - - if (now) { - /* Ready to request channel change immediately */ - ieee80211_queue_work(aphy->sc->hw, &aphy->sc->chan_work); - } - - /* - * wiphys will be unpaused in ath9k_tx_status() once channel has been - * changed if any wiphy needs time to become paused. - */ - - return 0; -} - -bool ath9k_wiphy_started(struct ath_softc *sc) -{ - int i; - spin_lock_bh(&sc->wiphy_lock); - if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) { - spin_unlock_bh(&sc->wiphy_lock); - return true; - } - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] && - sc->sec_wiphy[i]->state != ATH_WIPHY_INACTIVE) { - spin_unlock_bh(&sc->wiphy_lock); - return true; - } - } - spin_unlock_bh(&sc->wiphy_lock); - return false; -} - -static void ath9k_wiphy_pause_chan(struct ath_wiphy *aphy, - struct ath_wiphy *selected) -{ - if (selected->state == ATH_WIPHY_SCAN) { - if (aphy == selected) - return; - /* - * Pause all other wiphys for the duration of the scan even if - * they are on the current channel now. - */ - } else if (aphy->chan_idx == selected->chan_idx) - return; - aphy->state = ATH_WIPHY_PAUSED; - ieee80211_stop_queues(aphy->hw); -} - -void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, - struct ath_wiphy *selected) -{ - int i; - spin_lock_bh(&sc->wiphy_lock); - if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) - ath9k_wiphy_pause_chan(sc->pri_wiphy, selected); - for (i = 0; i < sc->num_sec_wiphy; i++) { - if (sc->sec_wiphy[i] && - sc->sec_wiphy[i]->state == ATH_WIPHY_ACTIVE) - ath9k_wiphy_pause_chan(sc->sec_wiphy[i], selected); - } - spin_unlock_bh(&sc->wiphy_lock); -} - -void ath9k_wiphy_work(struct work_struct *work) -{ - struct ath_softc *sc = container_of(work, struct ath_softc, - wiphy_work.work); - struct ath_wiphy *aphy = NULL; - bool first = true; - - spin_lock_bh(&sc->wiphy_lock); - - if (sc->wiphy_scheduler_int == 0) { - /* wiphy scheduler is disabled */ - spin_unlock_bh(&sc->wiphy_lock); - return; - } - -try_again: - sc->wiphy_scheduler_index++; - while (sc->wiphy_scheduler_index <= sc->num_sec_wiphy) { - aphy = sc->sec_wiphy[sc->wiphy_scheduler_index - 1]; - if (aphy && aphy->state != ATH_WIPHY_INACTIVE) - break; - - sc->wiphy_scheduler_index++; - aphy = NULL; - } - if (aphy == NULL) { - sc->wiphy_scheduler_index = 0; - if (sc->pri_wiphy->state == ATH_WIPHY_INACTIVE) { - if (first) { - first = false; - goto try_again; - } - /* No wiphy is ready to be scheduled */ - } else - aphy = sc->pri_wiphy; - } - - spin_unlock_bh(&sc->wiphy_lock); - - if (aphy && - aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN && - ath9k_wiphy_select(aphy)) { - printk(KERN_DEBUG "ath9k: Failed to schedule virtual wiphy " - "change\n"); - } - - ieee80211_queue_delayed_work(sc->hw, - &sc->wiphy_work, - sc->wiphy_scheduler_int); -} - -void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int) -{ - cancel_delayed_work_sync(&sc->wiphy_work); - sc->wiphy_scheduler_int = msecs_to_jiffies(msec_int); - if (sc->wiphy_scheduler_int) - ieee80211_queue_delayed_work(sc->hw, &sc->wiphy_work, - sc->wiphy_scheduler_int); -} - -/* caller must hold wiphy_lock */ -bool ath9k_all_wiphys_idle(struct ath_softc *sc) -{ - unsigned int i; - if (!sc->pri_wiphy->idle) - return false; - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - if (!aphy) - continue; - if (!aphy->idle) - return false; - } - return true; -} - -/* caller must hold wiphy_lock */ -void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle) -{ - struct ath_softc *sc = aphy->sc; - - aphy->idle = idle; - ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG, - "Marking %s as %sidle\n", - wiphy_name(aphy->hw->wiphy), idle ? "" : "not-"); -} -/* Only bother starting a queue on an active virtual wiphy */ -bool ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue) -{ - struct ieee80211_hw *hw = sc->pri_wiphy->hw; - unsigned int i; - bool txq_started = false; - - spin_lock_bh(&sc->wiphy_lock); - - /* Start the primary wiphy */ - if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) { - ieee80211_wake_queue(hw, skb_queue); - txq_started = true; - goto unlock; - } - - /* Now start the secondary wiphy queues */ - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - if (!aphy) - continue; - if (aphy->state != ATH_WIPHY_ACTIVE) - continue; - - hw = aphy->hw; - ieee80211_wake_queue(hw, skb_queue); - txq_started = true; - break; - } - -unlock: - spin_unlock_bh(&sc->wiphy_lock); - return txq_started; -} - -/* Go ahead and propagate information to all virtual wiphys, it won't hurt */ -void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue) -{ - struct ieee80211_hw *hw = sc->pri_wiphy->hw; - unsigned int i; - - spin_lock_bh(&sc->wiphy_lock); - - /* Stop the primary wiphy */ - ieee80211_stop_queue(hw, skb_queue); - - /* Now stop the secondary wiphy queues */ - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - if (!aphy) - continue; - hw = aphy->hw; - ieee80211_stop_queue(hw, skb_queue); - } - spin_unlock_bh(&sc->wiphy_lock); -} diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 07b7804aec5b..9f4e755d27ce 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -19,7 +19,6 @@ #define BITS_PER_BYTE 8 #define OFDM_PLCP_BITS 22 -#define HT_RC_2_MCS(_rc) ((_rc) & 0x1f) #define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) #define L_STF 8 #define L_LTF 8 @@ -32,7 +31,6 @@ #define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2) #define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18) -#define OFDM_SIFS_TIME 16 static u16 bits_per_symbol[][2] = { /* 20MHz 40MHz */ @@ -57,8 +55,9 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, struct list_head *head); static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len); -static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, - int nframes, int nbad, int txok, bool update_rc); +static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, + struct ath_tx_status *ts, int nframes, int nbad, + int txok, bool update_rc); static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, int seqno); @@ -169,7 +168,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) ath_tx_update_baw(sc, tid, fi->seqno); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); } else { - ath_tx_send_normal(sc, txq, tid, &bf_head); + ath_tx_send_normal(sc, txq, NULL, &bf_head); } spin_lock_bh(&txq->axq_lock); } @@ -297,7 +296,6 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) ATH_TXBUF_RESET(tbf); - tbf->aphy = bf->aphy; tbf->bf_mpdu = bf->bf_mpdu; tbf->bf_buf_addr = bf->bf_buf_addr; memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len); @@ -345,7 +343,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_node *an = NULL; struct sk_buff *skb; struct ieee80211_sta *sta; - struct ieee80211_hw *hw; + struct ieee80211_hw *hw = sc->hw; struct ieee80211_hdr *hdr; struct ieee80211_tx_info *tx_info; struct ath_atx_tid *tid = NULL; @@ -364,7 +362,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, hdr = (struct ieee80211_hdr *)skb->data; tx_info = IEEE80211_SKB_CB(skb); - hw = bf->aphy->hw; memcpy(rates, tx_info->control.rates, sizeof(rates)); @@ -383,7 +380,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, !bf->bf_stale || bf_next != NULL) list_move_tail(&bf->list, &bf_head); - ath_tx_rc_status(bf, ts, 1, 1, 0, false); + ath_tx_rc_status(sc, bf, ts, 1, 1, 0, false); ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, 0, 0); @@ -429,7 +426,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad); while (bf) { - txfail = txpending = 0; + txfail = txpending = sendbar = 0; bf_next = bf->bf_next; skb = bf->bf_mpdu; @@ -489,10 +486,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { memcpy(tx_info->control.rates, rates, sizeof(rates)); - ath_tx_rc_status(bf, ts, nframes, nbad, txok, true); + ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok, true); rc_update = false; } else { - ath_tx_rc_status(bf, ts, nframes, nbad, txok, false); + ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok, false); } ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, @@ -516,7 +513,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, bf->bf_state.bf_type |= BUF_XRETRY; - ath_tx_rc_status(bf, ts, nframes, + ath_tx_rc_status(sc, bf, ts, nframes, nbad, 0, false); ath_tx_complete_buf(sc, bf, txq, &bf_head, @@ -566,8 +563,11 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, rcu_read_unlock(); - if (needreset) + if (needreset) { + spin_unlock_bh(&sc->sc_pcu_lock); ath_reset(sc, false); + spin_lock_bh(&sc->sc_pcu_lock); + } } static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, @@ -856,7 +856,10 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, txtid->state |= AGGR_ADDBA_PROGRESS; txtid->paused = true; - *ssn = txtid->seq_start; + *ssn = txtid->seq_start = txtid->seq_next; + + memset(txtid->tx_buf, 0, sizeof(txtid->tx_buf)); + txtid->baw_head = txtid->baw_tail = 0; return 0; } @@ -942,7 +945,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) [WME_AC_VI] = ATH_TXQ_AC_VI, [WME_AC_VO] = ATH_TXQ_AC_VO, }; - int qnum, i; + int axq_qnum, i; memset(&qi, 0, sizeof(qi)); qi.tqi_subtype = subtype_txq_to_hwq[subtype]; @@ -976,24 +979,25 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | TXQ_FLAG_TXDESCINT_ENABLE; } - qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi); - if (qnum == -1) { + axq_qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi); + if (axq_qnum == -1) { /* * NB: don't print a message, this happens * normally on parts with too few tx queues */ return NULL; } - if (qnum >= ARRAY_SIZE(sc->tx.txq)) { + if (axq_qnum >= ARRAY_SIZE(sc->tx.txq)) { ath_err(common, "qnum %u out of range, max %zu!\n", - qnum, ARRAY_SIZE(sc->tx.txq)); - ath9k_hw_releasetxqueue(ah, qnum); + axq_qnum, ARRAY_SIZE(sc->tx.txq)); + ath9k_hw_releasetxqueue(ah, axq_qnum); return NULL; } - if (!ATH_TXQ_SETUP(sc, qnum)) { - struct ath_txq *txq = &sc->tx.txq[qnum]; + if (!ATH_TXQ_SETUP(sc, axq_qnum)) { + struct ath_txq *txq = &sc->tx.txq[axq_qnum]; - txq->axq_qnum = qnum; + txq->axq_qnum = axq_qnum; + txq->mac80211_qnum = -1; txq->axq_link = NULL; INIT_LIST_HEAD(&txq->axq_q); INIT_LIST_HEAD(&txq->axq_acq); @@ -1001,14 +1005,14 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) txq->axq_depth = 0; txq->axq_ampdu_depth = 0; txq->axq_tx_inprogress = false; - sc->tx.txqsetup |= 1<<qnum; + sc->tx.txqsetup |= 1<<axq_qnum; txq->txq_headidx = txq->txq_tailidx = 0; for (i = 0; i < ATH_TXFIFO_DEPTH; i++) INIT_LIST_HEAD(&txq->txq_fifo[i]); INIT_LIST_HEAD(&txq->txq_fifo_pending); } - return &sc->tx.txq[qnum]; + return &sc->tx.txq[axq_qnum]; } int ath_txq_update(struct ath_softc *sc, int qnum, @@ -1205,8 +1209,17 @@ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) ath_err(common, "Failed to stop TX DMA!\n"); for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (ATH_TXQ_SETUP(sc, i)) - ath_draintxq(sc, &sc->tx.txq[i], retry_tx); + if (!ATH_TXQ_SETUP(sc, i)) + continue; + + /* + * The caller will resume queues with ieee80211_wake_queues. + * Mark the queue as not stopped to prevent ath_tx_complete + * from waking the queue too early. + */ + txq = &sc->tx.txq[i]; + txq->stopped = false; + ath_draintxq(sc, txq, retry_tx); } return !npend; @@ -1218,46 +1231,59 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) sc->tx.txqsetup &= ~(1<<txq->axq_qnum); } +/* For each axq_acq entry, for each tid, try to schedule packets + * for transmit until ampdu_depth has reached min Q depth. + */ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) { - struct ath_atx_ac *ac; - struct ath_atx_tid *tid; + struct ath_atx_ac *ac, *ac_tmp, *last_ac; + struct ath_atx_tid *tid, *last_tid; - if (list_empty(&txq->axq_acq)) + if (list_empty(&txq->axq_acq) || + txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) return; ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list); - list_del(&ac->list); - ac->sched = false; + last_ac = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list); - do { - if (list_empty(&ac->tid_q)) - return; + list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) { + last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list); + list_del(&ac->list); + ac->sched = false; - tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list); - list_del(&tid->list); - tid->sched = false; + while (!list_empty(&ac->tid_q)) { + tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, + list); + list_del(&tid->list); + tid->sched = false; - if (tid->paused) - continue; + if (tid->paused) + continue; - ath_tx_sched_aggr(sc, txq, tid); + ath_tx_sched_aggr(sc, txq, tid); - /* - * add tid to round-robin queue if more frames - * are pending for the tid - */ - if (!list_empty(&tid->buf_q)) - ath_tx_queue_tid(txq, tid); + /* + * add tid to round-robin queue if more frames + * are pending for the tid + */ + if (!list_empty(&tid->buf_q)) + ath_tx_queue_tid(txq, tid); - break; - } while (!list_empty(&ac->tid_q)); + if (tid == last_tid || + txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) + break; + } - if (!list_empty(&ac->tid_q)) { - if (!ac->sched) { - ac->sched = true; - list_add_tail(&ac->list, &txq->axq_acq); + if (!list_empty(&ac->tid_q)) { + if (!ac->sched) { + ac->sched = true; + list_add_tail(&ac->list, &txq->axq_acq); + } } + + if (ac == last_ac || + txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) + return; } } @@ -1301,6 +1327,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]); list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]); INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH); + TX_STAT_INC(txq->axq_qnum, puttxbuf); ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n", txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); @@ -1308,6 +1335,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, list_splice_tail_init(head, &txq->axq_q); if (txq->axq_link == NULL) { + TX_STAT_INC(txq->axq_qnum, puttxbuf); ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n", txq->axq_qnum, ito64(bf->bf_daddr), @@ -1321,6 +1349,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, } ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc, &txq->axq_link); + TX_STAT_INC(txq->axq_qnum, txstart); ath9k_hw_txstart(ah, txq->axq_qnum); } txq->axq_depth++; @@ -1335,7 +1364,6 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, struct list_head bf_head; bf->bf_state.bf_type |= BUF_AMPDU; - TX_STAT_INC(txctl->txq->axq_qnum, a_queued); /* * Do not queue to h/w when any of the following conditions is true: @@ -1351,6 +1379,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, * Add this frame to software queue for scheduling later * for aggregation. */ + TX_STAT_INC(txctl->txq->axq_qnum, a_queued_sw); list_add_tail(&bf->list, &tid->buf_q); ath_tx_queue_tid(txctl->txq, tid); return; @@ -1364,6 +1393,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, ath_tx_addto_baw(sc, tid, fi->seqno); /* Queue to h/w without aggregation */ + TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw); bf->bf_lastbf = bf; ath_buf_set_rate(sc, bf, fi->framelen); ath_tx_txqaddbuf(sc, txctl->txq, &bf_head); @@ -1416,8 +1446,7 @@ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb, int framelen) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_sta *sta = tx_info->control.sta; struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; @@ -1635,8 +1664,7 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_txq *txq, struct sk_buff *skb) { - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_frame_info *fi = get_frame_info(skb); @@ -1652,7 +1680,6 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, ATH_TXBUF_RESET(bf); - bf->aphy = aphy; bf->bf_flags = setup_tx_flags(skb); bf->bf_mpdu = skb; @@ -1741,8 +1768,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_sta *sta = info->control.sta; - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; + struct ath_softc *sc = hw->priv; struct ath_txq *txq = txctl->txq; struct ath_buf *bf; int padpos, padsize; @@ -1794,7 +1820,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, spin_lock_bh(&txq->axq_lock); if (txq == sc->tx.txq_map[q] && ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) { - ath_mac80211_stop_queue(sc, q); + ieee80211_stop_queue(sc->hw, q); txq->stopped = 1; } spin_unlock_bh(&txq->axq_lock); @@ -1809,8 +1835,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, /*****************/ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, - struct ath_wiphy *aphy, int tx_flags, int ftype, - struct ath_txq *txq) + int tx_flags, int ftype, struct ath_txq *txq) { struct ieee80211_hw *hw = sc->hw; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); @@ -1820,9 +1845,6 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, ath_dbg(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); - if (aphy) - hw = aphy->hw; - if (tx_flags & ATH_TX_BAR) tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; @@ -1852,19 +1874,20 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, PS_WAIT_FOR_TX_ACK)); } - if (unlikely(ftype)) - ath9k_tx_status(hw, skb, ftype); - else { - q = skb_get_queue_mapping(skb); - if (txq == sc->tx.txq_map[q]) { - spin_lock_bh(&txq->axq_lock); - if (WARN_ON(--txq->pending_frames < 0)) - txq->pending_frames = 0; - spin_unlock_bh(&txq->axq_lock); - } + q = skb_get_queue_mapping(skb); + if (txq == sc->tx.txq_map[q]) { + spin_lock_bh(&txq->axq_lock); + if (WARN_ON(--txq->pending_frames < 0)) + txq->pending_frames = 0; - ieee80211_tx_status(hw, skb); + if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) { + ieee80211_wake_queue(sc->hw, q); + txq->stopped = 0; + } + spin_unlock_bh(&txq->axq_lock); } + + ieee80211_tx_status(hw, skb); } static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, @@ -1896,8 +1919,8 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, else complete(&sc->paprd_complete); } else { - ath_debug_stat_tx(sc, bf, ts); - ath_tx_complete(sc, skb, bf->aphy, tx_flags, + ath_debug_stat_tx(sc, bf, ts, txq); + ath_tx_complete(sc, skb, tx_flags, bf->bf_state.bfs_ftype, txq); } /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't @@ -1913,14 +1936,14 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, spin_unlock_irqrestore(&sc->tx.txbuflock, flags); } -static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, - int nframes, int nbad, int txok, bool update_rc) +static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, + struct ath_tx_status *ts, int nframes, int nbad, + int txok, bool update_rc) { struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_hw *hw = bf->aphy->hw; - struct ath_softc *sc = bf->aphy->sc; + struct ieee80211_hw *hw = sc->hw; struct ath_hw *ah = sc->sc_ah; u8 i, tx_rateindex; @@ -1971,19 +1994,6 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1; } -static void ath_wake_mac80211_queue(struct ath_softc *sc, int qnum) -{ - struct ath_txq *txq; - - txq = sc->tx.txq_map[qnum]; - spin_lock_bh(&txq->axq_lock); - if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) { - if (ath_mac80211_start_queue(sc, qnum)) - txq->stopped = 0; - } - spin_unlock_bh(&txq->axq_lock); -} - static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) { struct ath_hw *ah = sc->sc_ah; @@ -1994,7 +2004,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) struct ath_tx_status ts; int txok; int status; - int qnum; ath_dbg(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n", txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum), @@ -2004,6 +2013,8 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) spin_lock_bh(&txq->axq_lock); if (list_empty(&txq->axq_q)) { txq->axq_link = NULL; + if (sc->sc_flags & SC_OP_TXAGGR) + ath_txq_schedule(sc, txq); spin_unlock_bh(&txq->axq_lock); break; } @@ -2038,6 +2049,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) spin_unlock_bh(&txq->axq_lock); break; } + TX_STAT_INC(txq->axq_qnum, txprocdesc); /* * Remove ath_buf's of the same transmit unit from txq, @@ -2070,27 +2082,45 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) */ if (ts.ts_status & ATH9K_TXERR_XRETRY) bf->bf_state.bf_type |= BUF_XRETRY; - ath_tx_rc_status(bf, &ts, 1, txok ? 0 : 1, txok, true); + ath_tx_rc_status(sc, bf, &ts, 1, txok ? 0 : 1, txok, true); } - qnum = skb_get_queue_mapping(bf->bf_mpdu); - if (bf_isampdu(bf)) ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok, true); else ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0); - if (txq == sc->tx.txq_map[qnum]) - ath_wake_mac80211_queue(sc, qnum); - spin_lock_bh(&txq->axq_lock); + if (sc->sc_flags & SC_OP_TXAGGR) ath_txq_schedule(sc, txq); spin_unlock_bh(&txq->axq_lock); } } +static void ath_hw_pll_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + hw_pll_work.work); + static int count; + + if (AR_SREV_9485(sc->sc_ah)) { + if (ar9003_get_pll_sqsum_dvc(sc->sc_ah) >= 0x40000) { + count++; + + if (count == 3) { + /* Rx is hung for more than 500ms. Reset it */ + ath_reset(sc, true); + count = 0; + } + } else + count = 0; + + ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); + } +} + static void ath_tx_complete_poll_work(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, @@ -2098,6 +2128,9 @@ static void ath_tx_complete_poll_work(struct work_struct *work) struct ath_txq *txq; int i; bool needreset = false; +#ifdef CONFIG_ATH9K_DEBUGFS + sc->tx_complete_poll_work_seen++; +#endif for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) if (ATH_TXQ_SETUP(sc, i)) { @@ -2111,6 +2144,33 @@ static void ath_tx_complete_poll_work(struct work_struct *work) } else { txq->axq_tx_inprogress = true; } + } else { + /* If the queue has pending buffers, then it + * should be doing tx work (and have axq_depth). + * Shouldn't get to this state I think..but + * we do. + */ + if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && + (txq->pending_frames > 0 || + !list_empty(&txq->axq_acq) || + txq->stopped)) { + ath_err(ath9k_hw_common(sc->sc_ah), + "txq: %p axq_qnum: %u," + " mac80211_qnum: %i" + " axq_link: %p" + " pending frames: %i" + " axq_acq empty: %i" + " stopped: %i" + " axq_depth: 0 Attempting to" + " restart tx logic.\n", + txq, txq->axq_qnum, + txq->mac80211_qnum, + txq->axq_link, + txq->pending_frames, + list_empty(&txq->axq_acq), + txq->stopped); + ath_txq_schedule(sc, txq); + } } spin_unlock_bh(&txq->axq_lock); } @@ -2150,7 +2210,6 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) struct list_head bf_head; int status; int txok; - int qnum; for (;;) { status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs); @@ -2193,11 +2252,9 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) if (!bf_isampdu(bf)) { if (txs.ts_status & ATH9K_TXERR_XRETRY) bf->bf_state.bf_type |= BUF_XRETRY; - ath_tx_rc_status(bf, &txs, 1, txok ? 0 : 1, txok, true); + ath_tx_rc_status(sc, bf, &txs, 1, txok ? 0 : 1, txok, true); } - qnum = skb_get_queue_mapping(bf->bf_mpdu); - if (bf_isampdu(bf)) ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok, true); @@ -2205,10 +2262,8 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) ath_tx_complete_buf(sc, bf, txq, &bf_head, &txs, txok, 0); - if (txq == sc->tx.txq_map[qnum]) - ath_wake_mac80211_queue(sc, qnum); - spin_lock_bh(&txq->axq_lock); + if (!list_empty(&txq->txq_fifo_pending)) { INIT_LIST_HEAD(&bf_head); bf = list_first_entry(&txq->txq_fifo_pending, @@ -2285,6 +2340,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) } INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work); + INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { error = ath_tx_edma_init(sc); diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index d07ff7f2fd92..420d437f9580 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -283,6 +283,7 @@ struct ar9170 { unsigned int mem_blocks; unsigned int mem_block_size; unsigned int rx_size; + unsigned int tx_seq_table; } fw; /* reset / stuck frames/queue detection */ diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c index 546b4e4ec5ea..9517ede9e2df 100644 --- a/drivers/net/wireless/ath/carl9170/fw.c +++ b/drivers/net/wireless/ath/carl9170/fw.c @@ -150,6 +150,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) const struct carl9170fw_otus_desc *otus_desc; const struct carl9170fw_chk_desc *chk_desc; const struct carl9170fw_last_desc *last_desc; + const struct carl9170fw_txsq_desc *txsq_desc; last_desc = carl9170_fw_find_desc(ar, LAST_MAGIC, sizeof(*last_desc), CARL9170FW_LAST_DESC_CUR_VER); @@ -264,6 +265,9 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) FIF_PROMISC_IN_BSS; } + if (SUPP(CARL9170FW_WOL)) + device_set_wakeup_enable(&ar->udev->dev, true); + ar->fw.vif_num = otus_desc->vif_num; ar->fw.cmd_bufs = otus_desc->cmd_bufs; ar->fw.address = le32_to_cpu(otus_desc->fw_address); @@ -296,6 +300,17 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) } } + txsq_desc = carl9170_fw_find_desc(ar, TXSQ_MAGIC, + sizeof(*txsq_desc), CARL9170FW_TXSQ_DESC_CUR_VER); + + if (txsq_desc) { + ar->fw.tx_seq_table = le32_to_cpu(txsq_desc->seq_table_addr); + if (!valid_cpu_addr(ar->fw.tx_seq_table)) + return -EINVAL; + } else { + ar->fw.tx_seq_table = 0; + } + #undef SUPPORTED return 0; } diff --git a/drivers/net/wireless/ath/carl9170/fwcmd.h b/drivers/net/wireless/ath/carl9170/fwcmd.h index 3680dfc70f46..30449d21b762 100644 --- a/drivers/net/wireless/ath/carl9170/fwcmd.h +++ b/drivers/net/wireless/ath/carl9170/fwcmd.h @@ -167,6 +167,7 @@ struct carl9170_rx_filter_cmd { #define CARL9170_RX_FILTER_CTL_BACKR 0x20 #define CARL9170_RX_FILTER_MGMT 0x40 #define CARL9170_RX_FILTER_DATA 0x80 +#define CARL9170_RX_FILTER_EVERYTHING (~0) struct carl9170_bcn_ctrl_cmd { __le32 vif_id; diff --git a/drivers/net/wireless/ath/carl9170/fwdesc.h b/drivers/net/wireless/ath/carl9170/fwdesc.h index 71f3821f6058..921066822dd5 100644 --- a/drivers/net/wireless/ath/carl9170/fwdesc.h +++ b/drivers/net/wireless/ath/carl9170/fwdesc.h @@ -69,6 +69,9 @@ enum carl9170fw_feature_list { /* Firmware RX filter | CARL9170_CMD_RX_FILTER */ CARL9170FW_RX_FILTER, + /* Wake up on WLAN */ + CARL9170FW_WOL, + /* KEEP LAST */ __CARL9170FW_FEATURE_NUM }; @@ -78,6 +81,7 @@ enum carl9170fw_feature_list { #define FIX_MAGIC "FIX\0" #define DBG_MAGIC "DBG\0" #define CHK_MAGIC "CHK\0" +#define TXSQ_MAGIC "TXSQ" #define LAST_MAGIC "LAST" #define CARL9170FW_SET_DAY(d) (((d) - 1) % 31) @@ -88,8 +92,10 @@ enum carl9170fw_feature_list { #define CARL9170FW_GET_MONTH(m) ((((m) / 31) % 12) + 1) #define CARL9170FW_GET_YEAR(y) ((y) / 372 + 10) +#define CARL9170FW_MAGIC_SIZE 4 + struct carl9170fw_desc_head { - u8 magic[4]; + u8 magic[CARL9170FW_MAGIC_SIZE]; __le16 length; u8 min_ver; u8 cur_ver; @@ -170,6 +176,16 @@ struct carl9170fw_chk_desc { #define CARL9170FW_CHK_DESC_SIZE \ (sizeof(struct carl9170fw_chk_desc)) +#define CARL9170FW_TXSQ_DESC_MIN_VER 1 +#define CARL9170FW_TXSQ_DESC_CUR_VER 1 +struct carl9170fw_txsq_desc { + struct carl9170fw_desc_head head; + + __le32 seq_table_addr; +} __packed; +#define CARL9170FW_TXSQ_DESC_SIZE \ + (sizeof(struct carl9170fw_txsq_desc)) + #define CARL9170FW_LAST_DESC_MIN_VER 1 #define CARL9170FW_LAST_DESC_CUR_VER 2 struct carl9170fw_last_desc { @@ -189,8 +205,8 @@ struct carl9170fw_last_desc { } static inline void carl9170fw_fill_desc(struct carl9170fw_desc_head *head, - u8 magic[4], __le16 length, - u8 min_ver, u8 cur_ver) + u8 magic[CARL9170FW_MAGIC_SIZE], + __le16 length, u8 min_ver, u8 cur_ver) { head->magic[0] = magic[0]; head->magic[1] = magic[1]; @@ -204,7 +220,7 @@ static inline void carl9170fw_fill_desc(struct carl9170fw_desc_head *head, #define carl9170fw_for_each_hdr(desc, fw_desc) \ for (desc = fw_desc; \ - memcmp(desc->magic, LAST_MAGIC, 4) && \ + memcmp(desc->magic, LAST_MAGIC, CARL9170FW_MAGIC_SIZE) && \ le16_to_cpu(desc->length) >= CARL9170FW_DESC_HEAD_SIZE && \ le16_to_cpu(desc->length) < CARL9170FW_DESC_MAX_LENGTH; \ desc = (void *)((unsigned long)desc + le16_to_cpu(desc->length))) @@ -218,8 +234,8 @@ static inline bool carl9170fw_supports(__le32 list, u8 feature) } static inline bool carl9170fw_desc_cmp(const struct carl9170fw_desc_head *head, - const u8 descid[4], u16 min_len, - u8 compatible_revision) + const u8 descid[CARL9170FW_MAGIC_SIZE], + u16 min_len, u8 compatible_revision) { if (descid[0] == head->magic[0] && descid[1] == head->magic[1] && descid[2] == head->magic[2] && descid[3] == head->magic[3] && diff --git a/drivers/net/wireless/ath/carl9170/hw.h b/drivers/net/wireless/ath/carl9170/hw.h index e85df6edfed3..4e30762dd903 100644 --- a/drivers/net/wireless/ath/carl9170/hw.h +++ b/drivers/net/wireless/ath/carl9170/hw.h @@ -463,6 +463,8 @@ #define AR9170_PWR_REG_CHIP_REVISION (AR9170_PWR_REG_BASE + 0x010) #define AR9170_PWR_REG_PLL_ADDAC (AR9170_PWR_REG_BASE + 0x014) +#define AR9170_PWR_PLL_ADDAC_DIV_S 2 +#define AR9170_PWR_PLL_ADDAC_DIV 0xffc #define AR9170_PWR_REG_WATCH_DOG_MAGIC (AR9170_PWR_REG_BASE + 0x020) /* Faraday USB Controller */ @@ -471,6 +473,9 @@ #define AR9170_USB_REG_MAIN_CTRL (AR9170_USB_REG_BASE + 0x000) #define AR9170_USB_MAIN_CTRL_REMOTE_WAKEUP BIT(0) #define AR9170_USB_MAIN_CTRL_ENABLE_GLOBAL_INT BIT(2) +#define AR9170_USB_MAIN_CTRL_GO_TO_SUSPEND BIT(3) +#define AR9170_USB_MAIN_CTRL_RESET BIT(4) +#define AR9170_USB_MAIN_CTRL_CHIP_ENABLE BIT(5) #define AR9170_USB_MAIN_CTRL_HIGHSPEED BIT(6) #define AR9170_USB_REG_DEVICE_ADDRESS (AR9170_USB_REG_BASE + 0x001) @@ -499,6 +504,13 @@ #define AR9170_USB_REG_INTR_GROUP (AR9170_USB_REG_BASE + 0x020) #define AR9170_USB_REG_INTR_SOURCE_0 (AR9170_USB_REG_BASE + 0x021) +#define AR9170_USB_INTR_SRC0_SETUP BIT(0) +#define AR9170_USB_INTR_SRC0_IN BIT(1) +#define AR9170_USB_INTR_SRC0_OUT BIT(2) +#define AR9170_USB_INTR_SRC0_FAIL BIT(3) /* ??? */ +#define AR9170_USB_INTR_SRC0_END BIT(4) /* ??? */ +#define AR9170_USB_INTR_SRC0_ABORT BIT(7) + #define AR9170_USB_REG_INTR_SOURCE_1 (AR9170_USB_REG_BASE + 0x022) #define AR9170_USB_REG_INTR_SOURCE_2 (AR9170_USB_REG_BASE + 0x023) #define AR9170_USB_REG_INTR_SOURCE_3 (AR9170_USB_REG_BASE + 0x024) @@ -506,6 +518,15 @@ #define AR9170_USB_REG_INTR_SOURCE_5 (AR9170_USB_REG_BASE + 0x026) #define AR9170_USB_REG_INTR_SOURCE_6 (AR9170_USB_REG_BASE + 0x027) #define AR9170_USB_REG_INTR_SOURCE_7 (AR9170_USB_REG_BASE + 0x028) +#define AR9170_USB_INTR_SRC7_USB_RESET BIT(1) +#define AR9170_USB_INTR_SRC7_USB_SUSPEND BIT(2) +#define AR9170_USB_INTR_SRC7_USB_RESUME BIT(3) +#define AR9170_USB_INTR_SRC7_ISO_SEQ_ERR BIT(4) +#define AR9170_USB_INTR_SRC7_ISO_SEQ_ABORT BIT(5) +#define AR9170_USB_INTR_SRC7_TX0BYTE BIT(6) +#define AR9170_USB_INTR_SRC7_RX0BYTE BIT(7) + +#define AR9170_USB_REG_IDLE_COUNT (AR9170_USB_REG_BASE + 0x02f) #define AR9170_USB_REG_EP_MAP (AR9170_USB_REG_BASE + 0x030) #define AR9170_USB_REG_EP1_MAP (AR9170_USB_REG_BASE + 0x030) @@ -581,6 +602,10 @@ #define AR9170_USB_REG_MAX_AGG_UPLOAD (AR9170_USB_REG_BASE + 0x110) #define AR9170_USB_REG_UPLOAD_TIME_CTL (AR9170_USB_REG_BASE + 0x114) + +#define AR9170_USB_REG_WAKE_UP (AR9170_USB_REG_BASE + 0x120) +#define AR9170_USB_WAKE_UP_WAKE BIT(0) + #define AR9170_USB_REG_CBUS_CTRL (AR9170_USB_REG_BASE + 0x1f0) #define AR9170_USB_CBUS_CTRL_BUFFER_END (BIT(1)) diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 870df8c42622..ede3d7e5a048 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -662,6 +662,13 @@ init: goto unlock; } + if (ar->fw.tx_seq_table) { + err = carl9170_write_reg(ar, ar->fw.tx_seq_table + vif_id * 4, + 0); + if (err) + goto unlock; + } + unlock: if (err && (vif_id >= 0)) { vif_priv->active = false; @@ -1279,7 +1286,7 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, - u16 tid, u16 *ssn) + u16 tid, u16 *ssn, u8 buf_size) { struct ar9170 *ar = hw->priv; struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index 6cc58e052d10..6f41e21d3a1c 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -862,6 +862,9 @@ static int carl9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) if (unlikely(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM)) txc->s.misc |= CARL9170_TX_SUPER_MISC_CAB; + if (unlikely(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)) + txc->s.misc |= CARL9170_TX_SUPER_MISC_ASSIGN_SEQ; + if (unlikely(ieee80211_is_probe_resp(hdr->frame_control))) txc->s.misc |= CARL9170_TX_SUPER_MISC_FILL_IN_TSF; diff --git a/drivers/net/wireless/ath/carl9170/version.h b/drivers/net/wireless/ath/carl9170/version.h index ee0f84f2a2f6..15095c035169 100644 --- a/drivers/net/wireless/ath/carl9170/version.h +++ b/drivers/net/wireless/ath/carl9170/version.h @@ -1,7 +1,7 @@ #ifndef __CARL9170_SHARED_VERSION_H #define __CARL9170_SHARED_VERSION_H -#define CARL9170FW_VERSION_YEAR 10 -#define CARL9170FW_VERSION_MONTH 10 -#define CARL9170FW_VERSION_DAY 29 -#define CARL9170FW_VERSION_GIT "1.9.0" +#define CARL9170FW_VERSION_YEAR 11 +#define CARL9170FW_VERSION_MONTH 1 +#define CARL9170FW_VERSION_DAY 22 +#define CARL9170FW_VERSION_GIT "1.9.2" #endif /* __CARL9170_SHARED_VERSION_H */ diff --git a/drivers/net/wireless/ath/carl9170/wlan.h b/drivers/net/wireless/ath/carl9170/wlan.h index 24d63b583b6b..9e1324b67e08 100644 --- a/drivers/net/wireless/ath/carl9170/wlan.h +++ b/drivers/net/wireless/ath/carl9170/wlan.h @@ -251,7 +251,7 @@ struct carl9170_tx_superdesc { u8 ampdu_commit_factor:1; u8 ampdu_unused_bit:1; u8 queue:2; - u8 reserved:1; + u8 assign_seq:1; u8 vif_id:3; u8 fill_in_tsf:1; u8 cab:1; @@ -299,6 +299,7 @@ struct _ar9170_tx_hwdesc { #define CARL9170_TX_SUPER_MISC_QUEUE 0x3 #define CARL9170_TX_SUPER_MISC_QUEUE_S 0 +#define CARL9170_TX_SUPER_MISC_ASSIGN_SEQ 0x4 #define CARL9170_TX_SUPER_MISC_VIF_ID 0x38 #define CARL9170_TX_SUPER_MISC_VIF_ID_S 3 #define CARL9170_TX_SUPER_MISC_FILL_IN_TSF 0x40 @@ -413,6 +414,23 @@ enum ar9170_txq { __AR9170_NUM_TXQ, }; +/* + * This is an workaround for several undocumented bugs. + * Don't mess with the QoS/AC <-> HW Queue map, if you don't + * know what you are doing. + * + * Known problems [hardware]: + * * The MAC does not aggregate frames on anything other + * than the first HW queue. + * * when an AMPDU is placed [in the first hw queue] and + * additional frames are already queued on a different + * hw queue, the MAC will ALWAYS freeze. + * + * In a nutshell: The hardware can either do QoS or + * Aggregation but not both at the same time. As a + * result, this makes the device pretty much useless + * for any serious 802.11n setup. + */ static const u8 ar9170_qmap[__AR9170_NUM_TXQ] = { 2, 1, 0, 3 }; #define AR9170_TXQ_DEPTH 32 diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c index 5d465e5fcf24..37b8e115375a 100644 --- a/drivers/net/wireless/ath/key.c +++ b/drivers/net/wireless/ath/key.c @@ -58,8 +58,11 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry) REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); - if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) + if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) { REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), + AR_KEYTABLE_TYPE_CLR); + } } diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 2b14775e6bc6..f828f294ba89 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -158,6 +158,13 @@ ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg) } } +bool ath_is_49ghz_allowed(u16 regdomain) +{ + /* possibly more */ + return regdomain == MKK9_MKKC; +} +EXPORT_SYMBOL(ath_is_49ghz_allowed); + /* Frequency is one where radar detection is required */ static bool ath_is_radar_freq(u16 center_freq) { diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 345dd9721b41..172f63f671cf 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -250,6 +250,7 @@ enum CountryCode { }; bool ath_is_world_regd(struct ath_regulatory *reg); +bool ath_is_49ghz_allowed(u16 redomain); int ath_regd_init(struct ath_regulatory *reg, struct wiphy *wiphy, int (*reg_notifier)(struct wiphy *wiphy, struct regulatory_request *request)); diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 61915f371416..da60faee74fc 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -1397,7 +1397,7 @@ static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv) } /* - * Send the CARD_DISABLE_PHY_OFF comamnd to the card to disable it + * Send the CARD_DISABLE_PHY_OFF command to the card to disable it * * After disabling, if the card was associated, a STATUS_ASSN_LOST will be sent. * diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index ed424574160e..e1e3b1cf3cff 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -2,6 +2,10 @@ config IWLWIFI tristate "Intel Wireless Wifi" depends on PCI && MAC80211 select FW_LOADER + select NEW_LEDS + select LEDS_CLASS + select LEDS_TRIGGERS + select MAC80211_LEDS menu "Debugging Options" depends on IWLWIFI @@ -106,9 +110,27 @@ config IWL5000 Intel WiFi Link 1000BGN Intel Wireless WiFi 5150AGN Intel Wireless WiFi 5100AGN, 5300AGN, and 5350AGN - Intel 6000 Gen 2 Series Wi-Fi Adapters (6000G2A and 6000G2B) - Intel WIreless WiFi Link 6050BGN Gen 2 Adapter + Intel 6005 Series Wi-Fi Adapters + Intel 6030 Series Wi-Fi Adapters + Intel Wireless WiFi Link 6150BGN 2 Adapter Intel 100 Series Wi-Fi Adapters (100BGN and 130BGN) + Intel 2000 Series Wi-Fi Adapters + +config IWL_P2P + bool "iwlwifi experimental P2P support" + depends on IWL5000 + help + This option enables experimental P2P support for some devices + based on microcode support. Since P2P support is still under + development, this option may even enable it for some devices + now that turn out to not support it in the future due to + microcode restrictions. + + To determine if your microcode supports the experimental P2P + offered by this option, check if the driver advertises AP + support when it is loaded. + + Say Y only if you want to experiment with P2P. config IWL3945 tristate "Intel PRO/Wireless 3945ABG/BG Network Connection (iwl3945)" diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 93380f97835f..25be742c69c9 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -26,6 +26,7 @@ iwlagn-$(CONFIG_IWL5000) += iwl-agn-rxon.o iwl-agn-hcmd.o iwl-agn-ict.o iwlagn-$(CONFIG_IWL5000) += iwl-5000.o iwlagn-$(CONFIG_IWL5000) += iwl-6000.o iwlagn-$(CONFIG_IWL5000) += iwl-1000.o +iwlagn-$(CONFIG_IWL5000) += iwl-2000.o # 3945 obj-$(CONFIG_IWL3945) += iwl3945.o diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c new file mode 100644 index 000000000000..3c5dd36ff417 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -0,0 +1,560 @@ +/****************************************************************************** + * + * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/wireless.h> +#include <net/mac80211.h> +#include <linux/etherdevice.h> +#include <asm/unaligned.h> + +#include "iwl-eeprom.h" +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-io.h" +#include "iwl-sta.h" +#include "iwl-agn.h" +#include "iwl-helpers.h" +#include "iwl-agn-hw.h" +#include "iwl-6000-hw.h" +#include "iwl-agn-led.h" +#include "iwl-agn-debugfs.h" + +/* Highest firmware API version supported */ +#define IWL2030_UCODE_API_MAX 5 +#define IWL2000_UCODE_API_MAX 5 +#define IWL200_UCODE_API_MAX 5 + +/* Lowest firmware API version supported */ +#define IWL2030_UCODE_API_MIN 5 +#define IWL2000_UCODE_API_MIN 5 +#define IWL200_UCODE_API_MIN 5 + +#define IWL2030_FW_PRE "iwlwifi-2030-" +#define _IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE #api ".ucode" +#define IWL2030_MODULE_FIRMWARE(api) _IWL2030_MODULE_FIRMWARE(api) + +#define IWL2000_FW_PRE "iwlwifi-2000-" +#define _IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE #api ".ucode" +#define IWL2000_MODULE_FIRMWARE(api) _IWL2000_MODULE_FIRMWARE(api) + +#define IWL200_FW_PRE "iwlwifi-200-" +#define _IWL200_MODULE_FIRMWARE(api) IWL200_FW_PRE #api ".ucode" +#define IWL200_MODULE_FIRMWARE(api) _IWL200_MODULE_FIRMWARE(api) + +static void iwl2000_set_ct_threshold(struct iwl_priv *priv) +{ + /* want Celsius */ + priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; + priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; +} + +/* NIC configuration for 2000 series */ +static void iwl2000_nic_config(struct iwl_priv *priv) +{ + u16 radio_cfg; + + radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); + + /* write radio config values to register */ + if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <= EEPROM_RF_CONFIG_TYPE_MAX) + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + EEPROM_RF_CFG_TYPE_MSK(radio_cfg) | + EEPROM_RF_CFG_STEP_MSK(radio_cfg) | + EEPROM_RF_CFG_DASH_MSK(radio_cfg)); + + /* set CSR_HW_CONFIG_REG for uCode use */ + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | + CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); + + if (priv->cfg->iq_invert) + iwl_set_bit(priv, CSR_GP_DRIVER_REG, + CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER); + +} + +static struct iwl_sensitivity_ranges iwl2000_sensitivity = { + .min_nrg_cck = 97, + .max_nrg_cck = 0, /* not used, set to 0 */ + .auto_corr_min_ofdm = 80, + .auto_corr_min_ofdm_mrc = 128, + .auto_corr_min_ofdm_x1 = 105, + .auto_corr_min_ofdm_mrc_x1 = 192, + + .auto_corr_max_ofdm = 145, + .auto_corr_max_ofdm_mrc = 232, + .auto_corr_max_ofdm_x1 = 110, + .auto_corr_max_ofdm_mrc_x1 = 232, + + .auto_corr_min_cck = 125, + .auto_corr_max_cck = 175, + .auto_corr_min_cck_mrc = 160, + .auto_corr_max_cck_mrc = 310, + .nrg_th_cck = 97, + .nrg_th_ofdm = 100, + + .barker_corr_th_min = 190, + .barker_corr_th_min_mrc = 390, + .nrg_th_cca = 62, +}; + +static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) +{ + if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && + priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) + priv->cfg->base_params->num_of_queues = + priv->cfg->mod_params->num_of_queues; + + priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; + priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; + priv->hw_params.scd_bc_tbls_size = + priv->cfg->base_params->num_of_queues * + sizeof(struct iwlagn_scd_bc_tbl); + priv->hw_params.tfd_size = sizeof(struct iwl_tfd); + priv->hw_params.max_stations = IWLAGN_STATION_COUNT; + priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID; + + priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; + priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; + + priv->hw_params.max_bsm_size = 0; + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | + BIT(IEEE80211_BAND_5GHZ); + priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; + + priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); + if (priv->cfg->rx_with_siso_diversity) + priv->hw_params.rx_chains_num = 1; + else + priv->hw_params.rx_chains_num = + num_of_ant(priv->cfg->valid_rx_ant); + priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; + priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; + + iwl2000_set_ct_threshold(priv); + + /* Set initial sensitivity parameters */ + /* Set initial calibration set */ + priv->hw_params.sens = &iwl2000_sensitivity; + priv->hw_params.calib_init_cfg = + BIT(IWL_CALIB_XTAL) | + BIT(IWL_CALIB_LO) | + BIT(IWL_CALIB_TX_IQ) | + BIT(IWL_CALIB_BASE_BAND); + if (priv->cfg->need_dc_calib) + priv->hw_params.calib_rt_cfg |= BIT(IWL_CALIB_CFG_DC_IDX); + if (priv->cfg->need_temp_offset_calib) + priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_TEMP_OFFSET); + + priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS; + + return 0; +} + +static int iwl2030_hw_channel_switch(struct iwl_priv *priv, + struct ieee80211_channel_switch *ch_switch) +{ + /* + * MULTI-FIXME + * See iwl_mac_channel_switch. + */ + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + struct iwl6000_channel_switch_cmd cmd; + const struct iwl_channel_info *ch_info; + u32 switch_time_in_usec, ucode_switch_time; + u16 ch; + u32 tsf_low; + u8 switch_count; + u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval); + struct ieee80211_vif *vif = ctx->vif; + struct iwl_host_cmd hcmd = { + .id = REPLY_CHANNEL_SWITCH, + .len = sizeof(cmd), + .flags = CMD_SYNC, + .data = &cmd, + }; + + cmd.band = priv->band == IEEE80211_BAND_2GHZ; + ch = ch_switch->channel->hw_value; + IWL_DEBUG_11H(priv, "channel switch from %u to %u\n", + ctx->active.channel, ch); + cmd.channel = cpu_to_le16(ch); + cmd.rxon_flags = ctx->staging.flags; + cmd.rxon_filter_flags = ctx->staging.filter_flags; + switch_count = ch_switch->count; + tsf_low = ch_switch->timestamp & 0x0ffffffff; + /* + * calculate the ucode channel switch time + * adding TSF as one of the factor for when to switch + */ + if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) { + if (switch_count > ((priv->ucode_beacon_time - tsf_low) / + beacon_interval)) { + switch_count -= (priv->ucode_beacon_time - + tsf_low) / beacon_interval; + } else + switch_count = 0; + } + if (switch_count <= 1) + cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); + else { + switch_time_in_usec = + vif->bss_conf.beacon_int * switch_count * TIME_UNIT; + ucode_switch_time = iwl_usecs_to_beacons(priv, + switch_time_in_usec, + beacon_interval); + cmd.switch_time = iwl_add_beacon_time(priv, + priv->ucode_beacon_time, + ucode_switch_time, + beacon_interval); + } + IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", + cmd.switch_time); + ch_info = iwl_get_channel_info(priv, priv->band, ch); + if (ch_info) + cmd.expect_beacon = is_channel_radar(ch_info); + else { + IWL_ERR(priv, "invalid channel switch from %u to %u\n", + ctx->active.channel, ch); + return -EFAULT; + } + priv->switch_rxon.channel = cmd.channel; + priv->switch_rxon.switch_in_progress = true; + + return iwl_send_cmd_sync(priv, &hcmd); +} + +static struct iwl_lib_ops iwl2000_lib = { + .set_hw_params = iwl2000_hw_set_hw_params, + .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, + .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, + .txq_set_sched = iwlagn_txq_set_sched, + .txq_agg_enable = iwlagn_txq_agg_enable, + .txq_agg_disable = iwlagn_txq_agg_disable, + .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, + .txq_free_tfd = iwl_hw_txq_free_tfd, + .txq_init = iwl_hw_tx_queue_init, + .rx_handler_setup = iwlagn_rx_handler_setup, + .setup_deferred_work = iwlagn_setup_deferred_work, + .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, + .load_ucode = iwlagn_load_ucode, + .dump_nic_event_log = iwl_dump_nic_event_log, + .dump_nic_error_log = iwl_dump_nic_error_log, + .dump_csr = iwl_dump_csr, + .dump_fh = iwl_dump_fh, + .init_alive_start = iwlagn_init_alive_start, + .alive_notify = iwlagn_alive_notify, + .send_tx_power = iwlagn_send_tx_power, + .update_chain_flags = iwl_update_chain_flags, + .set_channel_switch = iwl2030_hw_channel_switch, + .apm_ops = { + .init = iwl_apm_init, + .config = iwl2000_nic_config, + }, + .eeprom_ops = { + .regulatory_bands = { + EEPROM_REG_BAND_1_CHANNELS, + EEPROM_REG_BAND_2_CHANNELS, + EEPROM_REG_BAND_3_CHANNELS, + EEPROM_REG_BAND_4_CHANNELS, + EEPROM_REG_BAND_5_CHANNELS, + EEPROM_6000_REG_BAND_24_HT40_CHANNELS, + EEPROM_REG_BAND_52_HT40_CHANNELS + }, + .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, + .release_semaphore = iwlcore_eeprom_release_semaphore, + .calib_version = iwlagn_eeprom_calib_version, + .query_addr = iwlagn_eeprom_query_addr, + .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, + }, + .isr_ops = { + .isr = iwl_isr_ict, + .free = iwl_free_isr_ict, + .alloc = iwl_alloc_isr_ict, + .reset = iwl_reset_ict, + .disable = iwl_disable_ict, + }, + .temp_ops = { + .temperature = iwlagn_temperature, + }, + .debugfs_ops = { + .rx_stats_read = iwl_ucode_rx_stats_read, + .tx_stats_read = iwl_ucode_tx_stats_read, + .general_stats_read = iwl_ucode_general_stats_read, + .bt_stats_read = iwl_ucode_bt_stats_read, + .reply_tx_error = iwl_reply_tx_error_read, + }, + .check_plcp_health = iwl_good_plcp_health, + .check_ack_health = iwl_good_ack_health, + .txfifo_flush = iwlagn_txfifo_flush, + .dev_txfifo_flush = iwlagn_dev_txfifo_flush, + .tt_ops = { + .lower_power_detection = iwl_tt_is_low_power_state, + .tt_power_mode = iwl_tt_current_power_mode, + .ct_kill_check = iwl_check_for_ct_kill, + } +}; + +static const struct iwl_ops iwl2000_ops = { + .lib = &iwl2000_lib, + .hcmd = &iwlagn_hcmd, + .utils = &iwlagn_hcmd_utils, + .led = &iwlagn_led_ops, + .ieee80211_ops = &iwlagn_hw_ops, +}; + +static const struct iwl_ops iwl2030_ops = { + .lib = &iwl2000_lib, + .hcmd = &iwlagn_bt_hcmd, + .utils = &iwlagn_hcmd_utils, + .led = &iwlagn_led_ops, + .ieee80211_ops = &iwlagn_hw_ops, +}; + +static const struct iwl_ops iwl200_ops = { + .lib = &iwl2000_lib, + .hcmd = &iwlagn_hcmd, + .utils = &iwlagn_hcmd_utils, + .led = &iwlagn_led_ops, + .ieee80211_ops = &iwlagn_hw_ops, +}; + +static const struct iwl_ops iwl230_ops = { + .lib = &iwl2000_lib, + .hcmd = &iwlagn_bt_hcmd, + .utils = &iwlagn_hcmd_utils, + .led = &iwlagn_led_ops, + .ieee80211_ops = &iwlagn_hw_ops, +}; + +static struct iwl_base_params iwl2000_base_params = { + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .num_of_queues = IWLAGN_NUM_QUEUES, + .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .pll_cfg_val = 0, + .set_l0s = true, + .use_bsm = false, + .max_ll_items = OTP_MAX_LL_ITEMS_2x00, + .shadow_ram_support = true, + .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .adv_thermal_throttle = true, + .support_ct_kill_exit = true, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, + .chain_noise_scale = 1000, + .wd_timeout = IWL_DEF_WD_TIMEOUT, + .max_event_log_size = 512, + .ucode_tracing = true, + .sensitivity_calib_by_driver = true, + .chain_noise_calib_by_driver = true, + .shadow_reg_enable = true, +}; + + +static struct iwl_base_params iwl2030_base_params = { + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .num_of_queues = IWLAGN_NUM_QUEUES, + .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, + .pll_cfg_val = 0, + .set_l0s = true, + .use_bsm = false, + .max_ll_items = OTP_MAX_LL_ITEMS_2x00, + .shadow_ram_support = true, + .led_compensation = 57, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .adv_thermal_throttle = true, + .support_ct_kill_exit = true, + .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, + .chain_noise_scale = 1000, + .wd_timeout = IWL_LONG_WD_TIMEOUT, + .max_event_log_size = 512, + .ucode_tracing = true, + .sensitivity_calib_by_driver = true, + .chain_noise_calib_by_driver = true, + .shadow_reg_enable = true, +}; + +static struct iwl_ht_params iwl2000_ht_params = { + .ht_greenfield_support = true, + .use_rts_for_aggregation = true, /* use rts/cts protection */ +}; + +static struct iwl_bt_params iwl2030_bt_params = { + .bt_statistics = true, + /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ + .advanced_bt_coexist = true, + .agg_time_limit = BT_AGG_THRESHOLD_DEF, + .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE, + .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT, + .bt_sco_disable = true, +}; + +#define IWL_DEVICE_2000 \ + .fw_name_pre = IWL2000_FW_PRE, \ + .ucode_api_max = IWL2000_UCODE_API_MAX, \ + .ucode_api_min = IWL2000_UCODE_API_MIN, \ + .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ + .ops = &iwl2000_ops, \ + .mod_params = &iwlagn_mod_params, \ + .base_params = &iwl2000_base_params, \ + .need_dc_calib = true, \ + .need_temp_offset_calib = true, \ + .led_mode = IWL_LED_RF_STATE, \ + .iq_invert = true \ + +struct iwl_cfg iwl2000_2bgn_cfg = { + .name = "2000 Series 2x2 BGN", + IWL_DEVICE_2000, + .ht_params = &iwl2000_ht_params, +}; + +struct iwl_cfg iwl2000_2bg_cfg = { + .name = "2000 Series 2x2 BG", + IWL_DEVICE_2000, +}; + +#define IWL_DEVICE_2030 \ + .fw_name_pre = IWL2030_FW_PRE, \ + .ucode_api_max = IWL2030_UCODE_API_MAX, \ + .ucode_api_min = IWL2030_UCODE_API_MIN, \ + .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ + .ops = &iwl2030_ops, \ + .mod_params = &iwlagn_mod_params, \ + .base_params = &iwl2030_base_params, \ + .bt_params = &iwl2030_bt_params, \ + .need_dc_calib = true, \ + .need_temp_offset_calib = true, \ + .led_mode = IWL_LED_RF_STATE, \ + .adv_pm = true, \ + .iq_invert = true \ + +struct iwl_cfg iwl2030_2bgn_cfg = { + .name = "2000 Series 2x2 BGN/BT", + IWL_DEVICE_2030, + .ht_params = &iwl2000_ht_params, +}; + +struct iwl_cfg iwl2030_2bg_cfg = { + .name = "2000 Series 2x2 BG/BT", + IWL_DEVICE_2030, +}; + +#define IWL_DEVICE_6035 \ + .fw_name_pre = IWL2030_FW_PRE, \ + .ucode_api_max = IWL2030_UCODE_API_MAX, \ + .ucode_api_min = IWL2030_UCODE_API_MIN, \ + .eeprom_ver = EEPROM_6035_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_6035_TX_POWER_VERSION, \ + .ops = &iwl2030_ops, \ + .mod_params = &iwlagn_mod_params, \ + .base_params = &iwl2030_base_params, \ + .bt_params = &iwl2030_bt_params, \ + .need_dc_calib = true, \ + .need_temp_offset_calib = true, \ + .led_mode = IWL_LED_RF_STATE, \ + .adv_pm = true \ + +struct iwl_cfg iwl6035_2agn_cfg = { + .name = "2000 Series 2x2 AGN/BT", + IWL_DEVICE_6035, + .ht_params = &iwl2000_ht_params, +}; + +struct iwl_cfg iwl6035_2abg_cfg = { + .name = "2000 Series 2x2 ABG/BT", + IWL_DEVICE_6035, +}; + +struct iwl_cfg iwl6035_2bg_cfg = { + .name = "2000 Series 2x2 BG/BT", + IWL_DEVICE_6035, +}; + +#define IWL_DEVICE_200 \ + .fw_name_pre = IWL200_FW_PRE, \ + .ucode_api_max = IWL200_UCODE_API_MAX, \ + .ucode_api_min = IWL200_UCODE_API_MIN, \ + .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ + .ops = &iwl200_ops, \ + .mod_params = &iwlagn_mod_params, \ + .base_params = &iwl2000_base_params, \ + .need_dc_calib = true, \ + .need_temp_offset_calib = true, \ + .led_mode = IWL_LED_RF_STATE, \ + .adv_pm = true, \ + .rx_with_siso_diversity = true \ + +struct iwl_cfg iwl200_bg_cfg = { + .name = "200 Series 1x1 BG", + IWL_DEVICE_200, +}; + +struct iwl_cfg iwl200_bgn_cfg = { + .name = "200 Series 1x1 BGN", + IWL_DEVICE_200, + .ht_params = &iwl2000_ht_params, +}; + +#define IWL_DEVICE_230 \ + .fw_name_pre = IWL200_FW_PRE, \ + .ucode_api_max = IWL200_UCODE_API_MAX, \ + .ucode_api_min = IWL200_UCODE_API_MIN, \ + .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ + .ops = &iwl230_ops, \ + .mod_params = &iwlagn_mod_params, \ + .base_params = &iwl2030_base_params, \ + .bt_params = &iwl2030_bt_params, \ + .need_dc_calib = true, \ + .need_temp_offset_calib = true, \ + .led_mode = IWL_LED_RF_STATE, \ + .adv_pm = true, \ + .rx_with_siso_diversity = true \ + +struct iwl_cfg iwl230_bg_cfg = { + .name = "200 Series 1x1 BG/BT", + IWL_DEVICE_230, +}; + +struct iwl_cfg iwl230_bgn_cfg = { + .name = "200 Series 1x1 BGN/BT", + IWL_DEVICE_230, + .ht_params = &iwl2000_ht_params, +}; + +MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL200_MODULE_FIRMWARE(IWL200_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index abe2b739c4dc..dc7c3a4167a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -59,33 +59,6 @@ static int iwl3945_send_led_cmd(struct iwl_priv *priv, return iwl_send_cmd(priv, &cmd); } -/* Set led on command */ -static int iwl3945_led_on(struct iwl_priv *priv) -{ - struct iwl_led_cmd led_cmd = { - .id = IWL_LED_LINK, - .on = IWL_LED_SOLID, - .off = 0, - .interval = IWL_DEF_LED_INTRVL - }; - return iwl3945_send_led_cmd(priv, &led_cmd); -} - -/* Set led off command */ -static int iwl3945_led_off(struct iwl_priv *priv) -{ - struct iwl_led_cmd led_cmd = { - .id = IWL_LED_LINK, - .on = 0, - .off = 0, - .interval = IWL_DEF_LED_INTRVL - }; - IWL_DEBUG_LED(priv, "led off\n"); - return iwl3945_send_led_cmd(priv, &led_cmd); -} - const struct iwl_led_ops iwl3945_led_ops = { .cmd = iwl3945_send_led_cmd, - .on = iwl3945_led_on, - .off = iwl3945_led_off, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index a9b852be4509..166e9f742596 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -402,72 +402,6 @@ static void iwl3945_accumulative_statistics(struct iwl_priv *priv, } #endif -/** - * iwl3945_good_plcp_health - checks for plcp error. - * - * When the plcp error is exceeding the thresholds, reset the radio - * to improve the throughput. - */ -static bool iwl3945_good_plcp_health(struct iwl_priv *priv, - struct iwl_rx_packet *pkt) -{ - bool rc = true; - struct iwl3945_notif_statistics current_stat; - int combined_plcp_delta; - unsigned int plcp_msec; - unsigned long plcp_received_jiffies; - - if (priv->cfg->base_params->plcp_delta_threshold == - IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) { - IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n"); - return rc; - } - memcpy(¤t_stat, pkt->u.raw, sizeof(struct - iwl3945_notif_statistics)); - /* - * check for plcp_err and trigger radio reset if it exceeds - * the plcp error threshold plcp_delta. - */ - plcp_received_jiffies = jiffies; - plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies - - (long) priv->plcp_jiffies); - priv->plcp_jiffies = plcp_received_jiffies; - /* - * check to make sure plcp_msec is not 0 to prevent division - * by zero. - */ - if (plcp_msec) { - combined_plcp_delta = - (le32_to_cpu(current_stat.rx.ofdm.plcp_err) - - le32_to_cpu(priv->_3945.statistics.rx.ofdm.plcp_err)); - - if ((combined_plcp_delta > 0) && - ((combined_plcp_delta * 100) / plcp_msec) > - priv->cfg->base_params->plcp_delta_threshold) { - /* - * if plcp_err exceed the threshold, the following - * data is printed in csv format: - * Text: plcp_err exceeded %d, - * Received ofdm.plcp_err, - * Current ofdm.plcp_err, - * combined_plcp_delta, - * plcp_msec - */ - IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, " - "%u, %d, %u mSecs\n", - priv->cfg->base_params->plcp_delta_threshold, - le32_to_cpu(current_stat.rx.ofdm.plcp_err), - combined_plcp_delta, plcp_msec); - /* - * Reset the RF radio due to the high plcp - * error rate - */ - rc = false; - } - } - return rc; -} - void iwl3945_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { @@ -594,10 +528,11 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv, rx_status.flag = 0; rx_status.mactime = le64_to_cpu(rx_end->timestamp); - rx_status.freq = - ieee80211_channel_to_frequency(le16_to_cpu(rx_hdr->channel)); rx_status.band = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + rx_status.freq = + ieee80211_channel_to_frequency(le16_to_cpu(rx_hdr->channel), + rx_status.band); rx_status.rate_idx = iwl3945_hwrate_to_plcp_idx(rx_hdr->rate); if (rx_status.band == IEEE80211_BAND_5GHZ) @@ -761,8 +696,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, /* We need to figure out how to get the sta->supp_rates while * in this running context */ - rate_mask = IWL_RATES_MASK; - + rate_mask = IWL_RATES_MASK_3945; /* Set retry limit on DATA packets and Probe Responses*/ if (ieee80211_is_probe_resp(fc)) @@ -1649,7 +1583,7 @@ static int iwl3945_hw_reg_comp_txpower_temp(struct iwl_priv *priv) ref_temp); /* set tx power value for all rates, OFDM and CCK */ - for (rate_index = 0; rate_index < IWL_RATE_COUNT; + for (rate_index = 0; rate_index < IWL_RATE_COUNT_3945; rate_index++) { int power_idx = ch_info->power_info[rate_index].base_power_index; @@ -1889,7 +1823,7 @@ int iwl3945_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) /* If we issue a new RXON command which required a tune then we must * send a new TXPOWER command or we won't be able to Tx any frames */ - rc = priv->cfg->ops->lib->send_tx_power(priv); + rc = iwl_set_tx_power(priv, priv->tx_power_next, true); if (rc) { IWL_ERR(priv, "Error setting Tx power (%d).\n", rc); return rc; @@ -2734,7 +2668,6 @@ static struct iwl_lib_ops iwl3945_lib = { .isr_ops = { .isr = iwl_isr_legacy, }, - .check_plcp_health = iwl3945_good_plcp_health, .debugfs_ops = { .rx_stats_read = iwl3945_ucode_rx_stats_read, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 91a9f5253469..8998ed134d1a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -251,14 +251,6 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) */ static void iwl4965_init_alive_start(struct iwl_priv *priv) { - /* Check alive response for "valid" sign from uCode */ - if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { - /* We had an error bringing up the hardware, so take it - * all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Initialize Alive failed.\n"); - goto restart; - } - /* Bootstrap uCode has loaded initialize uCode ... verify inst image. * This is a paranoid check, because we would not have gotten the * "initialize" alive if code weren't properly loaded. */ @@ -1571,7 +1563,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *c /* If we issue a new RXON command which required a tune then we must * send a new TXPOWER command or we won't be able to Tx any frames */ - ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); + ret = iwl_set_tx_power(priv, priv->tx_power_next, true); if (ret) { IWL_ERR(priv, "Error sending TX power (%d)\n", ret); return ret; @@ -2274,6 +2266,29 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, spin_unlock_irqrestore(&priv->sta_lock, flags); } +static void iwl4965_rx_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl4965_beacon_notif *beacon = (void *)pkt->u.raw; +#ifdef CONFIG_IWLWIFI_DEBUG + u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); + + IWL_DEBUG_RX(priv, "beacon status %#x, retries:%d ibssmgr:%d " + "tsf:0x%.8x%.8x rate:%d\n", + le32_to_cpu(beacon->beacon_notify_hdr.u.status) & TX_STATUS_MSK, + beacon->beacon_notify_hdr.failure_frame, + le32_to_cpu(beacon->ibss_mgr_status), + le32_to_cpu(beacon->high_tsf), + le32_to_cpu(beacon->low_tsf), rate); +#endif + + priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status); + + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) + queue_work(priv->workqueue, &priv->beacon_update); +} + static int iwl4965_calc_rssi(struct iwl_priv *priv, struct iwl_rx_phy_res *rx_resp) { @@ -2316,6 +2331,12 @@ static void iwl4965_rx_handler_setup(struct iwl_priv *priv) priv->rx_handlers[REPLY_RX] = iwlagn_rx_reply_rx; /* Tx response */ priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx; + priv->rx_handlers[BEACON_NOTIFICATION] = iwl4965_rx_beacon_notif; + + /* set up notification wait support */ + spin_lock_init(&priv->_agn.notif_wait_lock); + INIT_LIST_HEAD(&priv->_agn.notif_waits); + init_waitqueue_head(&priv->_agn.notif_waitq); } static void iwl4965_setup_deferred_work(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index ef36aff1bb43..f6493f77610d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -67,13 +67,13 @@ #define _IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode" #define IWL6050_MODULE_FIRMWARE(api) _IWL6050_MODULE_FIRMWARE(api) -#define IWL6000G2A_FW_PRE "iwlwifi-6000g2a-" -#define _IWL6000G2A_MODULE_FIRMWARE(api) IWL6000G2A_FW_PRE #api ".ucode" -#define IWL6000G2A_MODULE_FIRMWARE(api) _IWL6000G2A_MODULE_FIRMWARE(api) +#define IWL6005_FW_PRE "iwlwifi-6000g2a-" +#define _IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE #api ".ucode" +#define IWL6005_MODULE_FIRMWARE(api) _IWL6005_MODULE_FIRMWARE(api) -#define IWL6000G2B_FW_PRE "iwlwifi-6000g2b-" -#define _IWL6000G2B_MODULE_FIRMWARE(api) IWL6000G2B_FW_PRE #api ".ucode" -#define IWL6000G2B_MODULE_FIRMWARE(api) _IWL6000G2B_MODULE_FIRMWARE(api) +#define IWL6030_FW_PRE "iwlwifi-6000g2b-" +#define _IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE #api ".ucode" +#define IWL6030_MODULE_FIRMWARE(api) _IWL6030_MODULE_FIRMWARE(api) static void iwl6000_set_ct_threshold(struct iwl_priv *priv) { @@ -90,7 +90,7 @@ static void iwl6050_additional_nic_config(struct iwl_priv *priv) CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); } -static void iwl6050g2_additional_nic_config(struct iwl_priv *priv) +static void iwl6150_additional_nic_config(struct iwl_priv *priv) { /* Indicate calibration version to uCode. */ if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6) @@ -354,7 +354,7 @@ static struct iwl_lib_ops iwl6000_lib = { } }; -static struct iwl_lib_ops iwl6000g2b_lib = { +static struct iwl_lib_ops iwl6030_lib = { .set_hw_params = iwl6000_hw_set_hw_params, .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, @@ -430,8 +430,8 @@ static struct iwl_nic_ops iwl6050_nic_ops = { .additional_nic_config = &iwl6050_additional_nic_config, }; -static struct iwl_nic_ops iwl6050g2_nic_ops = { - .additional_nic_config = &iwl6050g2_additional_nic_config, +static struct iwl_nic_ops iwl6150_nic_ops = { + .additional_nic_config = &iwl6150_additional_nic_config, }; static const struct iwl_ops iwl6000_ops = { @@ -451,17 +451,17 @@ static const struct iwl_ops iwl6050_ops = { .ieee80211_ops = &iwlagn_hw_ops, }; -static const struct iwl_ops iwl6050g2_ops = { +static const struct iwl_ops iwl6150_ops = { .lib = &iwl6000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, .led = &iwlagn_led_ops, - .nic = &iwl6050g2_nic_ops, + .nic = &iwl6150_nic_ops, .ieee80211_ops = &iwlagn_hw_ops, }; -static const struct iwl_ops iwl6000g2b_ops = { - .lib = &iwl6000g2b_lib, +static const struct iwl_ops iwl6030_ops = { + .lib = &iwl6030_lib, .hcmd = &iwlagn_bt_hcmd, .utils = &iwlagn_hcmd_utils, .led = &iwlagn_led_ops, @@ -479,7 +479,6 @@ static struct iwl_base_params iwl6000_base_params = { .shadow_ram_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, @@ -503,7 +502,6 @@ static struct iwl_base_params iwl6050_base_params = { .shadow_ram_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, @@ -526,7 +524,6 @@ static struct iwl_base_params iwl6000_g2_base_params = { .shadow_ram_support = true, .led_compensation = 57, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, @@ -555,11 +552,11 @@ static struct iwl_bt_params iwl6000_bt_params = { }; #define IWL_DEVICE_6005 \ - .fw_name_pre = IWL6000G2A_FW_PRE, \ + .fw_name_pre = IWL6005_FW_PRE, \ .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ - .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, \ - .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, \ + .eeprom_ver = EEPROM_6005_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ .ops = &iwl6000_ops, \ .mod_params = &iwlagn_mod_params, \ .base_params = &iwl6000_g2_base_params, \ @@ -584,12 +581,12 @@ struct iwl_cfg iwl6005_2bg_cfg = { }; #define IWL_DEVICE_6030 \ - .fw_name_pre = IWL6000G2B_FW_PRE, \ + .fw_name_pre = IWL6030_FW_PRE, \ .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ - .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION, \ - .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION, \ - .ops = &iwl6000g2b_ops, \ + .eeprom_ver = EEPROM_6030_EEPROM_VERSION, \ + .eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ + .ops = &iwl6030_ops, \ .mod_params = &iwlagn_mod_params, \ .base_params = &iwl6000_g2_base_params, \ .bt_params = &iwl6000_bt_params, \ @@ -708,9 +705,9 @@ struct iwl_cfg iwl6150_bgn_cfg = { .fw_name_pre = IWL6050_FW_PRE, .ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_min = IWL6050_UCODE_API_MIN, - .eeprom_ver = EEPROM_6050G2_EEPROM_VERSION, - .eeprom_calib_ver = EEPROM_6050G2_TX_POWER_VERSION, - .ops = &iwl6050g2_ops, + .eeprom_ver = EEPROM_6150_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION, + .ops = &iwl6150_ops, .mod_params = &iwlagn_mod_params, .base_params = &iwl6050_base_params, .ht_params = &iwl6000_ht_params, @@ -736,5 +733,5 @@ struct iwl_cfg iwl6000_3agn_cfg = { MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL6000G2A_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL6000G2B_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL6005_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL6030_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c index d16bb5ede014..9006293e740c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c @@ -631,8 +631,7 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp) } spin_lock_irqsave(&priv->lock, flags); - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { + if (iwl_bt_statistics(priv)) { rx_info = &(((struct iwl_bt_notif_statistics *)resp)-> rx.general.common); ofdm = &(((struct iwl_bt_notif_statistics *)resp)->rx.ofdm); @@ -897,8 +896,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) } spin_lock_irqsave(&priv->lock, flags); - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { + if (iwl_bt_statistics(priv)) { rx_info = &(((struct iwl_bt_notif_statistics *)stat_resp)-> rx.general.common); } else { @@ -913,8 +911,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK); rxon_chnum = le16_to_cpu(ctx->staging.channel); - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { + if (iwl_bt_statistics(priv)) { stat_band24 = !!(((struct iwl_bt_notif_statistics *) stat_resp)->flag & STATISTICS_REPLY_FLG_BAND_24G_MSK); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c index a6dbd8983dac..b500aaae53ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c @@ -39,8 +39,7 @@ static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz) int p = 0; u32 flag; - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) + if (iwl_bt_statistics(priv)) flag = le32_to_cpu(priv->_agn.statistics_bt.flag); else flag = le32_to_cpu(priv->_agn.statistics.flag); @@ -89,8 +88,7 @@ ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf, * the last statistics notification from uCode * might not reflect the current uCode activity */ - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { + if (iwl_bt_statistics(priv)) { ofdm = &priv->_agn.statistics_bt.rx.ofdm; cck = &priv->_agn.statistics_bt.rx.cck; general = &priv->_agn.statistics_bt.rx.general.common; @@ -536,8 +534,7 @@ ssize_t iwl_ucode_tx_stats_read(struct file *file, * the last statistics notification from uCode * might not reflect the current uCode activity */ - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { + if (iwl_bt_statistics(priv)) { tx = &priv->_agn.statistics_bt.tx; accum_tx = &priv->_agn.accum_statistics_bt.tx; delta_tx = &priv->_agn.delta_statistics_bt.tx; @@ -737,8 +734,7 @@ ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf, * the last statistics notification from uCode * might not reflect the current uCode activity */ - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { + if (iwl_bt_statistics(priv)) { general = &priv->_agn.statistics_bt.general.common; dbg = &priv->_agn.statistics_bt.general.common.dbg; div = &priv->_agn.statistics_bt.general.common.div; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c index 366340f3fb0f..41543ad4cb84 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c @@ -305,7 +305,11 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv) cmd.slots[0].type = 0; /* BSS */ cmd.slots[1].type = 1; /* PAN */ - if (ctx_bss->vif && ctx_pan->vif) { + if (priv->_agn.hw_roc_channel) { + /* both contexts must be used for this to happen */ + slot1 = priv->_agn.hw_roc_duration; + slot0 = IWL_MIN_SLOT_TIME; + } else if (ctx_bss->vif && ctx_pan->vif) { int bcnint = ctx_pan->vif->bss_conf.beacon_int; int dtim = ctx_pan->vif->bss_conf.dtim_period ?: 1; @@ -330,12 +334,12 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv) if (test_bit(STATUS_SCAN_HW, &priv->status) || (!ctx_bss->vif->bss_conf.idle && !ctx_bss->vif->bss_conf.assoc)) { - slot0 = dtim * bcnint * 3 - 20; - slot1 = 20; + slot0 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME; + slot1 = IWL_MIN_SLOT_TIME; } else if (!ctx_pan->vif->bss_conf.idle && !ctx_pan->vif->bss_conf.assoc) { - slot1 = bcnint * 3 - 20; - slot0 = 20; + slot1 = bcnint * 3 - IWL_MIN_SLOT_TIME; + slot0 = IWL_MIN_SLOT_TIME; } } else if (ctx_pan->vif) { slot0 = 0; @@ -344,8 +348,8 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv) slot1 = max_t(int, DEFAULT_BEACON_INTERVAL, slot1); if (test_bit(STATUS_SCAN_HW, &priv->status)) { - slot0 = slot1 * 3 - 20; - slot1 = 20; + slot0 = slot1 * 3 - IWL_MIN_SLOT_TIME; + slot1 = IWL_MIN_SLOT_TIME; } } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.c b/drivers/net/wireless/iwlwifi/iwl-agn-led.c index 1a24946bc203..c1190d965614 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.c @@ -63,23 +63,11 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) } /* Set led register off */ -static int iwl_led_on_reg(struct iwl_priv *priv) +void iwlagn_led_enable(struct iwl_priv *priv) { - IWL_DEBUG_LED(priv, "led on\n"); iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON); - return 0; -} - -/* Set led register off */ -static int iwl_led_off_reg(struct iwl_priv *priv) -{ - IWL_DEBUG_LED(priv, "LED Reg off\n"); - iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF); - return 0; } const struct iwl_led_ops iwlagn_led_ops = { .cmd = iwl_send_led_cmd, - .on = iwl_led_on_reg, - .off = iwl_led_off_reg, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.h b/drivers/net/wireless/iwlwifi/iwl-agn-led.h index a594e4fdc6b8..96f323dc5dd6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.h @@ -28,5 +28,6 @@ #define __iwl_agn_led_h__ extern const struct iwl_led_ops iwlagn_led_ops; +void iwlagn_led_enable(struct iwl_priv *priv); #endif /* __iwl_agn_led_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 3dee87e8f55d..3aa486437509 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -473,6 +473,11 @@ void iwlagn_rx_handler_setup(struct iwl_priv *priv) priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] = iwlagn_rx_calib_complete; priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx; + + /* set up notification wait support */ + spin_lock_init(&priv->_agn.notif_wait_lock); + INIT_LIST_HEAD(&priv->_agn.notif_waits); + init_waitqueue_head(&priv->_agn.notif_waitq); } void iwlagn_setup_deferred_work(struct iwl_priv *priv) @@ -1157,10 +1162,11 @@ void iwlagn_rx_reply_rx(struct iwl_priv *priv, /* rx_status carries information about the packet to mac80211 */ rx_status.mactime = le64_to_cpu(phy_res->timestamp); - rx_status.freq = - ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel)); rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + rx_status.freq = + ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel), + rx_status.band); rx_status.rate_idx = iwlagn_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band); rx_status.flag = 0; @@ -1389,15 +1395,12 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) u32 extra; u32 suspend_time = 100; u32 scan_suspend_time = 100; - unsigned long flags; IWL_DEBUG_INFO(priv, "Scanning while associated...\n"); - spin_lock_irqsave(&priv->lock, flags); if (priv->is_internal_short_scan) interval = 0; else interval = vif->bss_conf.beacon_int; - spin_unlock_irqrestore(&priv->lock, flags); scan->suspend_time = 0; scan->max_out_time = cpu_to_le32(200 * 1024); @@ -1857,21 +1860,6 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv) if (iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, sizeof(bt_cmd), &bt_cmd)) IWL_ERR(priv, "failed to send BT Coex Config\n"); - /* - * When we are doing a restart, need to also reconfigure BT - * SCO to the device. If not doing a restart, bt_sco_active - * will always be false, so there's no need to have an extra - * variable to check for it. - */ - if (priv->bt_sco_active) { - struct iwlagn_bt_sco_cmd sco_cmd = { .flags = 0 }; - - if (priv->bt_sco_active) - sco_cmd.flags |= IWLAGN_BT_SCO_ACTIVE; - if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_SCO, - sizeof(sco_cmd), &sco_cmd)) - IWL_ERR(priv, "failed to send BT SCO command\n"); - } } static void iwlagn_bt_traffic_change_work(struct work_struct *work) @@ -2032,7 +2020,6 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, unsigned long flags; struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_bt_coex_profile_notif *coex = &pkt->u.bt_coex_profile_notif; - struct iwlagn_bt_sco_cmd sco_cmd = { .flags = 0 }; struct iwl_bt_uart_msg *uart_msg = &coex->last_bt_uart_msg; IWL_DEBUG_NOTIF(priv, "BT Coex notification:\n"); @@ -2063,15 +2050,6 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, queue_work(priv->workqueue, &priv->bt_traffic_change_work); } - if (priv->bt_sco_active != - (uart_msg->frame3 & BT_UART_MSG_FRAME3SCOESCO_MSK)) { - priv->bt_sco_active = uart_msg->frame3 & - BT_UART_MSG_FRAME3SCOESCO_MSK; - if (priv->bt_sco_active) - sco_cmd.flags |= IWLAGN_BT_SCO_ACTIVE; - iwl_send_cmd_pdu_async(priv, REPLY_BT_COEX_SCO, - sizeof(sco_cmd), &sco_cmd, NULL); - } } iwlagn_set_kill_msk(priv, uart_msg); @@ -2389,3 +2367,44 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display) } return 0; } + +/* notification wait support */ +void iwlagn_init_notification_wait(struct iwl_priv *priv, + struct iwl_notification_wait *wait_entry, + void (*fn)(struct iwl_priv *priv, + struct iwl_rx_packet *pkt), + u8 cmd) +{ + wait_entry->fn = fn; + wait_entry->cmd = cmd; + wait_entry->triggered = false; + + spin_lock_bh(&priv->_agn.notif_wait_lock); + list_add(&wait_entry->list, &priv->_agn.notif_waits); + spin_unlock_bh(&priv->_agn.notif_wait_lock); +} + +signed long iwlagn_wait_notification(struct iwl_priv *priv, + struct iwl_notification_wait *wait_entry, + unsigned long timeout) +{ + int ret; + + ret = wait_event_timeout(priv->_agn.notif_waitq, + &wait_entry->triggered, + timeout); + + spin_lock_bh(&priv->_agn.notif_wait_lock); + list_del(&wait_entry->list); + spin_unlock_bh(&priv->_agn.notif_wait_lock); + + return ret; +} + +void iwlagn_remove_notification(struct iwl_priv *priv, + struct iwl_notification_wait *wait_entry) +{ + spin_lock_bh(&priv->_agn.notif_wait_lock); + list_del(&wait_entry->list); + spin_unlock_bh(&priv->_agn.notif_wait_lock); +} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 75fcd30a7c13..d03b4734c892 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -179,31 +179,31 @@ static s32 expected_tpt_legacy[IWL_RATE_COUNT] = { }; static s32 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = { - {0, 0, 0, 0, 42, 0, 76, 102, 124, 158, 183, 193, 202}, /* Norm */ - {0, 0, 0, 0, 46, 0, 82, 110, 132, 167, 192, 202, 210}, /* SGI */ - {0, 0, 0, 0, 48, 0, 93, 135, 176, 251, 319, 351, 381}, /* AGG */ - {0, 0, 0, 0, 53, 0, 102, 149, 193, 275, 348, 381, 413}, /* AGG+SGI */ + {0, 0, 0, 0, 42, 0, 76, 102, 124, 159, 183, 193, 202}, /* Norm */ + {0, 0, 0, 0, 46, 0, 82, 110, 132, 168, 192, 202, 210}, /* SGI */ + {0, 0, 0, 0, 47, 0, 91, 133, 171, 242, 305, 334, 362}, /* AGG */ + {0, 0, 0, 0, 52, 0, 101, 145, 187, 264, 330, 361, 390}, /* AGG+SGI */ }; static s32 expected_tpt_siso40MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 77, 0, 127, 160, 184, 220, 242, 250, 257}, /* Norm */ {0, 0, 0, 0, 83, 0, 135, 169, 193, 229, 250, 257, 264}, /* SGI */ - {0, 0, 0, 0, 96, 0, 182, 259, 328, 451, 553, 598, 640}, /* AGG */ - {0, 0, 0, 0, 106, 0, 199, 282, 357, 487, 593, 640, 683}, /* AGG+SGI */ + {0, 0, 0, 0, 94, 0, 177, 249, 313, 423, 512, 550, 586}, /* AGG */ + {0, 0, 0, 0, 104, 0, 193, 270, 338, 454, 545, 584, 620}, /* AGG+SGI */ }; static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = { - {0, 0, 0, 0, 74, 0, 123, 155, 179, 213, 235, 243, 250}, /* Norm */ - {0, 0, 0, 0, 81, 0, 131, 164, 187, 221, 242, 250, 256}, /* SGI */ - {0, 0, 0, 0, 92, 0, 175, 250, 317, 436, 534, 578, 619}, /* AGG */ - {0, 0, 0, 0, 102, 0, 192, 273, 344, 470, 573, 619, 660}, /* AGG+SGI*/ + {0, 0, 0, 0, 74, 0, 123, 155, 179, 214, 236, 244, 251}, /* Norm */ + {0, 0, 0, 0, 81, 0, 131, 164, 188, 223, 243, 251, 257}, /* SGI */ + {0, 0, 0, 0, 89, 0, 167, 235, 296, 402, 488, 526, 560}, /* AGG */ + {0, 0, 0, 0, 97, 0, 182, 255, 320, 431, 520, 558, 593}, /* AGG+SGI*/ }; static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289}, /* Norm */ {0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293}, /* SGI */ - {0, 0, 0, 0, 180, 0, 327, 446, 545, 708, 828, 878, 922}, /* AGG */ - {0, 0, 0, 0, 197, 0, 355, 481, 584, 752, 872, 922, 966}, /* AGG+SGI */ + {0, 0, 0, 0, 171, 0, 305, 410, 496, 634, 731, 771, 805}, /* AGG */ + {0, 0, 0, 0, 186, 0, 329, 439, 527, 667, 764, 803, 838}, /* AGG+SGI */ }; static s32 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = { @@ -2890,6 +2890,8 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, u8 ant_toggle_cnt = 0; u8 use_ht_possible = 1; u8 valid_tx_ant = 0; + struct iwl_station_priv *sta_priv = + container_of(lq_sta, struct iwl_station_priv, lq_sta); struct iwl_link_quality_cmd *lq_cmd = &lq_sta->lq; /* Override starting rate (index 0) if needed for debug purposes */ @@ -3008,7 +3010,8 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, repeat_rate--; } - lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF; + lq_cmd->agg_params.agg_frame_cnt_limit = + sta_priv->max_agg_bufsize ?: LINK_QUAL_AGG_FRAME_LIMIT_DEF; lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; lq_cmd->agg_params.agg_time_limit = diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 75e50d33ecb3..184828c72b31 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -213,6 +213,7 @@ enum { IWL_CCK_BASIC_RATES_MASK) #define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) +#define IWL_RATES_MASK_3945 ((1 << IWL_RATE_COUNT_3945) - 1) #define IWL_INVALID_VALUE -1 diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c index bbd40b7dd597..b192ca842f0a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c @@ -73,8 +73,7 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv) int bcn_silence_a, bcn_silence_b, bcn_silence_c; int last_rx_noise; - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) + if (iwl_bt_statistics(priv)) rx_info = &(priv->_agn.statistics_bt.rx.general.common); else rx_info = &(priv->_agn.statistics.rx.general); @@ -125,8 +124,7 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv, struct statistics_general_common *general, *accum_general; struct statistics_tx *tx, *accum_tx; - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { + if (iwl_bt_statistics(priv)) { prev_stats = (__le32 *)&priv->_agn.statistics_bt; accum_stats = (u32 *)&priv->_agn.accum_statistics_bt; size = sizeof(struct iwl_bt_notif_statistics); @@ -207,8 +205,7 @@ bool iwl_good_plcp_health(struct iwl_priv *priv, struct statistics_rx_phy *ofdm; struct statistics_rx_ht_phy *ofdm_ht; - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { + if (iwl_bt_statistics(priv)) { ofdm = &pkt->u.stats_bt.rx.ofdm; ofdm_ht = &pkt->u.stats_bt.rx.ofdm_ht; combined_plcp_delta = @@ -265,8 +262,7 @@ void iwl_rx_statistics(struct iwl_priv *priv, int change; struct iwl_rx_packet *pkt = rxb_addr(rxb); - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { + if (iwl_bt_statistics(priv)) { IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", (int)sizeof(struct iwl_bt_notif_statistics), @@ -304,8 +300,7 @@ void iwl_rx_statistics(struct iwl_priv *priv, iwl_recover_from_statistics(priv, pkt); - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) + if (iwl_bt_statistics(priv)) memcpy(&priv->_agn.statistics_bt, &pkt->u.stats_bt, sizeof(priv->_agn.statistics_bt)); else diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 6d140bd53291..6c2adc58d654 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -52,10 +52,14 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, struct iwl_rxon_context *ctx, struct iwl_rxon_cmd *send) { + struct iwl_notification_wait disable_wait; __le32 old_filter = send->filter_flags; u8 old_dev_type = send->dev_type; int ret; + iwlagn_init_notification_wait(priv, &disable_wait, NULL, + REPLY_WIPAN_DEACTIVATION_COMPLETE); + send->filter_flags &= ~RXON_FILTER_ASSOC_MSK; send->dev_type = RXON_DEV_TYPE_P2P; ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, sizeof(*send), send); @@ -63,11 +67,18 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, send->filter_flags = old_filter; send->dev_type = old_dev_type; - if (ret) + if (ret) { IWL_ERR(priv, "Error disabling PAN (%d)\n", ret); - - /* FIXME: WAIT FOR PAN DISABLE */ - msleep(300); + iwlagn_remove_notification(priv, &disable_wait); + } else { + signed long wait_res; + + wait_res = iwlagn_wait_notification(priv, &disable_wait, HZ); + if (wait_res == 0) { + IWL_ERR(priv, "Timed out waiting for PAN disable\n"); + ret = -EIO; + } + } return ret; } @@ -145,6 +156,23 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) /* always get timestamp with Rx frame */ ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK; + if (ctx->ctxid == IWL_RXON_CTX_PAN && priv->_agn.hw_roc_channel) { + struct ieee80211_channel *chan = priv->_agn.hw_roc_channel; + + iwl_set_rxon_channel(priv, chan, ctx); + iwl_set_flags_for_band(priv, ctx, chan->band, NULL); + ctx->staging.filter_flags |= + RXON_FILTER_ASSOC_MSK | + RXON_FILTER_PROMISC_MSK | + RXON_FILTER_CTL2HOST_MSK; + ctx->staging.dev_type = RXON_DEV_TYPE_P2P; + new_assoc = true; + + if (memcmp(&ctx->staging, &ctx->active, + sizeof(ctx->staging)) == 0) + return 0; + } + if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) || !(ctx->staging.flags & RXON_FLG_BAND_24G_MSK)) ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; @@ -288,10 +316,9 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) * If we issue a new RXON command which required a tune then we must * send a new TXPOWER command or we won't be able to Tx any frames. * - * FIXME: which RXON requires a tune? Can we optimise this out in - * some cases? + * It's expected we set power here if channel is changing. */ - ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); + ret = iwl_set_tx_power(priv, priv->tx_power_next, true); if (ret) { IWL_ERR(priv, "Error sending TX power (%d)\n", ret); return ret; @@ -546,12 +573,10 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, if (changes & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { - iwl_led_associate(priv); priv->timestamp = bss_conf->timestamp; ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; } else { ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_led_disassociate(priv); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 24a11b8f73bc..266490d8a397 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -539,7 +539,14 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) unsigned long flags; bool is_agg = false; - if (info->control.vif) + /* + * If the frame needs to go out off-channel, then + * we'll have put the PAN context to that channel, + * so make the frame go out there. + */ + if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) + ctx = &priv->contexts[IWL_RXON_CTX_PAN]; + else if (info->control.vif) ctx = iwl_rxon_ctx_from_vif(info->control.vif); spin_lock_irqsave(&priv->lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 24dabcd2a36c..d807e5e2b718 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -308,14 +308,6 @@ void iwlagn_init_alive_start(struct iwl_priv *priv) { int ret = 0; - /* Check alive response for "valid" sign from uCode */ - if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { - /* We had an error bringing up the hardware, so take it - * all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Initialize Alive failed.\n"); - goto restart; - } - /* initialize uCode was loaded... verify inst image. * This is a paranoid check, because we would not have gotten the * "initialize" alive if code weren't properly loaded. */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c1cfd9952e52..8ee810f5fc06 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -59,6 +59,7 @@ #include "iwl-sta.h" #include "iwl-agn-calib.h" #include "iwl-agn.h" +#include "iwl-agn-led.h" /****************************************************************************** @@ -461,8 +462,12 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv, if (palive->is_valid == UCODE_VALID_OK) queue_delayed_work(priv->workqueue, pwork, msecs_to_jiffies(5)); - else - IWL_WARN(priv, "uCode did not respond OK.\n"); + else { + IWL_WARN(priv, "%s uCode did not respond OK.\n", + (palive->ver_subtype == INITIALIZE_SUBTYPE) ? + "init" : "runtime"); + queue_work(priv->workqueue, &priv->restart); + } } static void iwl_bg_beacon_update(struct work_struct *work) @@ -699,18 +704,18 @@ static void iwl_bg_ucode_trace(unsigned long data) } } -static void iwl_rx_beacon_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwlagn_rx_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl4965_beacon_notif *beacon = - (struct iwl4965_beacon_notif *)pkt->u.raw; + struct iwlagn_beacon_notif *beacon = (void *)pkt->u.raw; #ifdef CONFIG_IWLWIFI_DEBUG + u16 status = le16_to_cpu(beacon->beacon_notify_hdr.status.status); u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); - IWL_DEBUG_RX(priv, "beacon status %x retries %d iss %d " - "tsf %d %d rate %d\n", - le32_to_cpu(beacon->beacon_notify_hdr.u.status) & TX_STATUS_MSK, + IWL_DEBUG_RX(priv, "beacon status %#x, retries:%d ibssmgr:%d " + "tsf:0x%.8x%.8x rate:%d\n", + status & TX_STATUS_MSK, beacon->beacon_notify_hdr.failure_frame, le32_to_cpu(beacon->ibss_mgr_status), le32_to_cpu(beacon->high_tsf), @@ -813,7 +818,7 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv) priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = iwl_rx_pm_debug_statistics_notif; - priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif; + priv->rx_handlers[BEACON_NOTIFICATION] = iwlagn_rx_beacon_notif; /* * The same handler is used for both the REPLY to a discrete @@ -846,7 +851,7 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv) * the appropriate handlers, including command responses, * frame-received notifications, and other notifications. */ -void iwl_rx_handle(struct iwl_priv *priv) +static void iwl_rx_handle(struct iwl_priv *priv) { struct iwl_rx_mem_buffer *rxb; struct iwl_rx_packet *pkt; @@ -910,6 +915,27 @@ void iwl_rx_handle(struct iwl_priv *priv) (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && (pkt->hdr.cmd != REPLY_TX); + /* + * Do the notification wait before RX handlers so + * even if the RX handler consumes the RXB we have + * access to it in the notification wait entry. + */ + if (!list_empty(&priv->_agn.notif_waits)) { + struct iwl_notification_wait *w; + + spin_lock(&priv->_agn.notif_wait_lock); + list_for_each_entry(w, &priv->_agn.notif_waits, list) { + if (w->cmd == pkt->hdr.cmd) { + w->triggered = true; + if (w->fn) + w->fn(priv, pkt); + } + } + spin_unlock(&priv->_agn.notif_wait_lock); + + wake_up_all(&priv->_agn.notif_waitq); + } + /* Based on type of command response or notification, * handle those that need handling via function in * rx_handlers table. See iwl_setup_rx_handlers() */ @@ -2632,13 +2658,6 @@ static void iwl_alive_start(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); - if (priv->card_alive.is_valid != UCODE_VALID_OK) { - /* We had an error bringing up the hardware, so take it - * all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Alive failed.\n"); - goto restart; - } - /* Initialize uCode has loaded Runtime uCode ... verify inst image. * This is a paranoid check, because we would not have gotten the * "runtime" alive if code weren't properly loaded. */ @@ -2726,8 +2745,6 @@ static void iwl_alive_start(struct iwl_priv *priv) /* At this point, the NIC is initialized and operational */ iwl_rf_kill_ct_config(priv); - iwl_leds_init(priv); - IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n"); wake_up_interruptible(&priv->wait_command_queue); @@ -2769,7 +2786,6 @@ static void __iwl_down(struct iwl_priv *priv) priv->cfg->bt_params->bt_init_traffic_load; else priv->bt_traffic_load = 0; - priv->bt_sco_active = false; priv->bt_full_concurrent = false; priv->bt_ci_compliance = 0; @@ -3063,8 +3079,7 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work) } if (priv->start_calib) { - if (priv->cfg->bt_params && - priv->cfg->bt_params->bt_statistics) { + if (iwl_bt_statistics(priv)) { iwl_chain_noise_calibration(priv, (void *)&priv->_agn.statistics_bt); iwl_sensitivity_calibration(priv, @@ -3089,7 +3104,7 @@ static void iwl_bg_restart(struct work_struct *data) if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) { struct iwl_rxon_context *ctx; - bool bt_sco, bt_full_concurrent; + bool bt_full_concurrent; u8 bt_ci_compliance; u8 bt_load; u8 bt_status; @@ -3108,7 +3123,6 @@ static void iwl_bg_restart(struct work_struct *data) * re-configure the hw when we reconfigure the BT * command. */ - bt_sco = priv->bt_sco_active; bt_full_concurrent = priv->bt_full_concurrent; bt_ci_compliance = priv->bt_ci_compliance; bt_load = priv->bt_traffic_load; @@ -3116,7 +3130,6 @@ static void iwl_bg_restart(struct work_struct *data) __iwl_down(priv); - priv->bt_sco_active = bt_sco; priv->bt_full_concurrent = bt_full_concurrent; priv->bt_ci_compliance = bt_ci_compliance; priv->bt_traffic_load = bt_load; @@ -3178,6 +3191,8 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, IEEE80211_HW_SPECTRUM_MGMT | IEEE80211_HW_REPORTS_TX_ACK_STATUS; + hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF; + if (!priv->cfg->base_params->broken_powersave) hw->flags |= IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS; @@ -3194,8 +3209,11 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, hw->wiphy->interface_modes |= ctx->exclusive_interface_modes; } + hw->wiphy->max_remain_on_channel_duration = 1000; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | - WIPHY_FLAG_DISABLE_BEACON_HINTS; + WIPHY_FLAG_DISABLE_BEACON_HINTS | + WIPHY_FLAG_IBSS_RSN; /* * For now, disable PS by default because it affects @@ -3219,6 +3237,8 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->bands[IEEE80211_BAND_5GHZ]; + iwl_leds_init(priv); + ret = ieee80211_register_hw(priv->hw); if (ret) { IWL_ERR(priv, "Failed to register hw (error %d)\n", ret); @@ -3263,7 +3283,7 @@ int iwlagn_mac_start(struct ieee80211_hw *hw) } } - iwl_led_start(priv); + iwlagn_led_enable(priv); out: priv->is_open = 1; @@ -3345,6 +3365,14 @@ int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return -EOPNOTSUPP; } + /* + * To support IBSS RSN, don't program group keys in IBSS, the + * hardware will then not attempt to decrypt the frames. + */ + if (vif->type == NL80211_IFTYPE_ADHOC && + !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + return -EOPNOTSUPP; + sta_id = iwl_sta_id_or_broadcast(priv, vif_priv->ctx, sta); if (sta_id == IWL_INVALID_STATION) return -EINVAL; @@ -3399,10 +3427,12 @@ int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn) + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size) { struct iwl_priv *priv = hw->priv; int ret = -EINVAL; + struct iwl_station_priv *sta_priv = (void *) sta->drv_priv; IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n", sta->addr, tid); @@ -3457,11 +3487,28 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, } break; case IEEE80211_AMPDU_TX_OPERATIONAL: + /* + * If the limit is 0, then it wasn't initialised yet, + * use the default. We can do that since we take the + * minimum below, and we don't want to go above our + * default due to hardware restrictions. + */ + if (sta_priv->max_agg_bufsize == 0) + sta_priv->max_agg_bufsize = + LINK_QUAL_AGG_FRAME_LIMIT_DEF; + + /* + * Even though in theory the peer could have different + * aggregation reorder buffer sizes for different sessions, + * our ucode doesn't allow for that and has a global limit + * for each station. Therefore, use the minimum of all the + * aggregation sessions and our default value. + */ + sta_priv->max_agg_bufsize = + min(sta_priv->max_agg_bufsize, buf_size); + if (priv->cfg->ht_params && priv->cfg->ht_params->use_rts_for_aggregation) { - struct iwl_station_priv *sta_priv = - (void *) sta->drv_priv; - /* * switch to RTS/CTS if it is the prefer protection * method for HT traffic @@ -3469,9 +3516,13 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, sta_priv->lq_sta.lq.general_params.flags |= LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK; - iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif), - &sta_priv->lq_sta.lq, CMD_ASYNC, false); } + + sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit = + sta_priv->max_agg_bufsize; + + iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif), + &sta_priv->lq_sta.lq, CMD_ASYNC, false); ret = 0; break; } @@ -3709,6 +3760,97 @@ done: IWL_DEBUG_MAC80211(priv, "leave\n"); } +static void iwlagn_disable_roc(struct iwl_priv *priv) +{ + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN]; + struct ieee80211_channel *chan = ACCESS_ONCE(priv->hw->conf.channel); + + lockdep_assert_held(&priv->mutex); + + if (!ctx->is_active) + return; + + ctx->staging.dev_type = RXON_DEV_TYPE_2STA; + ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl_set_rxon_channel(priv, chan, ctx); + iwl_set_flags_for_band(priv, ctx, chan->band, NULL); + + priv->_agn.hw_roc_channel = NULL; + + iwlcore_commit_rxon(priv, ctx); + + ctx->is_active = false; +} + +static void iwlagn_bg_roc_done(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, + _agn.hw_roc_work.work); + + mutex_lock(&priv->mutex); + ieee80211_remain_on_channel_expired(priv->hw); + iwlagn_disable_roc(priv); + mutex_unlock(&priv->mutex); +} + +#ifdef CONFIG_IWL5000 +static int iwl_mac_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_channel *channel, + enum nl80211_channel_type channel_type, + int duration) +{ + struct iwl_priv *priv = hw->priv; + int err = 0; + + if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) + return -EOPNOTSUPP; + + if (!(priv->contexts[IWL_RXON_CTX_PAN].interface_modes & + BIT(NL80211_IFTYPE_P2P_CLIENT))) + return -EOPNOTSUPP; + + mutex_lock(&priv->mutex); + + if (priv->contexts[IWL_RXON_CTX_PAN].is_active || + test_bit(STATUS_SCAN_HW, &priv->status)) { + err = -EBUSY; + goto out; + } + + priv->contexts[IWL_RXON_CTX_PAN].is_active = true; + priv->_agn.hw_roc_channel = channel; + priv->_agn.hw_roc_chantype = channel_type; + priv->_agn.hw_roc_duration = DIV_ROUND_UP(duration * 1000, 1024); + iwlcore_commit_rxon(priv, &priv->contexts[IWL_RXON_CTX_PAN]); + queue_delayed_work(priv->workqueue, &priv->_agn.hw_roc_work, + msecs_to_jiffies(duration + 20)); + + msleep(IWL_MIN_SLOT_TIME); /* TU is almost ms */ + ieee80211_ready_on_channel(priv->hw); + + out: + mutex_unlock(&priv->mutex); + + return err; +} + +static int iwl_mac_cancel_remain_on_channel(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + + if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) + return -EOPNOTSUPP; + + cancel_delayed_work_sync(&priv->_agn.hw_roc_work); + + mutex_lock(&priv->mutex); + iwlagn_disable_roc(priv); + mutex_unlock(&priv->mutex); + + return 0; +} +#endif + /***************************************************************************** * * driver setup and teardown @@ -3730,6 +3872,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config); INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); + INIT_DELAYED_WORK(&priv->_agn.hw_roc_work, iwlagn_bg_roc_done); iwl_setup_scan_deferred_work(priv); @@ -3898,6 +4041,8 @@ struct ieee80211_ops iwlagn_hw_ops = { .channel_switch = iwlagn_mac_channel_switch, .flush = iwlagn_mac_flush, .tx_last_beacon = iwl_mac_tx_last_beacon, + .remain_on_channel = iwl_mac_remain_on_channel, + .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel, }; #endif @@ -4025,6 +4170,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE; priv->contexts[IWL_RXON_CTX_PAN].interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP); +#ifdef CONFIG_IWL_P2P + priv->contexts[IWL_RXON_CTX_PAN].interface_modes |= + BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); +#endif priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP; priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA; priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P; @@ -4272,6 +4421,9 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) * we need to set STATUS_EXIT_PENDING bit. */ set_bit(STATUS_EXIT_PENDING, &priv->status); + + iwl_leds_exit(priv); + if (priv->mac80211_registered) { ieee80211_unregister_hw(priv->hw); priv->mac80211_registered = 0; @@ -4492,6 +4644,49 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x0896, 0x5025, iwl130_bgn_cfg)}, {IWL_PCI_DEVICE(0x0896, 0x5027, iwl130_bg_cfg)}, +/* 2x00 Series */ + {IWL_PCI_DEVICE(0x0890, 0x4022, iwl2000_2bgn_cfg)}, + {IWL_PCI_DEVICE(0x0891, 0x4222, iwl2000_2bgn_cfg)}, + {IWL_PCI_DEVICE(0x0890, 0x4422, iwl2000_2bgn_cfg)}, + {IWL_PCI_DEVICE(0x0890, 0x4026, iwl2000_2bg_cfg)}, + {IWL_PCI_DEVICE(0x0891, 0x4226, iwl2000_2bg_cfg)}, + {IWL_PCI_DEVICE(0x0890, 0x4426, iwl2000_2bg_cfg)}, + +/* 2x30 Series */ + {IWL_PCI_DEVICE(0x0887, 0x4062, iwl2030_2bgn_cfg)}, + {IWL_PCI_DEVICE(0x0888, 0x4262, iwl2030_2bgn_cfg)}, + {IWL_PCI_DEVICE(0x0887, 0x4462, iwl2030_2bgn_cfg)}, + {IWL_PCI_DEVICE(0x0887, 0x4066, iwl2030_2bg_cfg)}, + {IWL_PCI_DEVICE(0x0888, 0x4266, iwl2030_2bg_cfg)}, + {IWL_PCI_DEVICE(0x0887, 0x4466, iwl2030_2bg_cfg)}, + +/* 6x35 Series */ + {IWL_PCI_DEVICE(0x088E, 0x4060, iwl6035_2agn_cfg)}, + {IWL_PCI_DEVICE(0x088F, 0x4260, iwl6035_2agn_cfg)}, + {IWL_PCI_DEVICE(0x088E, 0x4460, iwl6035_2agn_cfg)}, + {IWL_PCI_DEVICE(0x088E, 0x4064, iwl6035_2abg_cfg)}, + {IWL_PCI_DEVICE(0x088F, 0x4264, iwl6035_2abg_cfg)}, + {IWL_PCI_DEVICE(0x088E, 0x4464, iwl6035_2abg_cfg)}, + {IWL_PCI_DEVICE(0x088E, 0x4066, iwl6035_2bg_cfg)}, + {IWL_PCI_DEVICE(0x088F, 0x4266, iwl6035_2bg_cfg)}, + {IWL_PCI_DEVICE(0x088E, 0x4466, iwl6035_2bg_cfg)}, + +/* 200 Series */ + {IWL_PCI_DEVICE(0x0894, 0x0022, iwl200_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0895, 0x0222, iwl200_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0894, 0x0422, iwl200_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0894, 0x0026, iwl200_bg_cfg)}, + {IWL_PCI_DEVICE(0x0895, 0x0226, iwl200_bg_cfg)}, + {IWL_PCI_DEVICE(0x0894, 0x0426, iwl200_bg_cfg)}, + +/* 230 Series */ + {IWL_PCI_DEVICE(0x0892, 0x0062, iwl230_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0893, 0x0262, iwl230_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0892, 0x0462, iwl230_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0892, 0x0066, iwl230_bg_cfg)}, + {IWL_PCI_DEVICE(0x0893, 0x0266, iwl230_bg_cfg)}, + {IWL_PCI_DEVICE(0x0892, 0x0466, iwl230_bg_cfg)}, + #endif /* CONFIG_IWL5000 */ {0} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index da303585f801..d00e1ea50a8d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -96,6 +96,17 @@ extern struct iwl_cfg iwl100_bgn_cfg; extern struct iwl_cfg iwl100_bg_cfg; extern struct iwl_cfg iwl130_bgn_cfg; extern struct iwl_cfg iwl130_bg_cfg; +extern struct iwl_cfg iwl2000_2bgn_cfg; +extern struct iwl_cfg iwl2000_2bg_cfg; +extern struct iwl_cfg iwl2030_2bgn_cfg; +extern struct iwl_cfg iwl2030_2bg_cfg; +extern struct iwl_cfg iwl6035_2agn_cfg; +extern struct iwl_cfg iwl6035_2abg_cfg; +extern struct iwl_cfg iwl6035_2bg_cfg; +extern struct iwl_cfg iwl200_bg_cfg; +extern struct iwl_cfg iwl200_bgn_cfg; +extern struct iwl_cfg iwl230_bg_cfg; +extern struct iwl_cfg iwl230_bgn_cfg; extern struct iwl_mod_params iwlagn_mod_params; extern struct iwl_hcmd_ops iwlagn_hcmd; @@ -185,7 +196,6 @@ void iwlagn_rx_reply_rx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); void iwlagn_rx_reply_rx_phy(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); -void iwl_rx_handle(struct iwl_priv *priv); /* tx */ void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); @@ -330,6 +340,21 @@ void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac); int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv); void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv); +/* notification wait support */ +void __acquires(wait_entry) +iwlagn_init_notification_wait(struct iwl_priv *priv, + struct iwl_notification_wait *wait_entry, + void (*fn)(struct iwl_priv *priv, + struct iwl_rx_packet *pkt), + u8 cmd); +signed long __releases(wait_entry) +iwlagn_wait_notification(struct iwl_priv *priv, + struct iwl_notification_wait *wait_entry, + unsigned long timeout); +void __releases(wait_entry) +iwlagn_remove_notification(struct iwl_priv *priv, + struct iwl_notification_wait *wait_entry); + /* mac80211 handlers (for 4965) */ int iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb); int iwlagn_mac_start(struct ieee80211_hw *hw); @@ -349,7 +374,8 @@ void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn); + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size); int iwlagn_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index f893d4a6aa87..0a1d4aeb36aa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -178,7 +178,6 @@ enum { REPLY_BT_COEX_PRIO_TABLE = 0xcc, REPLY_BT_COEX_PROT_ENV = 0xcd, REPLY_BT_COEX_PROFILE_NOTIF = 0xce, - REPLY_BT_COEX_SCO = 0xcf, /* PAN commands */ REPLY_WIPAN_PARAMS = 0xb2, @@ -189,6 +188,7 @@ enum { REPLY_WIPAN_WEPKEY = 0xb8, /* use REPLY_WEPKEY structure */ REPLY_WIPAN_P2P_CHANNEL_SWITCH = 0xb9, REPLY_WIPAN_NOA_NOTIFICATION = 0xbc, + REPLY_WIPAN_DEACTIVATION_COMPLETE = 0xbd, REPLY_MAX = 0xff }; @@ -3082,6 +3082,13 @@ struct iwl4965_beacon_notif { __le32 ibss_mgr_status; } __packed; +struct iwlagn_beacon_notif { + struct iwlagn_tx_resp beacon_notify_hdr; + __le32 low_tsf; + __le32 high_tsf; + __le32 ibss_mgr_status; +} __packed; + /* * REPLY_TX_BEACON = 0x91 (command, has simple generic response) */ @@ -4369,6 +4376,11 @@ int iwl_agn_check_rxon_cmd(struct iwl_priv *priv); * REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification) */ +/* + * Minimum slot time in TU + */ +#define IWL_MIN_SLOT_TIME 20 + /** * struct iwl_wipan_slot * @width: Time in TU diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index efbde1f1a8bf..4ad89389a0a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -219,15 +219,12 @@ int iwlcore_init_geos(struct iwl_priv *priv) if (!is_channel_valid(ch)) continue; - if (is_channel_a_band(ch)) - sband = &priv->bands[IEEE80211_BAND_5GHZ]; - else - sband = &priv->bands[IEEE80211_BAND_2GHZ]; + sband = &priv->bands[ch->band]; geo_ch = &sband->channels[sband->n_channels++]; geo_ch->center_freq = - ieee80211_channel_to_frequency(ch->channel); + ieee80211_channel_to_frequency(ch->channel, ch->band); geo_ch->max_power = ch->max_power_avg; geo_ch->max_antenna_gain = 0xff; geo_ch->hw_value = ch->channel; @@ -1161,6 +1158,8 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) { int ret; s8 prev_tx_power; + bool defer; + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; lockdep_assert_held(&priv->mutex); @@ -1188,10 +1187,15 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) if (!iwl_is_ready_rf(priv)) return -EIO; - /* scan complete use tx_power_next, need to be updated */ + /* scan complete and commit_rxon use tx_power_next value, + * it always need to be updated for newest request */ priv->tx_power_next = tx_power; - if (test_bit(STATUS_SCANNING, &priv->status) && !force) { - IWL_DEBUG_INFO(priv, "Deferring tx power set while scanning\n"); + + /* do not set tx power when scanning or channel changing */ + defer = test_bit(STATUS_SCANNING, &priv->status) || + memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging)); + if (defer && !force) { + IWL_DEBUG_INFO(priv, "Deferring tx power set\n"); return 0; } @@ -1403,9 +1407,10 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; struct iwl_rxon_context *tmp, *ctx = NULL; int err; + enum nl80211_iftype viftype = ieee80211_vif_type_p2p(vif); IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n", - vif->type, vif->addr); + viftype, vif->addr); mutex_lock(&priv->mutex); @@ -1429,7 +1434,7 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) continue; } - if (!(possible_modes & BIT(vif->type))) + if (!(possible_modes & BIT(viftype))) continue; /* have maybe usable context w/o interface */ @@ -1675,7 +1680,6 @@ void iwl_clear_traffic_stats(struct iwl_priv *priv) { memset(&priv->tx_stats, 0, sizeof(struct traffic_stats)); memset(&priv->rx_stats, 0, sizeof(struct traffic_stats)); - priv->led_tpt = 0; } /* @@ -1768,7 +1772,6 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) stats->data_cnt++; stats->data_bytes += len; } - iwl_leds_background(priv); } EXPORT_SYMBOL(iwl_update_stats); #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a3474376fdbc..e0ec17079dc0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -227,8 +227,6 @@ struct iwl_lib_ops { struct iwl_led_ops { int (*cmd)(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd); - int (*on)(struct iwl_priv *priv); - int (*off)(struct iwl_priv *priv); }; /* NIC specific ops */ @@ -307,7 +305,6 @@ struct iwl_base_params { u16 led_compensation; const bool broken_powersave; int chain_noise_num_beacons; - const bool supports_idle; bool adv_thermal_throttle; bool support_ct_kill_exit; const bool support_wimax_coexist; @@ -366,6 +363,7 @@ struct iwl_ht_params { * @adv_pm: advance power management * @rx_with_siso_diversity: 1x1 device with rx antenna diversity * @internal_wimax_coex: internal wifi/wimax combo device + * @iq_invert: I/Q inversion * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -415,6 +413,7 @@ struct iwl_cfg { const bool adv_pm; const bool rx_with_siso_diversity; const bool internal_wimax_coex; + const bool iq_invert; }; /*************************** @@ -494,18 +493,6 @@ static inline void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) { - struct traffic_stats *stats; - - if (is_tx) - stats = &priv->tx_stats; - else - stats = &priv->rx_stats; - - if (ieee80211_is_data(fc)) { - /* data */ - stats->data_bytes += len; - } - iwl_leds_background(priv); } #endif /***************************************************** @@ -755,6 +742,17 @@ static inline const struct ieee80211_supported_band *iwl_get_hw_mode( return priv->hw->wiphy->bands[band]; } +static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv) +{ + return priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist; +} + +static inline bool iwl_bt_statistics(struct iwl_priv *priv) +{ + return priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics; +} + extern bool bt_coex_active; extern bool bt_siso_mode; diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index b80bf7dff55b..f52bc040bcbf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -290,7 +290,7 @@ /* HW REV */ -#define CSR_HW_REV_TYPE_MSK (0x00000F0) +#define CSR_HW_REV_TYPE_MSK (0x00001F0) #define CSR_HW_REV_TYPE_3945 (0x00000D0) #define CSR_HW_REV_TYPE_4965 (0x0000000) #define CSR_HW_REV_TYPE_5300 (0x0000020) @@ -300,9 +300,15 @@ #define CSR_HW_REV_TYPE_1000 (0x0000060) #define CSR_HW_REV_TYPE_6x00 (0x0000070) #define CSR_HW_REV_TYPE_6x50 (0x0000080) -#define CSR_HW_REV_TYPE_6x50g2 (0x0000084) -#define CSR_HW_REV_TYPE_6x00g2 (0x00000B0) -#define CSR_HW_REV_TYPE_NONE (0x00000F0) +#define CSR_HW_REV_TYPE_6150 (0x0000084) +#define CSR_HW_REV_TYPE_6x05 (0x00000B0) +#define CSR_HW_REV_TYPE_6x30 CSR_HW_REV_TYPE_6x05 +#define CSR_HW_REV_TYPE_6x35 CSR_HW_REV_TYPE_6x05 +#define CSR_HW_REV_TYPE_2x30 (0x00000C0) +#define CSR_HW_REV_TYPE_2x00 (0x0000100) +#define CSR_HW_REV_TYPE_200 (0x0000110) +#define CSR_HW_REV_TYPE_230 (0x0000120) +#define CSR_HW_REV_TYPE_NONE (0x00001F0) /* EEPROM REG */ #define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) @@ -376,6 +382,8 @@ #define CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6 (0x00000004) #define CSR_GP_DRIVER_REG_BIT_6050_1x2 (0x00000008) +#define CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER (0x00000080) + /* GIO Chicken Bits (PCI Express bus link power management) */ #define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) #define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 6fe80b5e7a15..bc7a965c18f9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -207,18 +207,19 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, return ret; } -#define BYTE1_MASK 0x000000ff; -#define BYTE2_MASK 0x0000ffff; -#define BYTE3_MASK 0x00ffffff; static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - u32 val; + u32 val = 0; char *buf; ssize_t ret; - int i; + int i = 0; + bool device_format = false; + int offset = 0; + int len = 0; int pos = 0; + int sram; struct iwl_priv *priv = file->private_data; size_t bufsz; @@ -230,35 +231,62 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, else priv->dbgfs_sram_len = priv->ucode_data.len; } - bufsz = 30 + priv->dbgfs_sram_len * sizeof(char) * 10; + len = priv->dbgfs_sram_len; + + if (len == -4) { + device_format = true; + len = 4; + } + + bufsz = 50 + len * 4; buf = kmalloc(bufsz, GFP_KERNEL); if (!buf) return -ENOMEM; + pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n", - priv->dbgfs_sram_len); + len); pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n", priv->dbgfs_sram_offset); - for (i = priv->dbgfs_sram_len; i > 0; i -= 4) { - val = iwl_read_targ_mem(priv, priv->dbgfs_sram_offset + \ - priv->dbgfs_sram_len - i); - if (i < 4) { - switch (i) { - case 1: - val &= BYTE1_MASK; - break; - case 2: - val &= BYTE2_MASK; - break; - case 3: - val &= BYTE3_MASK; - break; - } + + /* adjust sram address since reads are only on even u32 boundaries */ + offset = priv->dbgfs_sram_offset & 0x3; + sram = priv->dbgfs_sram_offset & ~0x3; + + /* read the first u32 from sram */ + val = iwl_read_targ_mem(priv, sram); + + for (; len; len--) { + /* put the address at the start of every line */ + if (i == 0) + pos += scnprintf(buf + pos, bufsz - pos, + "%08X: ", sram + offset); + + if (device_format) + pos += scnprintf(buf + pos, bufsz - pos, + "%02x", (val >> (8 * (3 - offset))) & 0xff); + else + pos += scnprintf(buf + pos, bufsz - pos, + "%02x ", (val >> (8 * offset)) & 0xff); + + /* if all bytes processed, read the next u32 from sram */ + if (++offset == 4) { + sram += 4; + offset = 0; + val = iwl_read_targ_mem(priv, sram); } - if (!(i % 16)) + + /* put in extra spaces and split lines for human readability */ + if (++i == 16) { + i = 0; pos += scnprintf(buf + pos, bufsz - pos, "\n"); - pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val); + } else if (!(i & 7)) { + pos += scnprintf(buf + pos, bufsz - pos, " "); + } else if (!(i & 3)) { + pos += scnprintf(buf + pos, bufsz - pos, " "); + } } - pos += scnprintf(buf + pos, bufsz - pos, "\n"); + if (i) + pos += scnprintf(buf + pos, bufsz - pos, "\n"); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); @@ -282,6 +310,9 @@ static ssize_t iwl_dbgfs_sram_write(struct file *file, if (sscanf(buf, "%x,%x", &offset, &len) == 2) { priv->dbgfs_sram_offset = offset; priv->dbgfs_sram_len = len; + } else if (sscanf(buf, "%x", &offset) == 1) { + priv->dbgfs_sram_offset = offset; + priv->dbgfs_sram_len = -4; } else { priv->dbgfs_sram_offset = 0; priv->dbgfs_sram_len = 0; @@ -668,29 +699,6 @@ static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } -static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - int pos = 0; - char buf[256]; - const size_t bufsz = sizeof(buf); - - pos += scnprintf(buf + pos, bufsz - pos, - "allow blinking: %s\n", - (priv->allow_blinking) ? "True" : "False"); - if (priv->allow_blinking) { - pos += scnprintf(buf + pos, bufsz - pos, - "Led blinking rate: %u\n", - priv->last_blink_rate); - pos += scnprintf(buf + pos, bufsz - pos, - "Last blink time: %lu\n", - priv->last_blink_time); - } - - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); -} - static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -856,7 +864,6 @@ DEBUGFS_READ_FILE_OPS(channels); DEBUGFS_READ_FILE_OPS(status); DEBUGFS_READ_WRITE_FILE_OPS(interrupt); DEBUGFS_READ_FILE_OPS(qos); -DEBUGFS_READ_FILE_OPS(led); DEBUGFS_READ_FILE_OPS(thermal_throttling); DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40); DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override); @@ -1580,10 +1587,9 @@ static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file, "last traffic notif: %d\n", priv->bt_status ? "On" : "Off", priv->last_bt_traffic_load); pos += scnprintf(buf + pos, bufsz - pos, "ch_announcement: %d, " - "sco_active: %d, kill_ack_mask: %x, " - "kill_cts_mask: %x\n", - priv->bt_ch_announce, priv->bt_sco_active, - priv->kill_ack_mask, priv->kill_cts_mask); + "kill_ack_mask: %x, kill_cts_mask: %x\n", + priv->bt_ch_announce, priv->kill_ack_mask, + priv->kill_cts_mask); pos += scnprintf(buf + pos, bufsz - pos, "bluetooth traffic load: "); switch (priv->bt_traffic_load) { @@ -1725,7 +1731,6 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR); DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(led, dir_data, S_IRUSR); if (!priv->cfg->base_params->broken_powersave) { DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR); @@ -1759,13 +1764,13 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR); if (priv->cfg->base_params->ucode_tracing) DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR); - if (priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics) + if (iwl_bt_statistics(priv)) DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR); - if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist) + if (iwl_advanced_bt_coexist(priv)) DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR); if (priv->cfg->base_params->sensitivity_calib_by_driver) DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 8dda67850af4..ecfbef402781 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -34,6 +34,8 @@ #include <linux/pci.h> /* for struct pci_device_id */ #include <linux/kernel.h> +#include <linux/wait.h> +#include <linux/leds.h> #include <net/ieee80211_radiotap.h> #include "iwl-eeprom.h" @@ -136,7 +138,7 @@ struct iwl_queue { * space more than this */ int high_mark; /* high watermark, stop queue if free * space less than this */ -} __packed; +}; /* One for each TFD */ struct iwl_tx_info { @@ -507,6 +509,7 @@ struct iwl_station_priv { atomic_t pending_frames; bool client; bool asleep; + u8 max_agg_bufsize; }; /** @@ -995,7 +998,6 @@ struct reply_agg_tx_error_statistics { u32 unknown; }; -#ifdef CONFIG_IWLWIFI_DEBUGFS /* management statistics */ enum iwl_mgmt_stats { MANAGEMENT_ASSOC_REQ = 0, @@ -1026,16 +1028,13 @@ enum iwl_ctrl_stats { }; struct traffic_stats { +#ifdef CONFIG_IWLWIFI_DEBUGFS u32 mgmt[MANAGEMENT_MAX]; u32 ctrl[CONTROL_MAX]; u32 data_cnt; u64 data_bytes; -}; -#else -struct traffic_stats { - u64 data_bytes; -}; #endif +}; /* * iwl_switch_rxon: "channel switch" structure @@ -1139,6 +1138,33 @@ struct iwl_force_reset { */ #define IWLAGN_EXT_BEACON_TIME_POS 22 +/** + * struct iwl_notification_wait - notification wait entry + * @list: list head for global list + * @fn: function called with the notification + * @cmd: command ID + * + * This structure is not used directly, to wait for a + * notification declare it on the stack, and call + * iwlagn_init_notification_wait() with appropriate + * parameters. Then do whatever will cause the ucode + * to notify the driver, and to wait for that then + * call iwlagn_wait_notification(). + * + * Each notification is one-shot. If at some point we + * need to support multi-shot notifications (which + * can't be allocated on the stack) we need to modify + * the code for them. + */ +struct iwl_notification_wait { + struct list_head list; + + void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt); + + u8 cmd; + bool triggered; +}; + enum iwl_rxon_context_id { IWL_RXON_CTX_BSS, IWL_RXON_CTX_PAN, @@ -1310,11 +1336,6 @@ struct iwl_priv { struct iwl_init_alive_resp card_alive_init; struct iwl_alive_resp card_alive; - unsigned long last_blink_time; - u8 last_blink_rate; - u8 allow_blinking; - u64 led_tpt; - u16 active_rate; u8 start_calib; @@ -1463,6 +1484,17 @@ struct iwl_priv { struct iwl_bt_notif_statistics delta_statistics_bt; struct iwl_bt_notif_statistics max_delta_bt; #endif + + /* notification wait support */ + struct list_head notif_waits; + spinlock_t notif_wait_lock; + wait_queue_head_t notif_waitq; + + /* remain-on-channel offload support */ + struct ieee80211_channel *hw_roc_channel; + struct delayed_work hw_roc_work; + enum nl80211_channel_type hw_roc_chantype; + int hw_roc_duration; } _agn; #endif }; @@ -1472,7 +1504,6 @@ struct iwl_priv { u8 bt_status; u8 bt_traffic_load, last_bt_traffic_load; bool bt_ch_announce; - bool bt_sco_active; bool bt_full_concurrent; bool bt_ant_couple_ok; __le32 kill_ack_mask; @@ -1547,6 +1578,10 @@ struct iwl_priv { bool hw_ready; struct iwl_event_log event_log; + + struct led_classdev led; + unsigned long blink_on, blink_off; + bool led_registered; }; /*iwl_priv */ static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id) diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 9e6f31355eee..98aa8af01192 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -247,13 +247,26 @@ struct iwl_eeprom_enhanced_txpwr { #define EEPROM_6050_TX_POWER_VERSION (4) #define EEPROM_6050_EEPROM_VERSION (0x532) -/* 6x50g2 Specific */ -#define EEPROM_6050G2_TX_POWER_VERSION (6) -#define EEPROM_6050G2_EEPROM_VERSION (0x553) +/* 6150 Specific */ +#define EEPROM_6150_TX_POWER_VERSION (6) +#define EEPROM_6150_EEPROM_VERSION (0x553) + +/* 6x05 Specific */ +#define EEPROM_6005_TX_POWER_VERSION (6) +#define EEPROM_6005_EEPROM_VERSION (0x709) + +/* 6x30 Specific */ +#define EEPROM_6030_TX_POWER_VERSION (6) +#define EEPROM_6030_EEPROM_VERSION (0x709) + +/* 2x00 Specific */ +#define EEPROM_2000_TX_POWER_VERSION (6) +#define EEPROM_2000_EEPROM_VERSION (0x805) + +/* 6x35 Specific */ +#define EEPROM_6035_TX_POWER_VERSION (6) +#define EEPROM_6035_EEPROM_VERSION (0x753) -/* 6x00g2 Specific */ -#define EEPROM_6000G2_TX_POWER_VERSION (6) -#define EEPROM_6000G2_EEPROM_VERSION (0x709) /* OTP */ /* lower blocks contain EEPROM image and calibration data */ @@ -264,6 +277,7 @@ struct iwl_eeprom_enhanced_txpwr { #define OTP_MAX_LL_ITEMS_1000 (3) /* OTP blocks for 1000 */ #define OTP_MAX_LL_ITEMS_6x00 (4) /* OTP blocks for 6x00 */ #define OTP_MAX_LL_ITEMS_6x50 (7) /* OTP blocks for 6x50 */ +#define OTP_MAX_LL_ITEMS_2x00 (4) /* OTP blocks for 2x00 */ /* 2.4 GHz */ extern const u8 iwl_eeprom_band_1[14]; diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index c373b53babea..e4b953d7b7bf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -108,6 +108,7 @@ const char *get_cmd_string(u8 cmd) IWL_CMD(REPLY_WIPAN_WEPKEY); IWL_CMD(REPLY_WIPAN_P2P_CHANNEL_SWITCH); IWL_CMD(REPLY_WIPAN_NOA_NOTIFICATION); + IWL_CMD(REPLY_WIPAN_DEACTIVATION_COMPLETE); default: return "UNKNOWN"; diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 46ccdf406e8e..074ad2275228 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -48,31 +48,19 @@ module_param(led_mode, int, S_IRUGO); MODULE_PARM_DESC(led_mode, "0=system default, " "1=On(RF On)/Off(RF Off), 2=blinking"); -static const struct { - u16 tpt; /* Mb/s */ - u8 on_time; - u8 off_time; -} blink_tbl[] = -{ - {300, 25, 25}, - {200, 40, 40}, - {100, 55, 55}, - {70, 65, 65}, - {50, 75, 75}, - {20, 85, 85}, - {10, 95, 95}, - {5, 110, 110}, - {1, 130, 130}, - {0, 167, 167}, - /* SOLID_ON */ - {-1, IWL_LED_SOLID, 0} +static const struct ieee80211_tpt_blink iwl_blink[] = { + { .throughput = 0 * 1024 - 1, .blink_time = 334 }, + { .throughput = 1 * 1024 - 1, .blink_time = 260 }, + { .throughput = 5 * 1024 - 1, .blink_time = 220 }, + { .throughput = 10 * 1024 - 1, .blink_time = 190 }, + { .throughput = 20 * 1024 - 1, .blink_time = 170 }, + { .throughput = 50 * 1024 - 1, .blink_time = 150 }, + { .throughput = 70 * 1024 - 1, .blink_time = 130 }, + { .throughput = 100 * 1024 - 1, .blink_time = 110 }, + { .throughput = 200 * 1024 - 1, .blink_time = 80 }, + { .throughput = 300 * 1024 - 1, .blink_time = 50 }, }; -#define IWL_1MB_RATE (128 * 1024) -#define IWL_LED_THRESHOLD (16) -#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /* exclude SOLID_ON */ -#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1) - /* * Adjust led blink rate to compensate on a MAC Clock difference on every HW * Led blink rate analysis showed an average deviation of 0% on 3945, @@ -97,133 +85,104 @@ static inline u8 iwl_blink_compensation(struct iwl_priv *priv, } /* Set led pattern command */ -static int iwl_led_pattern(struct iwl_priv *priv, unsigned int idx) +static int iwl_led_cmd(struct iwl_priv *priv, + unsigned long on, + unsigned long off) { struct iwl_led_cmd led_cmd = { .id = IWL_LED_LINK, .interval = IWL_DEF_LED_INTRVL }; + int ret; - BUG_ON(idx > IWL_MAX_BLINK_TBL); + if (!test_bit(STATUS_READY, &priv->status)) + return -EBUSY; - IWL_DEBUG_LED(priv, "Led blink time compensation= %u\n", + if (priv->blink_on == on && priv->blink_off == off) + return 0; + + IWL_DEBUG_LED(priv, "Led blink time compensation=%u\n", priv->cfg->base_params->led_compensation); - led_cmd.on = - iwl_blink_compensation(priv, blink_tbl[idx].on_time, + led_cmd.on = iwl_blink_compensation(priv, on, priv->cfg->base_params->led_compensation); - led_cmd.off = - iwl_blink_compensation(priv, blink_tbl[idx].off_time, + led_cmd.off = iwl_blink_compensation(priv, off, priv->cfg->base_params->led_compensation); - return priv->cfg->ops->led->cmd(priv, &led_cmd); + ret = priv->cfg->ops->led->cmd(priv, &led_cmd); + if (!ret) { + priv->blink_on = on; + priv->blink_off = off; + } + return ret; } -int iwl_led_start(struct iwl_priv *priv) +static void iwl_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) { - return priv->cfg->ops->led->on(priv); -} -EXPORT_SYMBOL(iwl_led_start); + struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led); + unsigned long on = 0; -int iwl_led_associate(struct iwl_priv *priv) -{ - IWL_DEBUG_LED(priv, "Associated\n"); - if (priv->cfg->led_mode == IWL_LED_BLINK) - priv->allow_blinking = 1; - priv->last_blink_time = jiffies; + if (brightness > 0) + on = IWL_LED_SOLID; - return 0; + iwl_led_cmd(priv, on, 0); } -EXPORT_SYMBOL(iwl_led_associate); -int iwl_led_disassociate(struct iwl_priv *priv) +static int iwl_led_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) { - priv->allow_blinking = 0; + struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led); - return 0; + return iwl_led_cmd(priv, *delay_on, *delay_off); } -EXPORT_SYMBOL(iwl_led_disassociate); -/* - * calculate blink rate according to last second Tx/Rx activities - */ -static int iwl_get_blink_rate(struct iwl_priv *priv) -{ - int i; - /* count both tx and rx traffic to be able to - * handle traffic in either direction - */ - u64 current_tpt = priv->tx_stats.data_bytes + - priv->rx_stats.data_bytes; - s64 tpt = current_tpt - priv->led_tpt; - - if (tpt < 0) /* wraparound */ - tpt = -tpt; - - IWL_DEBUG_LED(priv, "tpt %lld current_tpt %llu\n", - (long long)tpt, - (unsigned long long)current_tpt); - priv->led_tpt = current_tpt; - - if (!priv->allow_blinking) - i = IWL_MAX_BLINK_TBL; - else - for (i = 0; i < IWL_MAX_BLINK_TBL; i++) - if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE)) - break; - - IWL_DEBUG_LED(priv, "LED BLINK IDX=%d\n", i); - return i; -} - -/* - * this function called from handler. Since setting Led command can - * happen very frequent we postpone led command to be called from - * REPLY handler so we know ucode is up - */ -void iwl_leds_background(struct iwl_priv *priv) +void iwl_leds_init(struct iwl_priv *priv) { - u8 blink_idx; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { - priv->last_blink_time = 0; - return; - } - if (iwl_is_rfkill(priv)) { - priv->last_blink_time = 0; - return; + int mode = led_mode; + int ret; + + if (mode == IWL_LED_DEFAULT) + mode = priv->cfg->led_mode; + + priv->led.name = kasprintf(GFP_KERNEL, "%s-led", + wiphy_name(priv->hw->wiphy)); + priv->led.brightness_set = iwl_led_brightness_set; + priv->led.blink_set = iwl_led_blink_set; + priv->led.max_brightness = 1; + + switch (mode) { + case IWL_LED_DEFAULT: + WARN_ON(1); + break; + case IWL_LED_BLINK: + priv->led.default_trigger = + ieee80211_create_tpt_led_trigger(priv->hw, + IEEE80211_TPT_LEDTRIG_FL_CONNECTED, + iwl_blink, ARRAY_SIZE(iwl_blink)); + break; + case IWL_LED_RF_STATE: + priv->led.default_trigger = + ieee80211_get_radio_led_name(priv->hw); + break; } - if (!priv->allow_blinking) { - priv->last_blink_time = 0; - if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) { - priv->last_blink_rate = IWL_SOLID_BLINK_IDX; - iwl_led_pattern(priv, IWL_SOLID_BLINK_IDX); - } + ret = led_classdev_register(&priv->pci_dev->dev, &priv->led); + if (ret) { + kfree(priv->led.name); return; } - if (!priv->last_blink_time || - !time_after(jiffies, priv->last_blink_time + - msecs_to_jiffies(1000))) - return; - - blink_idx = iwl_get_blink_rate(priv); - /* call only if blink rate change */ - if (blink_idx != priv->last_blink_rate) - iwl_led_pattern(priv, blink_idx); - - priv->last_blink_time = jiffies; - priv->last_blink_rate = blink_idx; + priv->led_registered = true; } -EXPORT_SYMBOL(iwl_leds_background); +EXPORT_SYMBOL(iwl_leds_init); -void iwl_leds_init(struct iwl_priv *priv) +void iwl_leds_exit(struct iwl_priv *priv) { - priv->last_blink_rate = 0; - priv->last_blink_time = 0; - priv->allow_blinking = 0; - if (led_mode != IWL_LED_DEFAULT && - led_mode != priv->cfg->led_mode) - priv->cfg->led_mode = led_mode; + if (!priv->led_registered) + return; + + led_classdev_unregister(&priv->led); + kfree(priv->led.name); } -EXPORT_SYMBOL(iwl_leds_init); +EXPORT_SYMBOL(iwl_leds_exit); diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index 9079b33486ef..101eef12b3bb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -31,23 +31,14 @@ struct iwl_priv; #define IWL_LED_SOLID 11 -#define IWL_LED_NAME_LEN 31 #define IWL_DEF_LED_INTRVL cpu_to_le32(1000) #define IWL_LED_ACTIVITY (0<<1) #define IWL_LED_LINK (1<<1) -enum led_type { - IWL_LED_TRG_TX, - IWL_LED_TRG_RX, - IWL_LED_TRG_ASSOC, - IWL_LED_TRG_RADIO, - IWL_LED_TRG_MAX, -}; - /* * LED mode - * IWL_LED_DEFAULT: use system default + * IWL_LED_DEFAULT: use device default * IWL_LED_RF_STATE: turn LED on/off based on RF state * LED ON = RF ON * LED OFF = RF OFF @@ -60,9 +51,6 @@ enum iwl_led_mode { }; void iwl_leds_init(struct iwl_priv *priv); -void iwl_leds_background(struct iwl_priv *priv); -int iwl_led_start(struct iwl_priv *priv); -int iwl_led_associate(struct iwl_priv *priv); -int iwl_led_disassociate(struct iwl_priv *priv); +void iwl_leds_exit(struct iwl_priv *priv); #endif /* __iwl_leds_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-legacy.c b/drivers/net/wireless/iwlwifi/iwl-legacy.c index bb1a742a98a0..e1ace3ce30b3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-legacy.c +++ b/drivers/net/wireless/iwlwifi/iwl-legacy.c @@ -85,10 +85,9 @@ int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed) IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n", channel->hw_value, changed); - if (unlikely(!priv->cfg->mod_params->disable_hw_scan && - test_bit(STATUS_SCANNING, &priv->status))) { + if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { scan_active = 1; - IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); + IWL_DEBUG_MAC80211(priv, "scan active\n"); } if (changed & (IEEE80211_CONF_CHANGE_SMPS | @@ -332,7 +331,6 @@ static inline void iwl_set_no_assoc(struct iwl_priv *priv, { struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); - iwl_led_disassociate(priv); /* * inform the ucode that there is no longer an * association and that no more packets should be @@ -520,8 +518,6 @@ void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw, if (bss_conf->assoc) { priv->timestamp = bss_conf->timestamp; - iwl_led_associate(priv); - if (!iwl_is_rfkill(priv)) priv->cfg->ops->legacy->post_associate(priv); } else @@ -545,7 +541,6 @@ void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw, memcpy(ctx->staging.bssid_addr, bss_conf->bssid, ETH_ALEN); memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN); - iwl_led_associate(priv); priv->cfg->ops->legacy->config_ap(priv); } else iwl_set_no_assoc(priv, vif); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 1eec18d909d8..1d1bf3234d8d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -226,8 +226,7 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, else cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA; - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist) { + if (iwl_advanced_bt_coexist(priv)) { if (!priv->cfg->bt_params->bt_sco_disable) cmd->flags |= IWL_POWER_BT_SCO_ENA; else @@ -313,8 +312,7 @@ static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv, else cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA; - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist) { + if (iwl_advanced_bt_coexist(priv)) { if (!priv->cfg->bt_params->bt_sco_disable) cmd->flags |= IWL_POWER_BT_SCO_ENA; else @@ -358,8 +356,7 @@ static void iwl_power_build_cmd(struct iwl_priv *priv, if (priv->cfg->base_params->broken_powersave) iwl_power_sleep_cam_cmd(priv, cmd); - else if (priv->cfg->base_params->supports_idle && - priv->hw->conf.flags & IEEE80211_CONF_IDLE) + else if (priv->hw->conf.flags & IEEE80211_CONF_IDLE) iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20); else if (priv->cfg->ops->lib->tt_ops.lower_power_detection && priv->cfg->ops->lib->tt_ops.tt_power_mode && diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 12d9363d0afe..08f1bea8b652 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -257,8 +257,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, queue_work(priv->workqueue, &priv->scan_completed); if (priv->iw_mode != NL80211_IFTYPE_ADHOC && - priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist && + iwl_advanced_bt_coexist(priv) && priv->bt_status != scan_notif->bt_status) { if (scan_notif->bt_status) { /* BT on */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 371abbf60eac..adcef735180a 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2517,7 +2517,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv) ieee80211_wake_queues(priv->hw); - priv->active_rate = IWL_RATES_MASK; + priv->active_rate = IWL_RATES_MASK_3945; iwl_power_update_mode(priv, true); @@ -2535,15 +2535,14 @@ static void iwl3945_alive_start(struct iwl_priv *priv) /* Configure Bluetooth device coexistence support */ priv->cfg->ops->hcmd->send_bt_config(priv); + set_bit(STATUS_READY, &priv->status); + /* Configure the adapter for unassociated operation */ iwl3945_commit_rxon(priv, ctx); iwl3945_reg_txpower_periodic(priv); - iwl_leds_init(priv); - IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n"); - set_bit(STATUS_READY, &priv->status); wake_up_interruptible(&priv->wait_command_queue); return; @@ -2861,16 +2860,13 @@ int iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) u32 extra; u32 suspend_time = 100; u32 scan_suspend_time = 100; - unsigned long flags; IWL_DEBUG_INFO(priv, "Scanning while associated...\n"); - spin_lock_irqsave(&priv->lock, flags); if (priv->is_internal_short_scan) interval = 0; else interval = vif->bss_conf.beacon_int; - spin_unlock_irqrestore(&priv->lock, flags); scan->suspend_time = 0; scan->max_out_time = cpu_to_le32(200 * 1024); @@ -3170,8 +3166,6 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw) * no need to poll the killswitch state anymore */ cancel_delayed_work(&priv->_3945.rfkill_poll); - iwl_led_start(priv); - priv->is_open = 1; IWL_DEBUG_MAC80211(priv, "leave\n"); return 0; @@ -3289,6 +3283,14 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return -EOPNOTSUPP; } + /* + * To support IBSS RSN, don't program group keys in IBSS, the + * hardware will then not attempt to decrypt the frames. + */ + if (vif->type == NL80211_IFTYPE_ADHOC && + !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + return -EOPNOTSUPP; + static_key = !iwl_is_associated(priv, IWL_RXON_CTX_BSS); if (!static_key) { @@ -3918,7 +3920,8 @@ static int iwl3945_setup_mac(struct iwl_priv *priv) priv->contexts[IWL_RXON_CTX_BSS].interface_modes; hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | - WIPHY_FLAG_DISABLE_BEACON_HINTS; + WIPHY_FLAG_DISABLE_BEACON_HINTS | + WIPHY_FLAG_IBSS_RSN; hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945; /* we create the 802.11 header and a zero-length SSID element */ @@ -3935,6 +3938,8 @@ static int iwl3945_setup_mac(struct iwl_priv *priv) priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->bands[IEEE80211_BAND_5GHZ]; + iwl_leds_init(priv); + ret = ieee80211_register_hw(priv->hw); if (ret) { IWL_ERR(priv, "Failed to register hw (error %d)\n", ret); @@ -4194,6 +4199,8 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) set_bit(STATUS_EXIT_PENDING, &priv->status); + iwl_leds_exit(priv); + if (priv->mac80211_registered) { ieee80211_unregister_hw(priv->hw); priv->mac80211_registered = 0; diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 5a4982271e96..ed57e4402800 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -287,7 +287,8 @@ int iwm_cfg80211_inform_bss(struct iwm_priv *iwm) return -EINVAL; } - freq = ieee80211_channel_to_frequency(umac_bss->channel); + freq = ieee80211_channel_to_frequency(umac_bss->channel, + band->band); channel = ieee80211_get_channel(wiphy, freq); signal = umac_bss->rssi * 100; diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index a944893ae3ca..9a57cf6a488f 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -543,7 +543,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, switch (le32_to_cpu(complete->status)) { case UMAC_ASSOC_COMPLETE_SUCCESS: chan = ieee80211_get_channel(wiphy, - ieee80211_channel_to_frequency(complete->channel)); + ieee80211_channel_to_frequency(complete->channel, + complete->band == UMAC_BAND_2GHZ ? + IEEE80211_BAND_2GHZ : + IEEE80211_BAND_5GHZ)); if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) { /* Associated to a unallowed channel, disassociate. */ __iwm_invalidate_mlme_profile(iwm); @@ -841,7 +844,7 @@ static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf, goto err; } - freq = ieee80211_channel_to_frequency(umac_bss->channel); + freq = ieee80211_channel_to_frequency(umac_bss->channel, band->band); channel = ieee80211_get_channel(wiphy, freq); signal = umac_bss->rssi * 100; diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 698a1f7694ed..30ef0351bfc4 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -607,7 +607,8 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, /* No channel, no luck */ if (chan_no != -1) { struct wiphy *wiphy = priv->wdev->wiphy; - int freq = ieee80211_channel_to_frequency(chan_no); + int freq = ieee80211_channel_to_frequency(chan_no, + IEEE80211_BAND_2GHZ); struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq); @@ -1597,7 +1598,8 @@ static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev, lbs_deb_enter(LBS_DEB_CFG80211); survey->channel = ieee80211_get_channel(wiphy, - ieee80211_channel_to_frequency(priv->channel)); + ieee80211_channel_to_frequency(priv->channel, + IEEE80211_BAND_2GHZ)); ret = lbs_get_rssi(priv, &signal, &noise); if (ret == 0) { diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 78c4da150a74..7e8a658b7670 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -145,9 +145,13 @@ int lbs_update_hw_spec(struct lbs_private *priv) if (priv->current_addr[0] == 0xff) memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN); - memcpy(priv->dev->dev_addr, priv->current_addr, ETH_ALEN); - if (priv->mesh_dev) - memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN); + if (!priv->copied_hwaddr) { + memcpy(priv->dev->dev_addr, priv->current_addr, ETH_ALEN); + if (priv->mesh_dev) + memcpy(priv->mesh_dev->dev_addr, + priv->current_addr, ETH_ALEN); + priv->copied_hwaddr = 1; + } out: lbs_deb_leave(LBS_DEB_CMD); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 18dd9a02c459..bc461eb39660 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -90,6 +90,7 @@ struct lbs_private { void *card; u8 fw_ready; u8 surpriseremoved; + u8 setup_fw_on_resume; int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); void (*reset_card) (struct lbs_private *priv); int (*enter_deep_sleep) (struct lbs_private *priv); @@ -101,6 +102,7 @@ struct lbs_private { u32 fwcapinfo; u16 regioncode; u8 current_addr[ETH_ALEN]; + u8 copied_hwaddr; /* Command download */ u8 dnld_sent; diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 00600239a053..f6c2cd665f49 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -20,10 +20,8 @@ #include <linux/moduleparam.h> #include <linux/firmware.h> #include <linux/jiffies.h> -#include <linux/kthread.h> #include <linux/list.h> #include <linux/netdevice.h> -#include <linux/semaphore.h> #include <linux/slab.h> #include <linux/spi/libertas_spi.h> #include <linux/spi/spi.h> @@ -34,6 +32,12 @@ #include "dev.h" #include "if_spi.h" +struct if_spi_packet { + struct list_head list; + u16 blen; + u8 buffer[0] __attribute__((aligned(4))); +}; + struct if_spi_card { struct spi_device *spi; struct lbs_private *priv; @@ -51,18 +55,36 @@ struct if_spi_card { unsigned long spu_reg_delay; /* Handles all SPI communication (except for FW load) */ - struct task_struct *spi_thread; - int run_thread; - - /* Used to wake up the spi_thread */ - struct semaphore spi_ready; - struct semaphore spi_thread_terminated; + struct workqueue_struct *workqueue; + struct work_struct packet_work; u8 cmd_buffer[IF_SPI_CMD_BUF_SIZE]; + + /* A buffer of incoming packets from libertas core. + * Since we can't sleep in hw_host_to_card, we have to buffer + * them. */ + struct list_head cmd_packet_list; + struct list_head data_packet_list; + + /* Protects cmd_packet_list and data_packet_list */ + spinlock_t buffer_lock; }; static void free_if_spi_card(struct if_spi_card *card) { + struct list_head *cursor, *next; + struct if_spi_packet *packet; + + list_for_each_safe(cursor, next, &card->cmd_packet_list) { + packet = container_of(cursor, struct if_spi_packet, list); + list_del(&packet->list); + kfree(packet); + } + list_for_each_safe(cursor, next, &card->data_packet_list) { + packet = container_of(cursor, struct if_spi_packet, list); + list_del(&packet->list); + kfree(packet); + } spi_set_drvdata(card->spi, NULL); kfree(card); } @@ -622,7 +644,7 @@ out: /* * SPI Transfer Thread * - * The SPI thread handles all SPI transfers, so there is no need for a lock. + * The SPI worker handles all SPI transfers, so there is no need for a lock. */ /* Move a command from the card to the host */ @@ -742,6 +764,40 @@ out: return err; } +/* Move data or a command from the host to the card. */ +static void if_spi_h2c(struct if_spi_card *card, + struct if_spi_packet *packet, int type) +{ + int err = 0; + u16 int_type, port_reg; + + switch (type) { + case MVMS_DAT: + int_type = IF_SPI_CIC_TX_DOWNLOAD_OVER; + port_reg = IF_SPI_DATA_RDWRPORT_REG; + break; + case MVMS_CMD: + int_type = IF_SPI_CIC_CMD_DOWNLOAD_OVER; + port_reg = IF_SPI_CMD_RDWRPORT_REG; + break; + default: + lbs_pr_err("can't transfer buffer of type %d\n", type); + err = -EINVAL; + goto out; + } + + /* Write the data to the card */ + err = spu_write(card, port_reg, packet->buffer, packet->blen); + if (err) + goto out; + +out: + kfree(packet); + + if (err) + lbs_pr_err("%s: error %d\n", __func__, err); +} + /* Inform the host about a card event */ static void if_spi_e2h(struct if_spi_card *card) { @@ -766,71 +822,88 @@ out: lbs_pr_err("%s: error %d\n", __func__, err); } -static int lbs_spi_thread(void *data) +static void if_spi_host_to_card_worker(struct work_struct *work) { int err; - struct if_spi_card *card = data; + struct if_spi_card *card; u16 hiStatus; + unsigned long flags; + struct if_spi_packet *packet; - while (1) { - /* Wait to be woken up by one of two things. First, our ISR - * could tell us that something happened on the WLAN. - * Secondly, libertas could call hw_host_to_card with more - * data, which we might be able to send. - */ - do { - err = down_interruptible(&card->spi_ready); - if (!card->run_thread) { - up(&card->spi_thread_terminated); - do_exit(0); - } - } while (err == -EINTR); + card = container_of(work, struct if_spi_card, packet_work); - /* Read the host interrupt status register to see what we - * can do. */ - err = spu_read_u16(card, IF_SPI_HOST_INT_STATUS_REG, - &hiStatus); - if (err) { - lbs_pr_err("I/O error\n"); + lbs_deb_enter(LBS_DEB_SPI); + + /* Read the host interrupt status register to see what we + * can do. */ + err = spu_read_u16(card, IF_SPI_HOST_INT_STATUS_REG, + &hiStatus); + if (err) { + lbs_pr_err("I/O error\n"); + goto err; + } + + if (hiStatus & IF_SPI_HIST_CMD_UPLOAD_RDY) { + err = if_spi_c2h_cmd(card); + if (err) goto err; - } + } + if (hiStatus & IF_SPI_HIST_RX_UPLOAD_RDY) { + err = if_spi_c2h_data(card); + if (err) + goto err; + } - if (hiStatus & IF_SPI_HIST_CMD_UPLOAD_RDY) { - err = if_spi_c2h_cmd(card); - if (err) - goto err; - } - if (hiStatus & IF_SPI_HIST_RX_UPLOAD_RDY) { - err = if_spi_c2h_data(card); - if (err) - goto err; + /* workaround: in PS mode, the card does not set the Command + * Download Ready bit, but it sets TX Download Ready. */ + if (hiStatus & IF_SPI_HIST_CMD_DOWNLOAD_RDY || + (card->priv->psstate != PS_STATE_FULL_POWER && + (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY))) { + /* This means two things. First of all, + * if there was a previous command sent, the card has + * successfully received it. + * Secondly, it is now ready to download another + * command. + */ + lbs_host_to_card_done(card->priv); + + /* Do we have any command packets from the host to + * send? */ + packet = NULL; + spin_lock_irqsave(&card->buffer_lock, flags); + if (!list_empty(&card->cmd_packet_list)) { + packet = (struct if_spi_packet *)(card-> + cmd_packet_list.next); + list_del(&packet->list); } + spin_unlock_irqrestore(&card->buffer_lock, flags); - /* workaround: in PS mode, the card does not set the Command - * Download Ready bit, but it sets TX Download Ready. */ - if (hiStatus & IF_SPI_HIST_CMD_DOWNLOAD_RDY || - (card->priv->psstate != PS_STATE_FULL_POWER && - (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY))) { - lbs_host_to_card_done(card->priv); + if (packet) + if_spi_h2c(card, packet, MVMS_CMD); + } + if (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY) { + /* Do we have any data packets from the host to + * send? */ + packet = NULL; + spin_lock_irqsave(&card->buffer_lock, flags); + if (!list_empty(&card->data_packet_list)) { + packet = (struct if_spi_packet *)(card-> + data_packet_list.next); + list_del(&packet->list); } + spin_unlock_irqrestore(&card->buffer_lock, flags); - if (hiStatus & IF_SPI_HIST_CARD_EVENT) - if_spi_e2h(card); + if (packet) + if_spi_h2c(card, packet, MVMS_DAT); + } + if (hiStatus & IF_SPI_HIST_CARD_EVENT) + if_spi_e2h(card); err: - if (err) - lbs_pr_err("%s: got error %d\n", __func__, err); - } -} + if (err) + lbs_pr_err("%s: got error %d\n", __func__, err); -/* Block until lbs_spi_thread thread has terminated */ -static void if_spi_terminate_spi_thread(struct if_spi_card *card) -{ - /* It would be nice to use kthread_stop here, but that function - * can't wake threads waiting for a semaphore. */ - card->run_thread = 0; - up(&card->spi_ready); - down(&card->spi_thread_terminated); + lbs_deb_leave(LBS_DEB_SPI); } /* @@ -842,18 +915,40 @@ static int if_spi_host_to_card(struct lbs_private *priv, u8 type, u8 *buf, u16 nb) { int err = 0; + unsigned long flags; struct if_spi_card *card = priv->card; + struct if_spi_packet *packet; + u16 blen; lbs_deb_enter_args(LBS_DEB_SPI, "type %d, bytes %d", type, nb); - nb = ALIGN(nb, 4); + if (nb == 0) { + lbs_pr_err("%s: invalid size requested: %d\n", __func__, nb); + err = -EINVAL; + goto out; + } + blen = ALIGN(nb, 4); + packet = kzalloc(sizeof(struct if_spi_packet) + blen, GFP_ATOMIC); + if (!packet) { + err = -ENOMEM; + goto out; + } + packet->blen = blen; + memcpy(packet->buffer, buf, nb); + memset(packet->buffer + nb, 0, blen - nb); switch (type) { case MVMS_CMD: - err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG, buf, nb); + priv->dnld_sent = DNLD_CMD_SENT; + spin_lock_irqsave(&card->buffer_lock, flags); + list_add_tail(&packet->list, &card->cmd_packet_list); + spin_unlock_irqrestore(&card->buffer_lock, flags); break; case MVMS_DAT: - err = spu_write(card, IF_SPI_DATA_RDWRPORT_REG, buf, nb); + priv->dnld_sent = DNLD_DATA_SENT; + spin_lock_irqsave(&card->buffer_lock, flags); + list_add_tail(&packet->list, &card->data_packet_list); + spin_unlock_irqrestore(&card->buffer_lock, flags); break; default: lbs_pr_err("can't transfer buffer of type %d", type); @@ -861,6 +956,9 @@ static int if_spi_host_to_card(struct lbs_private *priv, break; } + /* Queue spi xfer work */ + queue_work(card->workqueue, &card->packet_work); +out: lbs_deb_leave_args(LBS_DEB_SPI, "err=%d", err); return err; } @@ -869,13 +967,14 @@ static int if_spi_host_to_card(struct lbs_private *priv, * Host Interrupts * * Service incoming interrupts from the WLAN device. We can't sleep here, so - * don't try to talk on the SPI bus, just wake up the SPI thread. + * don't try to talk on the SPI bus, just queue the SPI xfer work. */ static irqreturn_t if_spi_host_interrupt(int irq, void *dev_id) { struct if_spi_card *card = dev_id; - up(&card->spi_ready); + queue_work(card->workqueue, &card->packet_work); + return IRQ_HANDLED; } @@ -883,56 +982,26 @@ static irqreturn_t if_spi_host_interrupt(int irq, void *dev_id) * SPI callbacks */ -static int __devinit if_spi_probe(struct spi_device *spi) +static int if_spi_init_card(struct if_spi_card *card) { - struct if_spi_card *card; - struct lbs_private *priv = NULL; - struct libertas_spi_platform_data *pdata = spi->dev.platform_data; - int err = 0, i; + struct spi_device *spi = card->spi; + int err, i; u32 scratch; - struct sched_param param = { .sched_priority = 1 }; const struct firmware *helper = NULL; const struct firmware *mainfw = NULL; lbs_deb_enter(LBS_DEB_SPI); - if (!pdata) { - err = -EINVAL; - goto out; - } - - if (pdata->setup) { - err = pdata->setup(spi); - if (err) - goto out; - } - - /* Allocate card structure to represent this specific device */ - card = kzalloc(sizeof(struct if_spi_card), GFP_KERNEL); - if (!card) { - err = -ENOMEM; - goto out; - } - spi_set_drvdata(spi, card); - card->pdata = pdata; - card->spi = spi; - card->prev_xfer_time = jiffies; - - sema_init(&card->spi_ready, 0); - sema_init(&card->spi_thread_terminated, 0); - - /* Initialize the SPI Interface Unit */ - err = spu_init(card, pdata->use_dummy_writes); + err = spu_init(card, card->pdata->use_dummy_writes); if (err) - goto free_card; + goto out; err = spu_get_chip_revision(card, &card->card_id, &card->card_rev); if (err) - goto free_card; + goto out; - /* Firmware load */ err = spu_read_u32(card, IF_SPI_SCRATCH_4_REG, &scratch); if (err) - goto free_card; + goto out; if (scratch == SUCCESSFUL_FW_DOWNLOAD_MAGIC) lbs_deb_spi("Firmware is already loaded for " "Marvell WLAN 802.11 adapter\n"); @@ -946,7 +1015,7 @@ static int __devinit if_spi_probe(struct spi_device *spi) lbs_pr_err("Unsupported chip_id: 0x%02x\n", card->card_id); err = -ENODEV; - goto free_card; + goto out; } err = lbs_get_firmware(&card->spi->dev, NULL, NULL, @@ -954,7 +1023,7 @@ static int __devinit if_spi_probe(struct spi_device *spi) &mainfw); if (err) { lbs_pr_err("failed to find firmware (%d)\n", err); - goto free_card; + goto out; } lbs_deb_spi("Initializing FW for Marvell WLAN 802.11 adapter " @@ -966,15 +1035,68 @@ static int __devinit if_spi_probe(struct spi_device *spi) spi->max_speed_hz); err = if_spi_prog_helper_firmware(card, helper); if (err) - goto free_card; + goto out; err = if_spi_prog_main_firmware(card, mainfw); if (err) - goto free_card; + goto out; lbs_deb_spi("loaded FW for Marvell WLAN 802.11 adapter\n"); } err = spu_set_interrupt_mode(card, 0, 1); if (err) + goto out; + +out: + if (helper) + release_firmware(helper); + if (mainfw) + release_firmware(mainfw); + + lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err); + + return err; +} + +static int __devinit if_spi_probe(struct spi_device *spi) +{ + struct if_spi_card *card; + struct lbs_private *priv = NULL; + struct libertas_spi_platform_data *pdata = spi->dev.platform_data; + int err = 0; + + lbs_deb_enter(LBS_DEB_SPI); + + if (!pdata) { + err = -EINVAL; + goto out; + } + + if (pdata->setup) { + err = pdata->setup(spi); + if (err) + goto out; + } + + /* Allocate card structure to represent this specific device */ + card = kzalloc(sizeof(struct if_spi_card), GFP_KERNEL); + if (!card) { + err = -ENOMEM; + goto teardown; + } + spi_set_drvdata(spi, card); + card->pdata = pdata; + card->spi = spi; + card->prev_xfer_time = jiffies; + + INIT_LIST_HEAD(&card->cmd_packet_list); + INIT_LIST_HEAD(&card->data_packet_list); + spin_lock_init(&card->buffer_lock); + + /* Initialize the SPI Interface Unit */ + + /* Firmware load */ + err = if_spi_init_card(card); + if (err) goto free_card; /* Register our card with libertas. @@ -993,27 +1115,16 @@ static int __devinit if_spi_probe(struct spi_device *spi) priv->fw_ready = 1; /* Initialize interrupt handling stuff. */ - card->run_thread = 1; - card->spi_thread = kthread_run(lbs_spi_thread, card, "lbs_spi_thread"); - if (IS_ERR(card->spi_thread)) { - card->run_thread = 0; - err = PTR_ERR(card->spi_thread); - lbs_pr_err("error creating SPI thread: err=%d\n", err); - goto remove_card; - } - if (sched_setscheduler(card->spi_thread, SCHED_FIFO, ¶m)) - lbs_pr_err("Error setting scheduler, using default.\n"); + card->workqueue = create_workqueue("libertas_spi"); + INIT_WORK(&card->packet_work, if_spi_host_to_card_worker); err = request_irq(spi->irq, if_spi_host_interrupt, IRQF_TRIGGER_FALLING, "libertas_spi", card); if (err) { lbs_pr_err("can't get host irq line-- request_irq failed\n"); - goto terminate_thread; + goto terminate_workqueue; } - /* poke the IRQ handler so that we don't miss the first interrupt */ - up(&card->spi_ready); - /* Start the card. * This will call register_netdev, and we'll start * getting interrupts... */ @@ -1028,18 +1139,16 @@ static int __devinit if_spi_probe(struct spi_device *spi) release_irq: free_irq(spi->irq, card); -terminate_thread: - if_spi_terminate_spi_thread(card); -remove_card: +terminate_workqueue: + flush_workqueue(card->workqueue); + destroy_workqueue(card->workqueue); lbs_remove_card(priv); /* will call free_netdev */ free_card: free_if_spi_card(card); +teardown: + if (pdata->teardown) + pdata->teardown(spi); out: - if (helper) - release_firmware(helper); - if (mainfw) - release_firmware(mainfw); - lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err); return err; } @@ -1056,7 +1165,8 @@ static int __devexit libertas_spi_remove(struct spi_device *spi) lbs_remove_card(priv); /* will call free_netdev */ free_irq(spi->irq, card); - if_spi_terminate_spi_thread(card); + flush_workqueue(card->workqueue); + destroy_workqueue(card->workqueue); if (card->pdata->teardown) card->pdata->teardown(spi); free_if_spi_card(card); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 6836a6dd9853..ca8149cd5bd9 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -539,6 +539,43 @@ static int lbs_thread(void *data) return 0; } +/** + * @brief This function gets the HW spec from the firmware and sets + * some basic parameters. + * + * @param priv A pointer to struct lbs_private structure + * @return 0 or -1 + */ +static int lbs_setup_firmware(struct lbs_private *priv) +{ + int ret = -1; + s16 curlevel = 0, minlevel = 0, maxlevel = 0; + + lbs_deb_enter(LBS_DEB_FW); + + /* Read MAC address from firmware */ + memset(priv->current_addr, 0xff, ETH_ALEN); + ret = lbs_update_hw_spec(priv); + if (ret) + goto done; + + /* Read power levels if available */ + ret = lbs_get_tx_power(priv, &curlevel, &minlevel, &maxlevel); + if (ret == 0) { + priv->txpower_cur = curlevel; + priv->txpower_min = minlevel; + priv->txpower_max = maxlevel; + } + + /* Send cmd to FW to enable 11D function */ + ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_11D_ENABLE, 1); + + lbs_set_mac_control(priv); +done: + lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); + return ret; +} + int lbs_suspend(struct lbs_private *priv) { int ret; @@ -584,47 +621,13 @@ int lbs_resume(struct lbs_private *priv) lbs_pr_err("deep sleep activation failed: %d\n", ret); } - lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); - return ret; -} -EXPORT_SYMBOL_GPL(lbs_resume); - -/** - * @brief This function gets the HW spec from the firmware and sets - * some basic parameters. - * - * @param priv A pointer to struct lbs_private structure - * @return 0 or -1 - */ -static int lbs_setup_firmware(struct lbs_private *priv) -{ - int ret = -1; - s16 curlevel = 0, minlevel = 0, maxlevel = 0; - - lbs_deb_enter(LBS_DEB_FW); - - /* Read MAC address from firmware */ - memset(priv->current_addr, 0xff, ETH_ALEN); - ret = lbs_update_hw_spec(priv); - if (ret) - goto done; - - /* Read power levels if available */ - ret = lbs_get_tx_power(priv, &curlevel, &minlevel, &maxlevel); - if (ret == 0) { - priv->txpower_cur = curlevel; - priv->txpower_min = minlevel; - priv->txpower_max = maxlevel; - } + if (priv->setup_fw_on_resume) + ret = lbs_setup_firmware(priv); - /* Send cmd to FW to enable 11D function */ - ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_11D_ENABLE, 1); - - lbs_set_mac_control(priv); -done: lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); return ret; } +EXPORT_SYMBOL_GPL(lbs_resume); /** * This function handles the timeout of command sending. diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 454f045ddff3..5d39b2840584 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -943,7 +943,8 @@ static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn) + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size) { switch (action) { case IEEE80211_AMPDU_TX_START: diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 9ecf8407cb1b..af4f2c64f242 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -232,6 +232,9 @@ struct mwl8k_priv { struct completion firmware_loading_complete; }; +#define MAX_WEP_KEY_LEN 13 +#define NUM_WEP_KEYS 4 + /* Per interface specific private data */ struct mwl8k_vif { struct list_head list; @@ -242,8 +245,21 @@ struct mwl8k_vif { /* Non AMPDU sequence number assigned by driver. */ u16 seqno; + + /* Saved WEP keys */ + struct { + u8 enabled; + u8 key[sizeof(struct ieee80211_key_conf) + MAX_WEP_KEY_LEN]; + } wep_key_conf[NUM_WEP_KEYS]; + + /* BSSID */ + u8 bssid[ETH_ALEN]; + + /* A flag to indicate is HW crypto is enabled for this bssid */ + bool is_hw_crypto_enabled; }; #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) +#define IEEE80211_KEY_CONF(_u8) ((struct ieee80211_key_conf *)(_u8)) struct mwl8k_sta { /* Index into station database. Returned by UPDATE_STADB. */ @@ -337,6 +353,7 @@ static const struct ieee80211_rate mwl8k_rates_50[] = { #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 #define MWL8K_CMD_BSS_START 0x1100 /* per-vif */ #define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */ +#define MWL8K_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */ #define MWL8K_CMD_UPDATE_STADB 0x1123 static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) @@ -375,6 +392,7 @@ static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) MWL8K_CMDNAME(SET_RATEADAPT_MODE); MWL8K_CMDNAME(BSS_START); MWL8K_CMDNAME(SET_NEW_STN); + MWL8K_CMDNAME(UPDATE_ENCRYPTION); MWL8K_CMDNAME(UPDATE_STADB); default: snprintf(buf, bufsize, "0x%x", cmd); @@ -715,10 +733,12 @@ static inline void mwl8k_remove_dma_header(struct sk_buff *skb, __le16 qos) skb_pull(skb, sizeof(*tr) - hdrlen); } -static inline void mwl8k_add_dma_header(struct sk_buff *skb) +static void +mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) { struct ieee80211_hdr *wh; int hdrlen; + int reqd_hdrlen; struct mwl8k_dma_data *tr; /* @@ -730,11 +750,13 @@ static inline void mwl8k_add_dma_header(struct sk_buff *skb) wh = (struct ieee80211_hdr *)skb->data; hdrlen = ieee80211_hdrlen(wh->frame_control); - if (hdrlen != sizeof(*tr)) - skb_push(skb, sizeof(*tr) - hdrlen); + reqd_hdrlen = sizeof(*tr); + + if (hdrlen != reqd_hdrlen) + skb_push(skb, reqd_hdrlen - hdrlen); if (ieee80211_is_data_qos(wh->frame_control)) - hdrlen -= 2; + hdrlen -= IEEE80211_QOS_CTL_LEN; tr = (struct mwl8k_dma_data *)skb->data; if (wh != &tr->wh) @@ -747,9 +769,52 @@ static inline void mwl8k_add_dma_header(struct sk_buff *skb) * payload". That is, everything except for the 802.11 header. * This includes all crypto material including the MIC. */ - tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr)); + tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr) + tail_pad); } +static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) +{ + struct ieee80211_hdr *wh; + struct ieee80211_tx_info *tx_info; + struct ieee80211_key_conf *key_conf; + int data_pad; + + wh = (struct ieee80211_hdr *)skb->data; + + tx_info = IEEE80211_SKB_CB(skb); + + key_conf = NULL; + if (ieee80211_is_data(wh->frame_control)) + key_conf = tx_info->control.hw_key; + + /* + * Make sure the packet header is in the DMA header format (4-address + * without QoS), the necessary crypto padding between the header and the + * payload has already been provided by mac80211, but it doesn't add tail + * padding when HW crypto is enabled. + * + * We have the following trailer padding requirements: + * - WEP: 4 trailer bytes (ICV) + * - TKIP: 12 trailer bytes (8 MIC + 4 ICV) + * - CCMP: 8 trailer bytes (MIC) + */ + data_pad = 0; + if (key_conf != NULL) { + switch (key_conf->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + data_pad = 4; + break; + case WLAN_CIPHER_SUITE_TKIP: + data_pad = 12; + break; + case WLAN_CIPHER_SUITE_CCMP: + data_pad = 8; + break; + } + } + mwl8k_add_dma_header(skb, data_pad); +} /* * Packet reception for 88w8366 AP firmware. @@ -778,6 +843,13 @@ struct mwl8k_rxd_8366_ap { #define MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST 0x80 +/* 8366 AP rx_status bits */ +#define MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK 0x80 +#define MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR 0xFF +#define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR 0x02 +#define MWL8K_8366_AP_RXSTAT_WEP_DECRYPT_ICV_ERR 0x04 +#define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_ICV_ERR 0x08 + static void mwl8k_rxd_8366_ap_init(void *_rxd, dma_addr_t next_dma_addr) { struct mwl8k_rxd_8366_ap *rxd = _rxd; @@ -834,10 +906,16 @@ mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status, } else { status->band = IEEE80211_BAND_2GHZ; } - status->freq = ieee80211_channel_to_frequency(rxd->channel); + status->freq = ieee80211_channel_to_frequency(rxd->channel, + status->band); *qos = rxd->qos_control; + if ((rxd->rx_status != MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR) && + (rxd->rx_status & MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK) && + (rxd->rx_status & MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR)) + status->flag |= RX_FLAG_MMIC_ERROR; + return le16_to_cpu(rxd->pkt_len); } @@ -876,6 +954,11 @@ struct mwl8k_rxd_sta { #define MWL8K_STA_RATE_INFO_MCS_FORMAT 0x0001 #define MWL8K_STA_RX_CTRL_OWNED_BY_HOST 0x02 +#define MWL8K_STA_RX_CTRL_DECRYPT_ERROR 0x04 +/* ICV=0 or MIC=1 */ +#define MWL8K_STA_RX_CTRL_DEC_ERR_TYPE 0x08 +/* Key is uploaded only in failure case */ +#define MWL8K_STA_RX_CTRL_KEY_INDEX 0x30 static void mwl8k_rxd_sta_init(void *_rxd, dma_addr_t next_dma_addr) { @@ -931,9 +1014,13 @@ mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status, } else { status->band = IEEE80211_BAND_2GHZ; } - status->freq = ieee80211_channel_to_frequency(rxd->channel); + status->freq = ieee80211_channel_to_frequency(rxd->channel, + status->band); *qos = rxd->qos_control; + if ((rxd->rx_ctrl & MWL8K_STA_RX_CTRL_DECRYPT_ERROR) && + (rxd->rx_ctrl & MWL8K_STA_RX_CTRL_DEC_ERR_TYPE)) + status->flag |= RX_FLAG_MMIC_ERROR; return le16_to_cpu(rxd->pkt_len); } @@ -1092,9 +1179,25 @@ static inline void mwl8k_save_beacon(struct ieee80211_hw *hw, ieee80211_queue_work(hw, &priv->finalize_join_worker); } +static inline struct mwl8k_vif *mwl8k_find_vif_bss(struct list_head *vif_list, + u8 *bssid) +{ + struct mwl8k_vif *mwl8k_vif; + + list_for_each_entry(mwl8k_vif, + vif_list, list) { + if (memcmp(bssid, mwl8k_vif->bssid, + ETH_ALEN) == 0) + return mwl8k_vif; + } + + return NULL; +} + static int rxq_process(struct ieee80211_hw *hw, int index, int limit) { struct mwl8k_priv *priv = hw->priv; + struct mwl8k_vif *mwl8k_vif = NULL; struct mwl8k_rx_queue *rxq = priv->rxq + index; int processed; @@ -1104,6 +1207,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) void *rxd; int pkt_len; struct ieee80211_rx_status status; + struct ieee80211_hdr *wh; __le16 qos; skb = rxq->buf[rxq->head].skb; @@ -1130,8 +1234,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) rxq->rxd_count--; - skb_put(skb, pkt_len); - mwl8k_remove_dma_header(skb, qos); + wh = &((struct mwl8k_dma_data *)skb->data)->wh; /* * Check for a pending join operation. Save a @@ -1141,6 +1244,46 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) if (mwl8k_capture_bssid(priv, (void *)skb->data)) mwl8k_save_beacon(hw, skb); + if (ieee80211_has_protected(wh->frame_control)) { + + /* Check if hw crypto has been enabled for + * this bss. If yes, set the status flags + * accordingly + */ + mwl8k_vif = mwl8k_find_vif_bss(&priv->vif_list, + wh->addr1); + + if (mwl8k_vif != NULL && + mwl8k_vif->is_hw_crypto_enabled == true) { + /* + * When MMIC ERROR is encountered + * by the firmware, payload is + * dropped and only 32 bytes of + * mwl8k Firmware header is sent + * to the host. + * + * We need to add four bytes of + * key information. In it + * MAC80211 expects keyidx set to + * 0 for triggering Counter + * Measure of MMIC failure. + */ + if (status.flag & RX_FLAG_MMIC_ERROR) { + struct mwl8k_dma_data *tr; + tr = (struct mwl8k_dma_data *)skb->data; + memset((void *)&(tr->data), 0, 4); + pkt_len += 4; + } + + if (!ieee80211_is_auth(wh->frame_control)) + status.flag |= RX_FLAG_IV_STRIPPED | + RX_FLAG_DECRYPTED | + RX_FLAG_MMIC_STRIPPED; + } + } + + skb_put(skb, pkt_len); + mwl8k_remove_dma_header(skb, qos); memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); ieee80211_rx_irqsafe(hw, skb); @@ -1443,7 +1586,11 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) else qos = 0; - mwl8k_add_dma_header(skb); + if (priv->ap_fw) + mwl8k_encapsulate_tx_frame(skb); + else + mwl8k_add_dma_header(skb, 0); + wh = &((struct mwl8k_dma_data *)skb->data)->wh; tx_info = IEEE80211_SKB_CB(skb); @@ -3099,6 +3246,274 @@ static int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw, } /* + * CMD_UPDATE_ENCRYPTION. + */ + +#define MAX_ENCR_KEY_LENGTH 16 +#define MIC_KEY_LENGTH 8 + +struct mwl8k_cmd_update_encryption { + struct mwl8k_cmd_pkt header; + + __le32 action; + __le32 reserved; + __u8 mac_addr[6]; + __u8 encr_type; + +} __attribute__((packed)); + +struct mwl8k_cmd_set_key { + struct mwl8k_cmd_pkt header; + + __le32 action; + __le32 reserved; + __le16 length; + __le16 key_type_id; + __le32 key_info; + __le32 key_id; + __le16 key_len; + __u8 key_material[MAX_ENCR_KEY_LENGTH]; + __u8 tkip_tx_mic_key[MIC_KEY_LENGTH]; + __u8 tkip_rx_mic_key[MIC_KEY_LENGTH]; + __le16 tkip_rsc_low; + __le32 tkip_rsc_high; + __le16 tkip_tsc_low; + __le32 tkip_tsc_high; + __u8 mac_addr[6]; +} __attribute__((packed)); + +enum { + MWL8K_ENCR_ENABLE, + MWL8K_ENCR_SET_KEY, + MWL8K_ENCR_REMOVE_KEY, + MWL8K_ENCR_SET_GROUP_KEY, +}; + +#define MWL8K_UPDATE_ENCRYPTION_TYPE_WEP 0 +#define MWL8K_UPDATE_ENCRYPTION_TYPE_DISABLE 1 +#define MWL8K_UPDATE_ENCRYPTION_TYPE_TKIP 4 +#define MWL8K_UPDATE_ENCRYPTION_TYPE_MIXED 7 +#define MWL8K_UPDATE_ENCRYPTION_TYPE_AES 8 + +enum { + MWL8K_ALG_WEP, + MWL8K_ALG_TKIP, + MWL8K_ALG_CCMP, +}; + +#define MWL8K_KEY_FLAG_TXGROUPKEY 0x00000004 +#define MWL8K_KEY_FLAG_PAIRWISE 0x00000008 +#define MWL8K_KEY_FLAG_TSC_VALID 0x00000040 +#define MWL8K_KEY_FLAG_WEP_TXKEY 0x01000000 +#define MWL8K_KEY_FLAG_MICKEY_VALID 0x02000000 + +static int mwl8k_cmd_update_encryption_enable(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u8 *addr, + u8 encr_type) +{ + struct mwl8k_cmd_update_encryption *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_ENCRYPTION); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + cmd->action = cpu_to_le32(MWL8K_ENCR_ENABLE); + memcpy(cmd->mac_addr, addr, ETH_ALEN); + cmd->encr_type = encr_type; + + rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); + kfree(cmd); + + return rc; +} + +static int mwl8k_encryption_set_cmd_info(struct mwl8k_cmd_set_key *cmd, + u8 *addr, + struct ieee80211_key_conf *key) +{ + cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_ENCRYPTION); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + cmd->length = cpu_to_le16(sizeof(*cmd) - + offsetof(struct mwl8k_cmd_set_key, length)); + cmd->key_id = cpu_to_le32(key->keyidx); + cmd->key_len = cpu_to_le16(key->keylen); + memcpy(cmd->mac_addr, addr, ETH_ALEN); + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + cmd->key_type_id = cpu_to_le16(MWL8K_ALG_WEP); + if (key->keyidx == 0) + cmd->key_info = cpu_to_le32(MWL8K_KEY_FLAG_WEP_TXKEY); + + break; + case WLAN_CIPHER_SUITE_TKIP: + cmd->key_type_id = cpu_to_le16(MWL8K_ALG_TKIP); + cmd->key_info = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) + ? cpu_to_le32(MWL8K_KEY_FLAG_PAIRWISE) + : cpu_to_le32(MWL8K_KEY_FLAG_TXGROUPKEY); + cmd->key_info |= cpu_to_le32(MWL8K_KEY_FLAG_MICKEY_VALID + | MWL8K_KEY_FLAG_TSC_VALID); + break; + case WLAN_CIPHER_SUITE_CCMP: + cmd->key_type_id = cpu_to_le16(MWL8K_ALG_CCMP); + cmd->key_info = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) + ? cpu_to_le32(MWL8K_KEY_FLAG_PAIRWISE) + : cpu_to_le32(MWL8K_KEY_FLAG_TXGROUPKEY); + break; + default: + return -ENOTSUPP; + } + + return 0; +} + +static int mwl8k_cmd_encryption_set_key(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u8 *addr, + struct ieee80211_key_conf *key) +{ + struct mwl8k_cmd_set_key *cmd; + int rc; + int keymlen; + u32 action; + u8 idx; + struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + rc = mwl8k_encryption_set_cmd_info(cmd, addr, key); + if (rc < 0) + goto done; + + idx = key->keyidx; + + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) + action = MWL8K_ENCR_SET_KEY; + else + action = MWL8K_ENCR_SET_GROUP_KEY; + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + if (!mwl8k_vif->wep_key_conf[idx].enabled) { + memcpy(mwl8k_vif->wep_key_conf[idx].key, key, + sizeof(*key) + key->keylen); + mwl8k_vif->wep_key_conf[idx].enabled = 1; + } + + keymlen = 0; + action = MWL8K_ENCR_SET_KEY; + break; + case WLAN_CIPHER_SUITE_TKIP: + keymlen = MAX_ENCR_KEY_LENGTH + 2 * MIC_KEY_LENGTH; + break; + case WLAN_CIPHER_SUITE_CCMP: + keymlen = key->keylen; + break; + default: + rc = -ENOTSUPP; + goto done; + } + + memcpy(cmd->key_material, key->key, keymlen); + cmd->action = cpu_to_le32(action); + + rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); +done: + kfree(cmd); + + return rc; +} + +static int mwl8k_cmd_encryption_remove_key(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u8 *addr, + struct ieee80211_key_conf *key) +{ + struct mwl8k_cmd_set_key *cmd; + int rc; + struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + rc = mwl8k_encryption_set_cmd_info(cmd, addr, key); + if (rc < 0) + goto done; + + if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || + WLAN_CIPHER_SUITE_WEP104) + mwl8k_vif->wep_key_conf[key->keyidx].enabled = 0; + + cmd->action = cpu_to_le32(MWL8K_ENCR_REMOVE_KEY); + + rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); +done: + kfree(cmd); + + return rc; +} + +static int mwl8k_set_key(struct ieee80211_hw *hw, + enum set_key_cmd cmd_param, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + int rc = 0; + u8 encr_type; + u8 *addr; + struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); + + if (vif->type == NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + + if (sta == NULL) + addr = hw->wiphy->perm_addr; + else + addr = sta->addr; + + if (cmd_param == SET_KEY) { + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + rc = mwl8k_cmd_encryption_set_key(hw, vif, addr, key); + if (rc) + goto out; + + if ((key->cipher == WLAN_CIPHER_SUITE_WEP40) + || (key->cipher == WLAN_CIPHER_SUITE_WEP104)) + encr_type = MWL8K_UPDATE_ENCRYPTION_TYPE_WEP; + else + encr_type = MWL8K_UPDATE_ENCRYPTION_TYPE_MIXED; + + rc = mwl8k_cmd_update_encryption_enable(hw, vif, addr, + encr_type); + if (rc) + goto out; + + mwl8k_vif->is_hw_crypto_enabled = true; + + } else { + rc = mwl8k_cmd_encryption_remove_key(hw, vif, addr, key); + + if (rc) + goto out; + + mwl8k_vif->is_hw_crypto_enabled = false; + + } +out: + return rc; +} + +/* * CMD_UPDATE_STADB. */ struct ewc_ht_info { @@ -3469,6 +3884,8 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, mwl8k_vif->vif = vif; mwl8k_vif->macid = macid; mwl8k_vif->seqno = 0; + memcpy(mwl8k_vif->bssid, vif->addr, ETH_ALEN); + mwl8k_vif->is_hw_crypto_enabled = false; /* Set the mac address. */ mwl8k_cmd_set_mac_addr(hw, vif, vif->addr); @@ -3866,18 +4283,27 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw, { struct mwl8k_priv *priv = hw->priv; int ret; + int i; + struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); + struct ieee80211_key_conf *key; if (!priv->ap_fw) { ret = mwl8k_cmd_update_stadb_add(hw, vif, sta); if (ret >= 0) { MWL8K_STA(sta)->peer_id = ret; - return 0; + ret = 0; } - return ret; + } else { + ret = mwl8k_cmd_set_new_stn_add(hw, vif, sta); } - return mwl8k_cmd_set_new_stn_add(hw, vif, sta); + for (i = 0; i < NUM_WEP_KEYS; i++) { + key = IEEE80211_KEY_CONF(mwl8k_vif->wep_key_conf[i].key); + if (mwl8k_vif->wep_key_conf[i].enabled) + mwl8k_set_key(hw, SET_KEY, vif, sta, key); + } + return ret; } static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, @@ -3932,7 +4358,8 @@ static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx, static int mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn) + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size) { switch (action) { case IEEE80211_AMPDU_RX_START: @@ -3955,6 +4382,7 @@ static const struct ieee80211_ops mwl8k_ops = { .bss_info_changed = mwl8k_bss_info_changed, .prepare_multicast = mwl8k_prepare_multicast, .configure_filter = mwl8k_configure_filter, + .set_key = mwl8k_set_key, .set_rts_threshold = mwl8k_set_rts_threshold, .sta_add = mwl8k_sta_add, .sta_remove = mwl8k_sta_remove, diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 54ca49ad3472..2725f3c4442e 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -46,7 +46,7 @@ * These indirect registers work with busy bits, * and we will try maximal REGISTER_BUSY_COUNT times to access * the register while taking a REGISTER_BUSY_DELAY us delay - * between each attampt. When the busy bit is still set at that time, + * between each attempt. When the busy bit is still set at that time, * the access attempt is considered to have failed, * and we will print an error. */ @@ -305,9 +305,7 @@ static void rt2400pci_config_intf(struct rt2x00_dev *rt2x00dev, * Enable synchronisation. */ rt2x00pci_register_read(rt2x00dev, CSR14, ®); - rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); rt2x00_set_field32(®, CSR14_TSF_SYNC, conf->sync); - rt2x00_set_field32(®, CSR14_TBCN, 1); rt2x00pci_register_write(rt2x00dev, CSR14, reg); } @@ -647,6 +645,11 @@ static void rt2400pci_start_queue(struct data_queue *queue) rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); break; case QID_BEACON: + /* + * Allow the tbtt tasklet to be scheduled. + */ + tasklet_enable(&rt2x00dev->tbtt_tasklet); + rt2x00pci_register_read(rt2x00dev, CSR14, ®); rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); rt2x00_set_field32(®, CSR14_TBCN, 1); @@ -708,6 +711,11 @@ static void rt2400pci_stop_queue(struct data_queue *queue) rt2x00_set_field32(®, CSR14_TBCN, 0); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); rt2x00pci_register_write(rt2x00dev, CSR14, reg); + + /* + * Wait for possibly running tbtt tasklets. + */ + tasklet_disable(&rt2x00dev->tbtt_tasklet); break; default: break; @@ -963,9 +971,9 @@ static int rt2400pci_init_bbp(struct rt2x00_dev *rt2x00dev) static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, enum dev_state state) { - int mask = (state == STATE_RADIO_IRQ_OFF) || - (state == STATE_RADIO_IRQ_OFF_ISR); + int mask = (state == STATE_RADIO_IRQ_OFF); u32 reg; + unsigned long flags; /* * When interrupts are being enabled, the interrupt registers @@ -974,12 +982,20 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, if (state == STATE_RADIO_IRQ_ON) { rt2x00pci_register_read(rt2x00dev, CSR7, ®); rt2x00pci_register_write(rt2x00dev, CSR7, reg); + + /* + * Enable tasklets. + */ + tasklet_enable(&rt2x00dev->txstatus_tasklet); + tasklet_enable(&rt2x00dev->rxdone_tasklet); } /* * Only toggle the interrupts bits we are going to use. * Non-checked interrupt bits are disabled by default. */ + spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + rt2x00pci_register_read(rt2x00dev, CSR8, ®); rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, mask); rt2x00_set_field32(®, CSR8_TXDONE_TXRING, mask); @@ -987,6 +1003,17 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, mask); rt2x00_set_field32(®, CSR8_RXDONE, mask); rt2x00pci_register_write(rt2x00dev, CSR8, reg); + + spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + + if (state == STATE_RADIO_IRQ_OFF) { + /* + * Ensure that all tasklets are finished before + * disabling the interrupts. + */ + tasklet_disable(&rt2x00dev->txstatus_tasklet); + tasklet_disable(&rt2x00dev->rxdone_tasklet); + } } static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev) @@ -1059,9 +1086,7 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev, rt2400pci_disable_radio(rt2x00dev); break; case STATE_RADIO_IRQ_ON: - case STATE_RADIO_IRQ_ON_ISR: case STATE_RADIO_IRQ_OFF: - case STATE_RADIO_IRQ_OFF_ISR: rt2400pci_toggle_irq(rt2x00dev, state); break; case STATE_DEEP_SLEEP: @@ -1183,8 +1208,6 @@ static void rt2400pci_write_beacon(struct queue_entry *entry, /* * Enable beaconing again. */ - rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); - rt2x00_set_field32(®, CSR14_TBCN, 1); rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); rt2x00pci_register_write(rt2x00dev, CSR14, reg); } @@ -1289,57 +1312,71 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, } } -static irqreturn_t rt2400pci_interrupt_thread(int irq, void *dev_instance) +static void rt2400pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, + struct rt2x00_field32 irq_field) { - struct rt2x00_dev *rt2x00dev = dev_instance; - u32 reg = rt2x00dev->irqvalue[0]; + unsigned long flags; + u32 reg; /* - * Handle interrupts, walk through all bits - * and run the tasks, the bits are checked in order of - * priority. + * Enable a single interrupt. The interrupt mask register + * access needs locking. */ + spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); - /* - * 1 - Beacon timer expired interrupt. - */ - if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE)) - rt2x00lib_beacondone(rt2x00dev); + rt2x00pci_register_read(rt2x00dev, CSR8, ®); + rt2x00_set_field32(®, irq_field, 0); + rt2x00pci_register_write(rt2x00dev, CSR8, reg); - /* - * 2 - Rx ring done interrupt. - */ - if (rt2x00_get_field32(reg, CSR7_RXDONE)) - rt2x00pci_rxdone(rt2x00dev); + spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); +} - /* - * 3 - Atim ring transmit done interrupt. - */ - if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING)) - rt2400pci_txdone(rt2x00dev, QID_ATIM); +static void rt2400pci_txstatus_tasklet(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + u32 reg; + unsigned long flags; /* - * 4 - Priority ring transmit done interrupt. + * Handle all tx queues. */ - if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING)) - rt2400pci_txdone(rt2x00dev, QID_AC_VO); + rt2400pci_txdone(rt2x00dev, QID_ATIM); + rt2400pci_txdone(rt2x00dev, QID_AC_VO); + rt2400pci_txdone(rt2x00dev, QID_AC_VI); /* - * 5 - Tx ring transmit done interrupt. + * Enable all TXDONE interrupts again. */ - if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) - rt2400pci_txdone(rt2x00dev, QID_AC_VI); + spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); - /* Enable interrupts again. */ - rt2x00dev->ops->lib->set_device_state(rt2x00dev, - STATE_RADIO_IRQ_ON_ISR); - return IRQ_HANDLED; + rt2x00pci_register_read(rt2x00dev, CSR8, ®); + rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); + rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); + rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); + rt2x00pci_register_write(rt2x00dev, CSR8, reg); + + spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); +} + +static void rt2400pci_tbtt_tasklet(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + rt2x00lib_beacondone(rt2x00dev); + rt2400pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE); +} + +static void rt2400pci_rxdone_tasklet(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + rt2x00pci_rxdone(rt2x00dev); + rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); } static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) { struct rt2x00_dev *rt2x00dev = dev_instance; - u32 reg; + u32 reg, mask; + unsigned long flags; /* * Get the interrupt sources & saved to local variable. @@ -1354,14 +1391,44 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return IRQ_HANDLED; - /* Store irqvalues for use in the interrupt thread. */ - rt2x00dev->irqvalue[0] = reg; + mask = reg; - /* Disable interrupts, will be enabled again in the interrupt thread. */ - rt2x00dev->ops->lib->set_device_state(rt2x00dev, - STATE_RADIO_IRQ_OFF_ISR); + /* + * Schedule tasklets for interrupt handling. + */ + if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE)) + tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet); - return IRQ_WAKE_THREAD; + if (rt2x00_get_field32(reg, CSR7_RXDONE)) + tasklet_schedule(&rt2x00dev->rxdone_tasklet); + + if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING) || + rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING) || + rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) { + tasklet_schedule(&rt2x00dev->txstatus_tasklet); + /* + * Mask out all txdone interrupts. + */ + rt2x00_set_field32(&mask, CSR8_TXDONE_TXRING, 1); + rt2x00_set_field32(&mask, CSR8_TXDONE_ATIMRING, 1); + rt2x00_set_field32(&mask, CSR8_TXDONE_PRIORING, 1); + } + + /* + * Disable all interrupts for which a tasklet was scheduled right now, + * the tasklet will reenable the appropriate interrupts. + */ + spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + + rt2x00pci_register_read(rt2x00dev, CSR8, ®); + reg |= mask; + rt2x00pci_register_write(rt2x00dev, CSR8, reg); + + spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + + + + return IRQ_HANDLED; } /* @@ -1655,7 +1722,9 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .irq_handler = rt2400pci_interrupt, - .irq_handler_thread = rt2400pci_interrupt_thread, + .txstatus_tasklet = rt2400pci_txstatus_tasklet, + .tbtt_tasklet = rt2400pci_tbtt_tasklet, + .rxdone_tasklet = rt2400pci_rxdone_tasklet, .probe_hw = rt2400pci_probe_hw, .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index a9ff26a27724..3ef1fb4185c0 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -311,9 +311,7 @@ static void rt2500pci_config_intf(struct rt2x00_dev *rt2x00dev, * Enable synchronisation. */ rt2x00pci_register_read(rt2x00dev, CSR14, ®); - rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); rt2x00_set_field32(®, CSR14_TSF_SYNC, conf->sync); - rt2x00_set_field32(®, CSR14_TBCN, 1); rt2x00pci_register_write(rt2x00dev, CSR14, reg); } @@ -737,6 +735,11 @@ static void rt2500pci_start_queue(struct data_queue *queue) rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); break; case QID_BEACON: + /* + * Allow the tbtt tasklet to be scheduled. + */ + tasklet_enable(&rt2x00dev->tbtt_tasklet); + rt2x00pci_register_read(rt2x00dev, CSR14, ®); rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); rt2x00_set_field32(®, CSR14_TBCN, 1); @@ -798,6 +801,11 @@ static void rt2500pci_stop_queue(struct data_queue *queue) rt2x00_set_field32(®, CSR14_TBCN, 0); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); rt2x00pci_register_write(rt2x00dev, CSR14, reg); + + /* + * Wait for possibly running tbtt tasklets. + */ + tasklet_disable(&rt2x00dev->tbtt_tasklet); break; default: break; @@ -1118,9 +1126,9 @@ static int rt2500pci_init_bbp(struct rt2x00_dev *rt2x00dev) static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, enum dev_state state) { - int mask = (state == STATE_RADIO_IRQ_OFF) || - (state == STATE_RADIO_IRQ_OFF_ISR); + int mask = (state == STATE_RADIO_IRQ_OFF); u32 reg; + unsigned long flags; /* * When interrupts are being enabled, the interrupt registers @@ -1129,12 +1137,20 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, if (state == STATE_RADIO_IRQ_ON) { rt2x00pci_register_read(rt2x00dev, CSR7, ®); rt2x00pci_register_write(rt2x00dev, CSR7, reg); + + /* + * Enable tasklets. + */ + tasklet_enable(&rt2x00dev->txstatus_tasklet); + tasklet_enable(&rt2x00dev->rxdone_tasklet); } /* * Only toggle the interrupts bits we are going to use. * Non-checked interrupt bits are disabled by default. */ + spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + rt2x00pci_register_read(rt2x00dev, CSR8, ®); rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, mask); rt2x00_set_field32(®, CSR8_TXDONE_TXRING, mask); @@ -1142,6 +1158,16 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, mask); rt2x00_set_field32(®, CSR8_RXDONE, mask); rt2x00pci_register_write(rt2x00dev, CSR8, reg); + + spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + + if (state == STATE_RADIO_IRQ_OFF) { + /* + * Ensure that all tasklets are finished. + */ + tasklet_disable(&rt2x00dev->txstatus_tasklet); + tasklet_disable(&rt2x00dev->rxdone_tasklet); + } } static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev) @@ -1214,9 +1240,7 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev, rt2500pci_disable_radio(rt2x00dev); break; case STATE_RADIO_IRQ_ON: - case STATE_RADIO_IRQ_ON_ISR: case STATE_RADIO_IRQ_OFF: - case STATE_RADIO_IRQ_OFF_ISR: rt2500pci_toggle_irq(rt2x00dev, state); break; case STATE_DEEP_SLEEP: @@ -1337,8 +1361,6 @@ static void rt2500pci_write_beacon(struct queue_entry *entry, /* * Enable beaconing again. */ - rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); - rt2x00_set_field32(®, CSR14_TBCN, 1); rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); rt2x00pci_register_write(rt2x00dev, CSR14, reg); } @@ -1422,58 +1444,71 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, } } -static irqreturn_t rt2500pci_interrupt_thread(int irq, void *dev_instance) +static void rt2500pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, + struct rt2x00_field32 irq_field) { - struct rt2x00_dev *rt2x00dev = dev_instance; - u32 reg = rt2x00dev->irqvalue[0]; + unsigned long flags; + u32 reg; /* - * Handle interrupts, walk through all bits - * and run the tasks, the bits are checked in order of - * priority. + * Enable a single interrupt. The interrupt mask register + * access needs locking. */ + spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); - /* - * 1 - Beacon timer expired interrupt. - */ - if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE)) - rt2x00lib_beacondone(rt2x00dev); + rt2x00pci_register_read(rt2x00dev, CSR8, ®); + rt2x00_set_field32(®, irq_field, 0); + rt2x00pci_register_write(rt2x00dev, CSR8, reg); - /* - * 2 - Rx ring done interrupt. - */ - if (rt2x00_get_field32(reg, CSR7_RXDONE)) - rt2x00pci_rxdone(rt2x00dev); + spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); +} - /* - * 3 - Atim ring transmit done interrupt. - */ - if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING)) - rt2500pci_txdone(rt2x00dev, QID_ATIM); +static void rt2500pci_txstatus_tasklet(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + u32 reg; + unsigned long flags; /* - * 4 - Priority ring transmit done interrupt. + * Handle all tx queues. */ - if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING)) - rt2500pci_txdone(rt2x00dev, QID_AC_VO); + rt2500pci_txdone(rt2x00dev, QID_ATIM); + rt2500pci_txdone(rt2x00dev, QID_AC_VO); + rt2500pci_txdone(rt2x00dev, QID_AC_VI); /* - * 5 - Tx ring transmit done interrupt. + * Enable all TXDONE interrupts again. */ - if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) - rt2500pci_txdone(rt2x00dev, QID_AC_VI); + spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + + rt2x00pci_register_read(rt2x00dev, CSR8, ®); + rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); + rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); + rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); + rt2x00pci_register_write(rt2x00dev, CSR8, reg); - /* Enable interrupts again. */ - rt2x00dev->ops->lib->set_device_state(rt2x00dev, - STATE_RADIO_IRQ_ON_ISR); + spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); +} - return IRQ_HANDLED; +static void rt2500pci_tbtt_tasklet(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + rt2x00lib_beacondone(rt2x00dev); + rt2500pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE); +} + +static void rt2500pci_rxdone_tasklet(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + rt2x00pci_rxdone(rt2x00dev); + rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); } static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) { struct rt2x00_dev *rt2x00dev = dev_instance; - u32 reg; + u32 reg, mask; + unsigned long flags; /* * Get the interrupt sources & saved to local variable. @@ -1488,14 +1523,42 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return IRQ_HANDLED; - /* Store irqvalues for use in the interrupt thread. */ - rt2x00dev->irqvalue[0] = reg; + mask = reg; - /* Disable interrupts, will be enabled again in the interrupt thread. */ - rt2x00dev->ops->lib->set_device_state(rt2x00dev, - STATE_RADIO_IRQ_OFF_ISR); + /* + * Schedule tasklets for interrupt handling. + */ + if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE)) + tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet); - return IRQ_WAKE_THREAD; + if (rt2x00_get_field32(reg, CSR7_RXDONE)) + tasklet_schedule(&rt2x00dev->rxdone_tasklet); + + if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING) || + rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING) || + rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) { + tasklet_schedule(&rt2x00dev->txstatus_tasklet); + /* + * Mask out all txdone interrupts. + */ + rt2x00_set_field32(&mask, CSR8_TXDONE_TXRING, 1); + rt2x00_set_field32(&mask, CSR8_TXDONE_ATIMRING, 1); + rt2x00_set_field32(&mask, CSR8_TXDONE_PRIORING, 1); + } + + /* + * Disable all interrupts for which a tasklet was scheduled right now, + * the tasklet will reenable the appropriate interrupts. + */ + spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + + rt2x00pci_register_read(rt2x00dev, CSR8, ®); + reg |= mask; + rt2x00pci_register_write(rt2x00dev, CSR8, reg); + + spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + + return IRQ_HANDLED; } /* @@ -1952,7 +2015,9 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .irq_handler = rt2500pci_interrupt, - .irq_handler_thread = rt2500pci_interrupt_thread, + .txstatus_tasklet = rt2500pci_txstatus_tasklet, + .tbtt_tasklet = rt2500pci_tbtt_tasklet, + .rxdone_tasklet = rt2500pci_rxdone_tasklet, .probe_hw = rt2500pci_probe_hw, .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 6b3b1de46792..01f385d5846c 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -478,9 +478,7 @@ static void rt2500usb_config_intf(struct rt2x00_dev *rt2x00dev, rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); - rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, conf->sync); - rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1); rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); } @@ -1056,9 +1054,7 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev, rt2500usb_disable_radio(rt2x00dev); break; case STATE_RADIO_IRQ_ON: - case STATE_RADIO_IRQ_ON_ISR: case STATE_RADIO_IRQ_OFF: - case STATE_RADIO_IRQ_OFF_ISR: /* No support, but no error either */ break; case STATE_DEEP_SLEEP: diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 4c55e8525cad..ec8159ce0ee8 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -372,8 +372,12 @@ /* * US_CYC_CNT + * BT_MODE_EN: Bluetooth mode enable + * CLOCK CYCLE: Clock cycle count in 1us. + * PCI:0x21, PCIE:0x7d, USB:0x1e */ #define US_CYC_CNT 0x02a4 +#define US_CYC_CNT_BT_MODE_EN FIELD32(0x00000100) #define US_CYC_CNT_CLOCK_CYCLE FIELD32(0x000000ff) /* @@ -1805,6 +1809,12 @@ struct mac_iveiv_entry { #define RFCSR30_RF_CALIBRATION FIELD8(0x80) /* + * RFCSR 31: + */ +#define RFCSR31_RX_AGC_FC FIELD8(0x1f) +#define RFCSR31_RX_H20M FIELD8(0x20) + +/* * RF registers */ diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 54917a281398..c9bf074342ba 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -818,8 +818,6 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) /* * Enable beaconing again. */ - rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); - rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); @@ -831,8 +829,8 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) } EXPORT_SYMBOL_GPL(rt2800_write_beacon); -static inline void rt2800_clear_beacon(struct rt2x00_dev *rt2x00dev, - unsigned int beacon_base) +static inline void rt2800_clear_beacon_register(struct rt2x00_dev *rt2x00dev, + unsigned int beacon_base) { int i; @@ -845,6 +843,33 @@ static inline void rt2800_clear_beacon(struct rt2x00_dev *rt2x00dev, rt2800_register_write(rt2x00dev, beacon_base + i, 0); } +void rt2800_clear_beacon(struct queue_entry *entry) +{ + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + u32 reg; + + /* + * Disable beaconing while we are reloading the beacon data, + * otherwise we might be sending out invalid data. + */ + rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); + + /* + * Clear beacon. + */ + rt2800_clear_beacon_register(rt2x00dev, + HW_BEACON_OFFSET(entry->entry_idx)); + + /* + * Enabled beaconing again. + */ + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); +} +EXPORT_SYMBOL_GPL(rt2800_clear_beacon); + #ifdef CONFIG_RT2X00_LIB_DEBUGFS const struct rt2x00debug rt2800_rt2x00debug = { .owner = THIS_MODULE, @@ -1005,7 +1030,7 @@ static void rt2800_config_wcid_attr(struct rt2x00_dev *rt2x00dev, memset(&wcid_entry, 0, sizeof(wcid_entry)); if (crypto->cmd == SET_KEY) - memcpy(&wcid_entry, crypto->address, ETH_ALEN); + memcpy(wcid_entry.mac, crypto->address, ETH_ALEN); rt2800_register_multiwrite(rt2x00dev, offset, &wcid_entry, sizeof(wcid_entry)); } @@ -1155,29 +1180,11 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, if (flags & CONFIG_UPDATE_TYPE) { /* - * Clear current synchronisation setup. - */ - rt2800_clear_beacon(rt2x00dev, - HW_BEACON_OFFSET(intf->beacon->entry_idx)); - /* * Enable synchronisation. */ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); - rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync); - rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, - (conf->sync == TSF_SYNC_ADHOC || - conf->sync == TSF_SYNC_AP_NONE)); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); - - /* - * Enable pre tbtt interrupt for beaconing modes - */ - rt2800_register_read(rt2x00dev, INT_TIMER_EN, ®); - rt2x00_set_field32(®, INT_TIMER_EN_PRE_TBTT_TIMER, - (conf->sync == TSF_SYNC_AP_NONE)); - rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg); - } if (flags & CONFIG_UPDATE_MAC) { @@ -2187,19 +2194,23 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) /* * Clear all beacons */ - rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE0); - rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE1); - rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE2); - rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE3); - rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE4); - rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE5); - rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE6); - rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE7); + rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE0); + rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE1); + rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE2); + rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE3); + rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE4); + rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE5); + rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE6); + rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE7); if (rt2x00_is_usb(rt2x00dev)) { rt2800_register_read(rt2x00dev, US_CYC_CNT, ®); rt2x00_set_field32(®, US_CYC_CNT_CLOCK_CYCLE, 30); rt2800_register_write(rt2x00dev, US_CYC_CNT, reg); + } else if (rt2x00_is_pcie(rt2x00dev)) { + rt2800_register_read(rt2x00dev, US_CYC_CNT, ®); + rt2x00_set_field32(®, US_CYC_CNT_CLOCK_CYCLE, 125); + rt2800_register_write(rt2x00dev, US_CYC_CNT, reg); } rt2800_register_read(rt2x00dev, HT_FBK_CFG0, ®); @@ -2436,6 +2447,10 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * bw40); rt2800_bbp_write(rt2x00dev, 4, bbp); + rt2800_rfcsr_read(rt2x00dev, 31, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR31_RX_H20M, bw40); + rt2800_rfcsr_write(rt2x00dev, 31, rfcsr); + rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 1); rt2800_rfcsr_write(rt2x00dev, 22, rfcsr); @@ -2510,7 +2525,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 4, 0x40); rt2800_rfcsr_write(rt2x00dev, 5, 0x03); rt2800_rfcsr_write(rt2x00dev, 6, 0x02); - rt2800_rfcsr_write(rt2x00dev, 7, 0x70); + rt2800_rfcsr_write(rt2x00dev, 7, 0x60); rt2800_rfcsr_write(rt2x00dev, 9, 0x0f); rt2800_rfcsr_write(rt2x00dev, 10, 0x41); rt2800_rfcsr_write(rt2x00dev, 11, 0x21); @@ -2602,12 +2617,12 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, LDO_CFG0, reg); } else if (rt2x00_rt(rt2x00dev, RT3071) || rt2x00_rt(rt2x00dev, RT3090)) { + rt2800_rfcsr_write(rt2x00dev, 31, 0x14); + rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR6_R2, 1); rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); - rt2800_rfcsr_write(rt2x00dev, 31, 0x14); - rt2800_register_read(rt2x00dev, LDO_CFG0, ®); rt2x00_set_field32(®, LDO_CFG0_BGSEL, 1); if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) || @@ -2619,6 +2634,10 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, 0); } rt2800_register_write(rt2x00dev, LDO_CFG0, reg); + + rt2800_register_read(rt2x00dev, GPIO_SWITCH, ®); + rt2x00_set_field32(®, GPIO_SWITCH_5, 0); + rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg); } else if (rt2x00_rt(rt2x00dev, RT3390)) { rt2800_register_read(rt2x00dev, GPIO_SWITCH, ®); rt2x00_set_field32(®, GPIO_SWITCH_5, 0); @@ -2670,10 +2689,11 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR17_TX_LO1_EN, 0); - if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) || + if (rt2x00_rt(rt2x00dev, RT3070) || + rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) || rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) || rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) { - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) + if (!test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) rt2x00_set_field8(&rfcsr, RFCSR17_R, 1); } rt2x00_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &eeprom); @@ -2686,6 +2706,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) if (rt2x00_rt(rt2x00dev, RT3090)) { rt2800_bbp_read(rt2x00dev, 138, &bbp); + /* Turn off unused DAC1 and ADC1 to reduce power consumption */ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1) rt2x00_set_field8(&bbp, BBP138_RX_ADC1, 0); @@ -2719,10 +2740,9 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 21, rfcsr); } - if (rt2x00_rt(rt2x00dev, RT3070) || rt2x00_rt(rt2x00dev, RT3071)) { + if (rt2x00_rt(rt2x00dev, RT3070)) { rt2800_rfcsr_read(rt2x00dev, 27, &rfcsr); - if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F) || - rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E)) + if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) rt2x00_set_field8(&rfcsr, RFCSR27_R1, 3); else rt2x00_set_field8(&rfcsr, RFCSR27_R1, 0); @@ -2810,10 +2830,7 @@ void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev) rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); /* Wait for DMA, ignore error */ @@ -2823,9 +2840,6 @@ void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 0); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - - rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0); - rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0); } EXPORT_SYMBOL_GPL(rt2800_disable_radio); @@ -3530,7 +3544,8 @@ EXPORT_SYMBOL_GPL(rt2800_get_tsf); int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn) + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size) { int ret = 0; diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index e3c995a9dec4..0c92d86a36f4 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -156,6 +156,7 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev); void rt2800_txdone_entry(struct queue_entry *entry, u32 status); void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc); +void rt2800_clear_beacon(struct queue_entry *entry); extern const struct rt2x00debug rt2800_rt2x00debug; @@ -198,7 +199,8 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, u64 rt2800_get_tsf(struct ieee80211_hw *hw); int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn); + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size); int rt2800_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey); diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index aa97971a38af..8f4dfc3d8023 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -200,11 +200,22 @@ static void rt2800pci_start_queue(struct data_queue *queue) rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); break; case QID_BEACON: + /* + * Allow beacon tasklets to be scheduled for periodic + * beacon updates. + */ + tasklet_enable(&rt2x00dev->tbtt_tasklet); + tasklet_enable(&rt2x00dev->pretbtt_tasklet); + rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); + + rt2800_register_read(rt2x00dev, INT_TIMER_EN, ®); + rt2x00_set_field32(®, INT_TIMER_EN_PRE_TBTT_TIMER, 1); + rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg); break; default: break; @@ -250,6 +261,16 @@ static void rt2800pci_stop_queue(struct data_queue *queue) rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); + + rt2800_register_read(rt2x00dev, INT_TIMER_EN, ®); + rt2x00_set_field32(®, INT_TIMER_EN_PRE_TBTT_TIMER, 0); + rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg); + + /* + * Wait for tbtt tasklets to finish. + */ + tasklet_disable(&rt2x00dev->tbtt_tasklet); + tasklet_disable(&rt2x00dev->pretbtt_tasklet); break; default: break; @@ -397,9 +418,9 @@ static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev) static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, enum dev_state state) { - int mask = (state == STATE_RADIO_IRQ_ON) || - (state == STATE_RADIO_IRQ_ON_ISR); + int mask = (state == STATE_RADIO_IRQ_ON); u32 reg; + unsigned long flags; /* * When interrupts are being enabled, the interrupt registers @@ -408,8 +429,17 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, if (state == STATE_RADIO_IRQ_ON) { rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, ®); rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg); + + /* + * Enable tasklets. The beacon related tasklets are + * enabled when the beacon queue is started. + */ + tasklet_enable(&rt2x00dev->txstatus_tasklet); + tasklet_enable(&rt2x00dev->rxdone_tasklet); + tasklet_enable(&rt2x00dev->autowake_tasklet); } + spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®); rt2x00_set_field32(®, INT_MASK_CSR_RXDELAYINT, 0); rt2x00_set_field32(®, INT_MASK_CSR_TXDELAYINT, 0); @@ -430,6 +460,17 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, INT_MASK_CSR_RX_COHERENT, 0); rt2x00_set_field32(®, INT_MASK_CSR_TX_COHERENT, 0); rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); + spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + + if (state == STATE_RADIO_IRQ_OFF) { + /* + * Ensure that all tasklets are finished before + * disabling the interrupts. + */ + tasklet_disable(&rt2x00dev->txstatus_tasklet); + tasklet_disable(&rt2x00dev->rxdone_tasklet); + tasklet_disable(&rt2x00dev->autowake_tasklet); + } } static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) @@ -475,39 +516,23 @@ static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev) static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev) { - u32 reg; - - rt2800_disable_radio(rt2x00dev); - - rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001280); - - rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, ®); - rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, 1); - rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, 1); - rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, 1); - rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX3, 1); - rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX4, 1); - rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX5, 1); - rt2x00_set_field32(®, WPDMA_RST_IDX_DRX_IDX0, 1); - rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg); - - rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f); - rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); + if (rt2x00_is_soc(rt2x00dev)) { + rt2800_disable_radio(rt2x00dev); + rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0); + rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0); + } } static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) { - /* - * Always put the device to sleep (even when we intend to wakeup!) - * if the device is booting and wasn't asleep it will return - * failure when attempting to wakeup. - */ - rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0xff, 2); - if (state == STATE_AWAKE) { - rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0); + rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0x02); rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKUP); + } else if (state == STATE_SLEEP) { + rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, 0xffffffff); + rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, 0xffffffff); + rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0x01, 0xff, 0x01); } return 0; @@ -538,9 +563,7 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, rt2800pci_set_state(rt2x00dev, STATE_SLEEP); break; case STATE_RADIO_IRQ_ON: - case STATE_RADIO_IRQ_ON_ISR: case STATE_RADIO_IRQ_OFF: - case STATE_RADIO_IRQ_OFF_ISR: rt2800pci_toggle_irq(rt2x00dev, state); break; case STATE_DEEP_SLEEP: @@ -652,6 +675,12 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry, */ rxdesc->flags |= RX_FLAG_IV_STRIPPED; + /* + * The hardware has already checked the Michael Mic and has + * stripped it from the frame. Signal this to mac80211. + */ + rxdesc->flags |= RX_FLAG_MMIC_STRIPPED; + if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS) rxdesc->flags |= RX_FLAG_DECRYPTED; else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC) @@ -726,45 +755,60 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) } } -static void rt2800pci_txstatus_tasklet(unsigned long data) +static void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, + struct rt2x00_field32 irq_field) { - rt2800pci_txdone((struct rt2x00_dev *)data); -} - -static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance) -{ - struct rt2x00_dev *rt2x00dev = dev_instance; - u32 reg = rt2x00dev->irqvalue[0]; + unsigned long flags; + u32 reg; /* - * 1 - Pre TBTT interrupt. + * Enable a single interrupt. The interrupt mask register + * access needs locking. */ - if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT)) - rt2x00lib_pretbtt(rt2x00dev); + spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®); + rt2x00_set_field32(®, irq_field, 1); + rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); + spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); +} - /* - * 2 - Beacondone interrupt. - */ - if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT)) - rt2x00lib_beacondone(rt2x00dev); +static void rt2800pci_txstatus_tasklet(unsigned long data) +{ + rt2800pci_txdone((struct rt2x00_dev *)data); /* - * 3 - Rx ring done interrupt. + * No need to enable the tx status interrupt here as we always + * leave it enabled to minimize the possibility of a tx status + * register overflow. See comment in interrupt handler. */ - if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE)) - rt2x00pci_rxdone(rt2x00dev); +} - /* - * 4 - Auto wakeup interrupt. - */ - if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP)) - rt2800pci_wakeup(rt2x00dev); +static void rt2800pci_pretbtt_tasklet(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + rt2x00lib_pretbtt(rt2x00dev); + rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_PRE_TBTT); +} - /* Enable interrupts again. */ - rt2x00dev->ops->lib->set_device_state(rt2x00dev, - STATE_RADIO_IRQ_ON_ISR); +static void rt2800pci_tbtt_tasklet(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + rt2x00lib_beacondone(rt2x00dev); + rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TBTT); +} - return IRQ_HANDLED; +static void rt2800pci_rxdone_tasklet(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + rt2x00pci_rxdone(rt2x00dev); + rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE); +} + +static void rt2800pci_autowake_tasklet(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + rt2800pci_wakeup(rt2x00dev); + rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_AUTO_WAKEUP); } static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev) @@ -810,8 +854,8 @@ static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev) static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) { struct rt2x00_dev *rt2x00dev = dev_instance; - u32 reg; - irqreturn_t ret = IRQ_HANDLED; + u32 reg, mask; + unsigned long flags; /* Read status and ACK all interrupts */ rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, ®); @@ -823,38 +867,44 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return IRQ_HANDLED; - if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) - rt2800pci_txstatus_interrupt(rt2x00dev); + /* + * Since INT_MASK_CSR and INT_SOURCE_CSR use the same bits + * for interrupts and interrupt masks we can just use the value of + * INT_SOURCE_CSR to create the interrupt mask. + */ + mask = ~reg; - if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT) || - rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT) || - rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE) || - rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP)) { + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) { + rt2800pci_txstatus_interrupt(rt2x00dev); /* - * All other interrupts are handled in the interrupt thread. - * Store irqvalue for use in the interrupt thread. + * Never disable the TX_FIFO_STATUS interrupt. */ - rt2x00dev->irqvalue[0] = reg; + rt2x00_set_field32(&mask, INT_MASK_CSR_TX_FIFO_STATUS, 1); + } - /* - * Disable interrupts, will be enabled again in the - * interrupt thread. - */ - rt2x00dev->ops->lib->set_device_state(rt2x00dev, - STATE_RADIO_IRQ_OFF_ISR); + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT)) + tasklet_hi_schedule(&rt2x00dev->pretbtt_tasklet); - /* - * Leave the TX_FIFO_STATUS interrupt enabled to not lose any - * tx status reports. - */ - rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®); - rt2x00_set_field32(®, INT_MASK_CSR_TX_FIFO_STATUS, 1); - rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT)) + tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet); - ret = IRQ_WAKE_THREAD; - } + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE)) + tasklet_schedule(&rt2x00dev->rxdone_tasklet); - return ret; + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP)) + tasklet_schedule(&rt2x00dev->autowake_tasklet); + + /* + * Disable all interrupts for which a tasklet was scheduled right now, + * the tasklet will reenable the appropriate interrupts. + */ + spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®); + reg &= mask; + rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); + spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + + return IRQ_HANDLED; } /* @@ -969,8 +1019,11 @@ static const struct rt2800_ops rt2800pci_rt2800_ops = { static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { .irq_handler = rt2800pci_interrupt, - .irq_handler_thread = rt2800pci_interrupt_thread, - .txstatus_tasklet = rt2800pci_txstatus_tasklet, + .txstatus_tasklet = rt2800pci_txstatus_tasklet, + .pretbtt_tasklet = rt2800pci_pretbtt_tasklet, + .tbtt_tasklet = rt2800pci_tbtt_tasklet, + .rxdone_tasklet = rt2800pci_rxdone_tasklet, + .autowake_tasklet = rt2800pci_autowake_tasklet, .probe_hw = rt2800pci_probe_hw, .get_firmware_name = rt2800pci_get_firmware_name, .check_firmware = rt2800_check_firmware, @@ -990,6 +1043,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { .write_tx_desc = rt2800pci_write_tx_desc, .write_tx_data = rt2800_write_tx_data, .write_beacon = rt2800_write_beacon, + .clear_beacon = rt2800_clear_beacon, .fill_rxdone = rt2800pci_fill_rxdone, .config_shared_key = rt2800_config_shared_key, .config_pairwise_key = rt2800_config_pairwise_key, diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index b97a4a54ff4c..5d91561e0de7 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -253,9 +253,7 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev, rt2800usb_set_state(rt2x00dev, STATE_SLEEP); break; case STATE_RADIO_IRQ_ON: - case STATE_RADIO_IRQ_ON_ISR: case STATE_RADIO_IRQ_OFF: - case STATE_RADIO_IRQ_OFF_ISR: /* No support, but no error either */ break; case STATE_DEEP_SLEEP: @@ -486,6 +484,12 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, */ rxdesc->flags |= RX_FLAG_IV_STRIPPED; + /* + * The hardware has already checked the Michael Mic and has + * stripped it from the frame. Signal this to mac80211. + */ + rxdesc->flags |= RX_FLAG_MMIC_STRIPPED; + if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS) rxdesc->flags |= RX_FLAG_DECRYPTED; else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC) @@ -633,6 +637,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { .write_tx_desc = rt2800usb_write_tx_desc, .write_tx_data = rt2800usb_write_tx_data, .write_beacon = rt2800_write_beacon, + .clear_beacon = rt2800_clear_beacon, .get_tx_data_len = rt2800usb_get_tx_data_len, .fill_rxdone = rt2800usb_fill_rxdone, .config_shared_key = rt2800_config_shared_key, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 84aaf393da43..39bc2faf1793 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -368,6 +368,7 @@ struct rt2x00_intf { * dedicated beacon entry. */ struct queue_entry *beacon; + bool enable_beacon; /* * Actions that needed rescheduling. @@ -511,14 +512,13 @@ struct rt2x00lib_ops { irq_handler_t irq_handler; /* - * Threaded Interrupt handlers. - */ - irq_handler_t irq_handler_thread; - - /* * TX status tasklet handler. */ void (*txstatus_tasklet) (unsigned long data); + void (*pretbtt_tasklet) (unsigned long data); + void (*tbtt_tasklet) (unsigned long data); + void (*rxdone_tasklet) (unsigned long data); + void (*autowake_tasklet) (unsigned long data); /* * Device init handlers. @@ -573,6 +573,7 @@ struct rt2x00lib_ops { struct txentry_desc *txdesc); void (*write_beacon) (struct queue_entry *entry, struct txentry_desc *txdesc); + void (*clear_beacon) (struct queue_entry *entry); int (*get_tx_data_len) (struct queue_entry *entry); /* @@ -788,10 +789,12 @@ struct rt2x00_dev { * - Open ap interface count. * - Open sta interface count. * - Association count. + * - Beaconing enabled count. */ unsigned int intf_ap_count; unsigned int intf_sta_count; unsigned int intf_associated; + unsigned int intf_beaconing; /* * Link quality @@ -857,6 +860,13 @@ struct rt2x00_dev { */ struct ieee80211_low_level_stats low_level_stats; + /** + * Work queue for all work which should not be placed + * on the mac80211 workqueue (because of dependencies + * between various work structures). + */ + struct workqueue_struct *workqueue; + /* * Scheduled work. * NOTE: intf_work will use ieee80211_iterate_active_interfaces() @@ -887,12 +897,6 @@ struct rt2x00_dev { const struct firmware *fw; /* - * Interrupt values, stored between interrupt service routine - * and interrupt thread routine. - */ - u32 irqvalue[2]; - - /* * FIFO for storing tx status reports between isr and tasklet. */ DECLARE_KFIFO_PTR(txstatus_fifo, u32); @@ -901,6 +905,15 @@ struct rt2x00_dev { * Tasklet for processing tx status reports (rt2800pci). */ struct tasklet_struct txstatus_tasklet; + struct tasklet_struct pretbtt_tasklet; + struct tasklet_struct tbtt_tasklet; + struct tasklet_struct rxdone_tasklet; + struct tasklet_struct autowake_tasklet; + + /* + * Protect the interrupt mask register. + */ + spinlock_t irqmask_lock; }; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 9597a03242cc..9de9dbe94399 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -121,7 +121,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, return; if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags)) - rt2x00queue_update_beacon(rt2x00dev, vif, true); + rt2x00queue_update_beacon(rt2x00dev, vif); } static void rt2x00lib_intf_scheduled(struct work_struct *work) @@ -174,7 +174,13 @@ static void rt2x00lib_beaconupdate_iter(void *data, u8 *mac, vif->type != NL80211_IFTYPE_WDS) return; - rt2x00queue_update_beacon(rt2x00dev, vif, true); + /* + * Update the beacon without locking. This is safe on PCI devices + * as they only update the beacon periodically here. This should + * never be called for USB devices. + */ + WARN_ON(rt2x00_is_usb(rt2x00dev)); + rt2x00queue_update_beacon_locked(rt2x00dev, vif); } void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) @@ -183,9 +189,9 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) return; /* send buffered bc/mc frames out for every bssid */ - ieee80211_iterate_active_interfaces(rt2x00dev->hw, - rt2x00lib_bc_buffer_iter, - rt2x00dev); + ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, + rt2x00lib_bc_buffer_iter, + rt2x00dev); /* * Devices with pre tbtt interrupt don't need to update the beacon * here as they will fetch the next beacon directly prior to @@ -195,9 +201,9 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) return; /* fetch next beacon */ - ieee80211_iterate_active_interfaces(rt2x00dev->hw, - rt2x00lib_beaconupdate_iter, - rt2x00dev); + ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, + rt2x00lib_beaconupdate_iter, + rt2x00dev); } EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); @@ -207,9 +213,9 @@ void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev) return; /* fetch next beacon */ - ieee80211_iterate_active_interfaces(rt2x00dev->hw, - rt2x00lib_beaconupdate_iter, - rt2x00dev); + ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, + rt2x00lib_beaconupdate_iter, + rt2x00dev); } EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt); @@ -649,7 +655,10 @@ static void rt2x00lib_channel(struct ieee80211_channel *entry, const int channel, const int tx_power, const int value) { - entry->center_freq = ieee80211_channel_to_frequency(channel); + /* XXX: this assumption about the band is wrong for 802.11j */ + entry->band = channel <= 14 ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + entry->center_freq = ieee80211_channel_to_frequency(channel, + entry->band); entry->hw_value = value; entry->max_power = tx_power; entry->max_antenna_gain = 0xff; @@ -812,15 +821,29 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) GFP_KERNEL); if (status) return status; + } - /* tasklet for processing the tx status reports. */ - if (rt2x00dev->ops->lib->txstatus_tasklet) - tasklet_init(&rt2x00dev->txstatus_tasklet, - rt2x00dev->ops->lib->txstatus_tasklet, - (unsigned long)rt2x00dev); - + /* + * Initialize tasklets if used by the driver. Tasklets are + * disabled until the interrupts are turned on. The driver + * has to handle that. + */ +#define RT2X00_TASKLET_INIT(taskletname) \ + if (rt2x00dev->ops->lib->taskletname) { \ + tasklet_init(&rt2x00dev->taskletname, \ + rt2x00dev->ops->lib->taskletname, \ + (unsigned long)rt2x00dev); \ + tasklet_disable(&rt2x00dev->taskletname); \ } + RT2X00_TASKLET_INIT(txstatus_tasklet); + RT2X00_TASKLET_INIT(pretbtt_tasklet); + RT2X00_TASKLET_INIT(tbtt_tasklet); + RT2X00_TASKLET_INIT(rxdone_tasklet); + RT2X00_TASKLET_INIT(autowake_tasklet); + +#undef RT2X00_TASKLET_INIT + /* * Register HW. */ @@ -949,6 +972,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) { int retval = -ENOMEM; + spin_lock_init(&rt2x00dev->irqmask_lock); mutex_init(&rt2x00dev->csr_mutex); set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); @@ -973,8 +997,15 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) BIT(NL80211_IFTYPE_WDS); /* - * Initialize configuration work. + * Initialize work. */ + rt2x00dev->workqueue = + alloc_ordered_workqueue(wiphy_name(rt2x00dev->hw->wiphy), 0); + if (!rt2x00dev->workqueue) { + retval = -ENOMEM; + goto exit; + } + INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); /* @@ -1033,6 +1064,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) cancel_work_sync(&rt2x00dev->intf_work); cancel_work_sync(&rt2x00dev->rxdone_work); cancel_work_sync(&rt2x00dev->txdone_work); + destroy_workqueue(rt2x00dev->workqueue); /* * Free the tx status fifo. @@ -1043,6 +1075,10 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) * Kill the tx status tasklet. */ tasklet_kill(&rt2x00dev->txstatus_tasklet); + tasklet_kill(&rt2x00dev->pretbtt_tasklet); + tasklet_kill(&rt2x00dev->tbtt_tasklet); + tasklet_kill(&rt2x00dev->rxdone_tasklet); + tasklet_kill(&rt2x00dev->autowake_tasklet); /* * Uninitialize device. diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index a105c500627b..2d94cbaf5f4a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -157,14 +157,30 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, bool local); /** - * rt2x00queue_update_beacon - Send new beacon from mac80211 to hardware + * rt2x00queue_update_beacon - Send new beacon from mac80211 + * to hardware. Handles locking by itself (mutex). * @rt2x00dev: Pointer to &struct rt2x00_dev. * @vif: Interface for which the beacon should be updated. - * @enable_beacon: Enable beaconing */ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, - struct ieee80211_vif *vif, - const bool enable_beacon); + struct ieee80211_vif *vif); + +/** + * rt2x00queue_update_beacon_locked - Send new beacon from mac80211 + * to hardware. Caller needs to ensure locking. + * @rt2x00dev: Pointer to &struct rt2x00_dev. + * @vif: Interface for which the beacon should be updated. + */ +int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev, + struct ieee80211_vif *vif); + +/** + * rt2x00queue_clear_beacon - Clear beacon in hardware + * @rt2x00dev: Pointer to &struct rt2x00_dev. + * @vif: Interface for which the beacon should be updated. + */ +int rt2x00queue_clear_beacon(struct rt2x00_dev *rt2x00dev, + struct ieee80211_vif *vif); /** * rt2x00queue_index_inc - Index incrementation function diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index bfda60eaf4ef..c975b0a12e95 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -417,7 +417,8 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev) !test_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags)) return; - schedule_delayed_work(&link->watchdog_work, WATCHDOG_INTERVAL); + ieee80211_queue_delayed_work(rt2x00dev->hw, + &link->watchdog_work, WATCHDOG_INTERVAL); } void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev) @@ -441,7 +442,9 @@ static void rt2x00link_watchdog(struct work_struct *work) rt2x00dev->ops->lib->watchdog(rt2x00dev); if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) - schedule_delayed_work(&link->watchdog_work, WATCHDOG_INTERVAL); + ieee80211_queue_delayed_work(rt2x00dev->hw, + &link->watchdog_work, + WATCHDOG_INTERVAL); } void rt2x00link_register(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index f3da051df39e..6a66021d8f65 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -617,11 +617,47 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, bss_conf->bssid); /* - * Update the beacon. + * Update the beacon. This is only required on USB devices. PCI + * devices fetch beacons periodically. */ - if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) - rt2x00queue_update_beacon(rt2x00dev, vif, - bss_conf->enable_beacon); + if (changes & BSS_CHANGED_BEACON && rt2x00_is_usb(rt2x00dev)) + rt2x00queue_update_beacon(rt2x00dev, vif); + + /* + * Start/stop beaconing. + */ + if (changes & BSS_CHANGED_BEACON_ENABLED) { + if (!bss_conf->enable_beacon && intf->enable_beacon) { + rt2x00queue_clear_beacon(rt2x00dev, vif); + rt2x00dev->intf_beaconing--; + intf->enable_beacon = false; + + if (rt2x00dev->intf_beaconing == 0) { + /* + * Last beaconing interface disabled + * -> stop beacon queue. + */ + mutex_lock(&intf->beacon_skb_mutex); + rt2x00queue_stop_queue(rt2x00dev->bcn); + mutex_unlock(&intf->beacon_skb_mutex); + } + + + } else if (bss_conf->enable_beacon && !intf->enable_beacon) { + rt2x00dev->intf_beaconing++; + intf->enable_beacon = true; + + if (rt2x00dev->intf_beaconing == 1) { + /* + * First beaconing interface enabled + * -> start beacon queue. + */ + mutex_lock(&intf->beacon_skb_mutex); + rt2x00queue_start_queue(rt2x00dev->bcn); + mutex_unlock(&intf->beacon_skb_mutex); + } + } + } /* * When the association status has changed we must reset the link diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index ace0b668c04e..4dd82b0b0520 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -160,10 +160,9 @@ int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) /* * Register interrupt handler. */ - status = request_threaded_irq(rt2x00dev->irq, - rt2x00dev->ops->lib->irq_handler, - rt2x00dev->ops->lib->irq_handler_thread, - IRQF_SHARED, rt2x00dev->name, rt2x00dev); + status = request_irq(rt2x00dev->irq, + rt2x00dev->ops->lib->irq_handler, + IRQF_SHARED, rt2x00dev->name, rt2x00dev); if (status) { ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n", rt2x00dev->irq, status); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index ca82b3a91697..fa17c83b9685 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -566,13 +566,10 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, return 0; } -int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, - struct ieee80211_vif *vif, - const bool enable_beacon) +int rt2x00queue_clear_beacon(struct rt2x00_dev *rt2x00dev, + struct ieee80211_vif *vif) { struct rt2x00_intf *intf = vif_to_intf(vif); - struct skb_frame_desc *skbdesc; - struct txentry_desc txdesc; if (unlikely(!intf->beacon)) return -ENOBUFS; @@ -584,17 +581,36 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, */ rt2x00queue_free_skb(intf->beacon); - if (!enable_beacon) { - rt2x00queue_stop_queue(intf->beacon->queue); - mutex_unlock(&intf->beacon_skb_mutex); - return 0; - } + /* + * Clear beacon (single bssid devices don't need to clear the beacon + * since the beacon queue will get stopped anyway). + */ + if (rt2x00dev->ops->lib->clear_beacon) + rt2x00dev->ops->lib->clear_beacon(intf->beacon); + + mutex_unlock(&intf->beacon_skb_mutex); + + return 0; +} + +int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev, + struct ieee80211_vif *vif) +{ + struct rt2x00_intf *intf = vif_to_intf(vif); + struct skb_frame_desc *skbdesc; + struct txentry_desc txdesc; + + if (unlikely(!intf->beacon)) + return -ENOBUFS; + + /* + * Clean up the beacon skb. + */ + rt2x00queue_free_skb(intf->beacon); intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif); - if (!intf->beacon->skb) { - mutex_unlock(&intf->beacon_skb_mutex); + if (!intf->beacon->skb) return -ENOMEM; - } /* * Copy all TX descriptor information into txdesc, @@ -611,13 +627,25 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, skbdesc->entry = intf->beacon; /* - * Send beacon to hardware and enable beacon genaration.. + * Send beacon to hardware. */ rt2x00dev->ops->lib->write_beacon(intf->beacon, &txdesc); + return 0; + +} + +int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, + struct ieee80211_vif *vif) +{ + struct rt2x00_intf *intf = vif_to_intf(vif); + int ret; + + mutex_lock(&intf->beacon_skb_mutex); + ret = rt2x00queue_update_beacon_locked(rt2x00dev, vif); mutex_unlock(&intf->beacon_skb_mutex); - return 0; + return ret; } void rt2x00queue_for_each_entry(struct data_queue *queue, @@ -885,7 +913,7 @@ void rt2x00queue_flush_queue(struct data_queue *queue, bool drop) * The queue flush has failed... */ if (unlikely(!rt2x00queue_empty(queue))) - WARNING(queue->rt2x00dev, "Queue %d failed to flush", queue->qid); + WARNING(queue->rt2x00dev, "Queue %d failed to flush\n", queue->qid); /* * Restore the queue to the previous status diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index e8259ae48ced..6f867eec49cc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h @@ -85,8 +85,6 @@ enum dev_state { STATE_RADIO_OFF, STATE_RADIO_IRQ_ON, STATE_RADIO_IRQ_OFF, - STATE_RADIO_IRQ_ON_ISR, - STATE_RADIO_IRQ_OFF_ISR, }; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 1a9937d5aff6..fbe735f5b352 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -227,7 +227,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) * Schedule the delayed work for reading the TX status * from the device. */ - ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work); + queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); } static void rt2x00usb_kick_tx_entry(struct queue_entry *entry) @@ -320,7 +320,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) * Schedule the delayed work for reading the RX status * from the device. */ - ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work); + queue_work(rt2x00dev->workqueue, &rt2x00dev->rxdone_work); } static void rt2x00usb_kick_rx_entry(struct queue_entry *entry) @@ -429,7 +429,7 @@ void rt2x00usb_flush_queue(struct data_queue *queue) * Schedule the completion handler manually, when this * worker function runs, it should cleanup the queue. */ - ieee80211_queue_work(queue->rt2x00dev->hw, completion); + queue_work(queue->rt2x00dev->workqueue, completion); /* * Wait for a little while to give the driver @@ -453,7 +453,7 @@ static void rt2x00usb_watchdog_tx_status(struct data_queue *queue) WARNING(queue->rt2x00dev, "TX queue %d status timed out," " invoke forced tx handler\n", queue->qid); - ieee80211_queue_work(queue->rt2x00dev->hw, &queue->rt2x00dev->txdone_work); + queue_work(queue->rt2x00dev->workqueue, &queue->rt2x00dev->txdone_work); } void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 8de44dd401e0..dd2164d4d57b 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -551,26 +551,14 @@ static void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00intf_conf *conf, const unsigned int flags) { - unsigned int beacon_base; u32 reg; if (flags & CONFIG_UPDATE_TYPE) { /* - * Clear current synchronisation setup. - * For the Beacon base registers, we only need to clear - * the first byte since that byte contains the VALID and OWNER - * bits which (when set to 0) will invalidate the entire beacon. - */ - beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); - rt2x00pci_register_write(rt2x00dev, beacon_base, 0); - - /* * Enable synchronisation. */ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); - rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, conf->sync); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); } @@ -1154,6 +1142,11 @@ static void rt61pci_start_queue(struct data_queue *queue) rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); break; case QID_BEACON: + /* + * Allow the tbtt tasklet to be scheduled. + */ + tasklet_enable(&rt2x00dev->tbtt_tasklet); + rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); @@ -1233,6 +1226,11 @@ static void rt61pci_stop_queue(struct data_queue *queue) rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); + + /* + * Wait for possibly running tbtt tasklets. + */ + tasklet_disable(&rt2x00dev->tbtt_tasklet); break; default: break; @@ -1719,9 +1717,9 @@ static int rt61pci_init_bbp(struct rt2x00_dev *rt2x00dev) static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, enum dev_state state) { - int mask = (state == STATE_RADIO_IRQ_OFF) || - (state == STATE_RADIO_IRQ_OFF_ISR); + int mask = (state == STATE_RADIO_IRQ_OFF); u32 reg; + unsigned long flags; /* * When interrupts are being enabled, the interrupt registers @@ -1733,12 +1731,21 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®); rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg); + + /* + * Enable tasklets. + */ + tasklet_enable(&rt2x00dev->txstatus_tasklet); + tasklet_enable(&rt2x00dev->rxdone_tasklet); + tasklet_enable(&rt2x00dev->autowake_tasklet); } /* * Only toggle the interrupts bits we are going to use. * Non-checked interrupt bits are disabled by default. */ + spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); rt2x00_set_field32(®, INT_MASK_CSR_TXDONE, mask); rt2x00_set_field32(®, INT_MASK_CSR_RXDONE, mask); @@ -1758,6 +1765,17 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, MCU_INT_MASK_CSR_7, mask); rt2x00_set_field32(®, MCU_INT_MASK_CSR_TWAKEUP, mask); rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); + + spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + + if (state == STATE_RADIO_IRQ_OFF) { + /* + * Ensure that all tasklets are finished. + */ + tasklet_disable(&rt2x00dev->txstatus_tasklet); + tasklet_disable(&rt2x00dev->rxdone_tasklet); + tasklet_disable(&rt2x00dev->autowake_tasklet); + } } static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev) @@ -1833,9 +1851,7 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, rt61pci_disable_radio(rt2x00dev); break; case STATE_RADIO_IRQ_ON: - case STATE_RADIO_IRQ_ON_ISR: case STATE_RADIO_IRQ_OFF: - case STATE_RADIO_IRQ_OFF_ISR: rt61pci_toggle_irq(rt2x00dev, state); break; case STATE_DEEP_SLEEP: @@ -2002,8 +2018,6 @@ static void rt61pci_write_beacon(struct queue_entry *entry, */ rt2x00pci_register_write(rt2x00dev, TXRX_CSR10, 0x00001008); - rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); @@ -2014,6 +2028,32 @@ static void rt61pci_write_beacon(struct queue_entry *entry, entry->skb = NULL; } +static void rt61pci_clear_beacon(struct queue_entry *entry) +{ + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + u32 reg; + + /* + * Disable beaconing while we are reloading the beacon data, + * otherwise we might be sending out invalid data. + */ + rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); + + /* + * Clear beacon. + */ + rt2x00pci_register_write(rt2x00dev, + HW_BEACON_OFFSET(entry->entry_idx), 0); + + /* + * Enable beaconing again. + */ + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); +} + /* * RX control handlers */ @@ -2078,9 +2118,8 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, rxdesc->flags |= RX_FLAG_IV_STRIPPED; /* - * FIXME: Legacy driver indicates that the frame does - * contain the Michael Mic. Unfortunately, in rt2x00 - * the MIC seems to be missing completely... + * The hardware has already checked the Michael Mic and has + * stripped it from the frame. Signal this to mac80211. */ rxdesc->flags |= RX_FLAG_MMIC_STRIPPED; @@ -2211,61 +2250,80 @@ static void rt61pci_wakeup(struct rt2x00_dev *rt2x00dev) rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); } -static irqreturn_t rt61pci_interrupt_thread(int irq, void *dev_instance) +static void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, + struct rt2x00_field32 irq_field) { - struct rt2x00_dev *rt2x00dev = dev_instance; - u32 reg = rt2x00dev->irqvalue[0]; - u32 reg_mcu = rt2x00dev->irqvalue[1]; + unsigned long flags; + u32 reg; /* - * Handle interrupts, walk through all bits - * and run the tasks, the bits are checked in order of - * priority. + * Enable a single interrupt. The interrupt mask register + * access needs locking. */ + spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); - /* - * 1 - Rx ring done interrupt. - */ - if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RXDONE)) - rt2x00pci_rxdone(rt2x00dev); + rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); + rt2x00_set_field32(®, irq_field, 0); + rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); - /* - * 2 - Tx ring done interrupt. - */ - if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TXDONE)) - rt61pci_txdone(rt2x00dev); + spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); +} - /* - * 3 - Handle MCU command done. - */ - if (reg_mcu) - rt2x00pci_register_write(rt2x00dev, - M2H_CMD_DONE_CSR, 0xffffffff); +static void rt61pci_enable_mcu_interrupt(struct rt2x00_dev *rt2x00dev, + struct rt2x00_field32 irq_field) +{ + unsigned long flags; + u32 reg; /* - * 4 - MCU Autowakeup interrupt. + * Enable a single MCU interrupt. The interrupt mask register + * access needs locking. */ - if (rt2x00_get_field32(reg_mcu, MCU_INT_SOURCE_CSR_TWAKEUP)) - rt61pci_wakeup(rt2x00dev); + spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); - /* - * 5 - Beacon done interrupt. - */ - if (rt2x00_get_field32(reg, INT_SOURCE_CSR_BEACON_DONE)) - rt2x00lib_beacondone(rt2x00dev); + rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, ®); + rt2x00_set_field32(®, irq_field, 0); + rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); - /* Enable interrupts again. */ - rt2x00dev->ops->lib->set_device_state(rt2x00dev, - STATE_RADIO_IRQ_ON_ISR); - return IRQ_HANDLED; + spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); +} + +static void rt61pci_txstatus_tasklet(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + rt61pci_txdone(rt2x00dev); + rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TXDONE); +} + +static void rt61pci_tbtt_tasklet(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + rt2x00lib_beacondone(rt2x00dev); + rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_BEACON_DONE); +} + +static void rt61pci_rxdone_tasklet(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + rt2x00pci_rxdone(rt2x00dev); + rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE); } +static void rt61pci_autowake_tasklet(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + rt61pci_wakeup(rt2x00dev); + rt2x00pci_register_write(rt2x00dev, + M2H_CMD_DONE_CSR, 0xffffffff); + rt61pci_enable_mcu_interrupt(rt2x00dev, MCU_INT_MASK_CSR_TWAKEUP); +} static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) { struct rt2x00_dev *rt2x00dev = dev_instance; - u32 reg_mcu; - u32 reg; + u32 reg_mcu, mask_mcu; + u32 reg, mask; + unsigned long flags; /* * Get the interrupt sources & saved to local variable. @@ -2283,14 +2341,46 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return IRQ_HANDLED; - /* Store irqvalues for use in the interrupt thread. */ - rt2x00dev->irqvalue[0] = reg; - rt2x00dev->irqvalue[1] = reg_mcu; + /* + * Schedule tasklets for interrupt handling. + */ + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RXDONE)) + tasklet_schedule(&rt2x00dev->rxdone_tasklet); + + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TXDONE)) + tasklet_schedule(&rt2x00dev->txstatus_tasklet); - /* Disable interrupts, will be enabled again in the interrupt thread. */ - rt2x00dev->ops->lib->set_device_state(rt2x00dev, - STATE_RADIO_IRQ_OFF_ISR); - return IRQ_WAKE_THREAD; + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_BEACON_DONE)) + tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet); + + if (rt2x00_get_field32(reg_mcu, MCU_INT_SOURCE_CSR_TWAKEUP)) + tasklet_schedule(&rt2x00dev->autowake_tasklet); + + /* + * Since INT_MASK_CSR and INT_SOURCE_CSR use the same bits + * for interrupts and interrupt masks we can just use the value of + * INT_SOURCE_CSR to create the interrupt mask. + */ + mask = reg; + mask_mcu = reg_mcu; + + /* + * Disable all interrupts for which a tasklet was scheduled right now, + * the tasklet will reenable the appropriate interrupts. + */ + spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + + rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); + reg |= mask; + rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, ®); + reg |= mask_mcu; + rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); + + spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + + return IRQ_HANDLED; } /* @@ -2884,7 +2974,10 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .irq_handler = rt61pci_interrupt, - .irq_handler_thread = rt61pci_interrupt_thread, + .txstatus_tasklet = rt61pci_txstatus_tasklet, + .tbtt_tasklet = rt61pci_tbtt_tasklet, + .rxdone_tasklet = rt61pci_rxdone_tasklet, + .autowake_tasklet = rt61pci_autowake_tasklet, .probe_hw = rt61pci_probe_hw, .get_firmware_name = rt61pci_get_firmware_name, .check_firmware = rt61pci_check_firmware, @@ -2903,6 +2996,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .stop_queue = rt61pci_stop_queue, .write_tx_desc = rt61pci_write_tx_desc, .write_beacon = rt61pci_write_beacon, + .clear_beacon = rt61pci_clear_beacon, .fill_rxdone = rt61pci_fill_rxdone, .config_shared_key = rt61pci_config_shared_key, .config_pairwise_key = rt61pci_config_pairwise_key, diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 029be3c6c030..5ff72deea8d4 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -502,26 +502,14 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00intf_conf *conf, const unsigned int flags) { - unsigned int beacon_base; u32 reg; if (flags & CONFIG_UPDATE_TYPE) { /* - * Clear current synchronisation setup. - * For the Beacon base registers we only need to clear - * the first byte since that byte contains the VALID and OWNER - * bits which (when set to 0) will invalidate the entire beacon. - */ - beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); - rt2x00usb_register_write(rt2x00dev, beacon_base, 0); - - /* * Enable synchronisation. */ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); - rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, conf->sync); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); } @@ -1440,9 +1428,7 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, rt73usb_disable_radio(rt2x00dev); break; case STATE_RADIO_IRQ_ON: - case STATE_RADIO_IRQ_ON_ISR: case STATE_RADIO_IRQ_OFF: - case STATE_RADIO_IRQ_OFF_ISR: /* No support, but no error either */ break; case STATE_DEEP_SLEEP: @@ -1590,8 +1576,6 @@ static void rt73usb_write_beacon(struct queue_entry *entry, */ rt2x00usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008); - rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); @@ -1602,6 +1586,33 @@ static void rt73usb_write_beacon(struct queue_entry *entry, entry->skb = NULL; } +static void rt73usb_clear_beacon(struct queue_entry *entry) +{ + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + unsigned int beacon_base; + u32 reg; + + /* + * Disable beaconing while we are reloading the beacon data, + * otherwise we might be sending out invalid data. + */ + rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); + + /* + * Clear beacon. + */ + beacon_base = HW_BEACON_OFFSET(entry->entry_idx); + rt2x00usb_register_write(rt2x00dev, beacon_base, 0); + + /* + * Enable beaconing again. + */ + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); +} + static int rt73usb_get_tx_data_len(struct queue_entry *entry) { int length; @@ -1698,9 +1709,8 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, rxdesc->flags |= RX_FLAG_IV_STRIPPED; /* - * FIXME: Legacy driver indicates that the frame does - * contain the Michael Mic. Unfortunately, in rt2x00 - * the MIC seems to be missing completely... + * The hardware has already checked the Michael Mic and has + * stripped it from the frame. Signal this to mac80211. */ rxdesc->flags |= RX_FLAG_MMIC_STRIPPED; @@ -2313,6 +2323,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .flush_queue = rt2x00usb_flush_queue, .write_tx_desc = rt73usb_write_tx_desc, .write_beacon = rt73usb_write_beacon, + .clear_beacon = rt73usb_clear_beacon, .get_tx_data_len = rt73usb_get_tx_data_len, .fill_rxdone = rt73usb_fill_rxdone, .config_shared_key = rt73usb_config_shared_key, diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index d6a924a05654..25d2d667ffba 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -748,7 +748,8 @@ static void rtl_op_sta_notify(struct ieee80211_hw *hw, static int rtl_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 * ssn) + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size) { struct rtl_priv *rtlpriv = rtl_priv(hw); diff --git a/drivers/net/wireless/wl1251/acx.c b/drivers/net/wireless/wl1251/acx.c index 64a0214cfb29..ef8370edace7 100644 --- a/drivers/net/wireless/wl1251/acx.c +++ b/drivers/net/wireless/wl1251/acx.c @@ -776,6 +776,31 @@ out: return ret; } +int wl1251_acx_low_rssi(struct wl1251 *wl, s8 threshold, u8 weight, + u8 depth, enum wl1251_acx_low_rssi_type type) +{ + struct acx_low_rssi *rssi; + int ret; + + wl1251_debug(DEBUG_ACX, "acx low rssi"); + + rssi = kzalloc(sizeof(*rssi), GFP_KERNEL); + if (!rssi) + return -ENOMEM; + + rssi->threshold = threshold; + rssi->weight = weight; + rssi->depth = depth; + rssi->type = type; + + ret = wl1251_cmd_configure(wl, ACX_LOW_RSSI, rssi, sizeof(*rssi)); + if (ret < 0) + wl1251_warning("failed to set low rssi threshold: %d", ret); + + kfree(rssi); + return ret; +} + int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble) { struct acx_preamble *acx; @@ -978,6 +1003,34 @@ out: return ret; } +int wl1251_acx_bet_enable(struct wl1251 *wl, enum wl1251_acx_bet_mode mode, + u8 max_consecutive) +{ + struct wl1251_acx_bet_enable *acx; + int ret; + + wl1251_debug(DEBUG_ACX, "acx bet enable"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->enable = mode; + acx->max_consecutive = max_consecutive; + + ret = wl1251_cmd_configure(wl, ACX_BET_ENABLE, acx, sizeof(*acx)); + if (ret < 0) { + wl1251_warning("wl1251 acx bet enable failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, u8 aifs, u16 txop) { diff --git a/drivers/net/wireless/wl1251/acx.h b/drivers/net/wireless/wl1251/acx.h index efcc3aaca14f..c2ba100f9b1a 100644 --- a/drivers/net/wireless/wl1251/acx.h +++ b/drivers/net/wireless/wl1251/acx.h @@ -399,6 +399,49 @@ struct acx_rts_threshold { u8 pad[2]; } __packed; +enum wl1251_acx_low_rssi_type { + /* + * The event is a "Level" indication which keeps triggering + * as long as the average RSSI is below the threshold. + */ + WL1251_ACX_LOW_RSSI_TYPE_LEVEL = 0, + + /* + * The event is an "Edge" indication which triggers + * only when the RSSI threshold is crossed from above. + */ + WL1251_ACX_LOW_RSSI_TYPE_EDGE = 1, +}; + +struct acx_low_rssi { + struct acx_header header; + + /* + * The threshold (in dBm) below (or above after low rssi + * indication) which the firmware generates an interrupt to the + * host. This parameter is signed. + */ + s8 threshold; + + /* + * The weight of the current RSSI sample, before adding the new + * sample, that is used to calculate the average RSSI. + */ + u8 weight; + + /* + * The number of Beacons/Probe response frames that will be + * received before issuing the Low or Regained RSSI event. + */ + u8 depth; + + /* + * Configures how the Low RSSI Event is triggered. Refer to + * enum wl1251_acx_low_rssi_type for more. + */ + u8 type; +} __packed; + struct acx_beacon_filter_option { struct acx_header header; @@ -1164,6 +1207,31 @@ struct wl1251_acx_wr_tbtt_and_dtim { u8 padding; } __packed; +enum wl1251_acx_bet_mode { + WL1251_ACX_BET_DISABLE = 0, + WL1251_ACX_BET_ENABLE = 1, +}; + +struct wl1251_acx_bet_enable { + struct acx_header header; + + /* + * Specifies if beacon early termination procedure is enabled or + * disabled, see enum wl1251_acx_bet_mode. + */ + u8 enable; + + /* + * Specifies the maximum number of consecutive beacons that may be + * early terminated. After this number is reached at least one full + * beacon must be correctly received in FW before beacon ET + * resumes. Range 0 - 255. + */ + u8 max_consecutive; + + u8 padding[2]; +} __packed; + struct wl1251_acx_ac_cfg { struct acx_header header; @@ -1393,6 +1461,8 @@ int wl1251_acx_cca_threshold(struct wl1251 *wl); int wl1251_acx_bcn_dtim_options(struct wl1251 *wl); int wl1251_acx_aid(struct wl1251 *wl, u16 aid); int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask); +int wl1251_acx_low_rssi(struct wl1251 *wl, s8 threshold, u8 weight, + u8 depth, enum wl1251_acx_low_rssi_type type); int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble); int wl1251_acx_cts_protect(struct wl1251 *wl, enum acx_ctsprotect_type ctsprotect); @@ -1401,6 +1471,8 @@ int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime); int wl1251_acx_rate_policies(struct wl1251 *wl); int wl1251_acx_mem_cfg(struct wl1251 *wl); int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim); +int wl1251_acx_bet_enable(struct wl1251 *wl, enum wl1251_acx_bet_mode mode, + u8 max_consecutive); int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, u8 aifs, u16 txop); int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, diff --git a/drivers/net/wireless/wl1251/event.c b/drivers/net/wireless/wl1251/event.c index 712372e50a87..dfc4579acb06 100644 --- a/drivers/net/wireless/wl1251/event.c +++ b/drivers/net/wireless/wl1251/event.c @@ -90,6 +90,24 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox) } } + if (wl->vif && wl->rssi_thold) { + if (vector & ROAMING_TRIGGER_LOW_RSSI_EVENT_ID) { + wl1251_debug(DEBUG_EVENT, + "ROAMING_TRIGGER_LOW_RSSI_EVENT"); + ieee80211_cqm_rssi_notify(wl->vif, + NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, + GFP_KERNEL); + } + + if (vector & ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID) { + wl1251_debug(DEBUG_EVENT, + "ROAMING_TRIGGER_REGAINED_RSSI_EVENT"); + ieee80211_cqm_rssi_notify(wl->vif, + NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, + GFP_KERNEL); + } + } + return 0; } diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c index 40372bac9482..5a1c13878eaf 100644 --- a/drivers/net/wireless/wl1251/main.c +++ b/drivers/net/wireless/wl1251/main.c @@ -502,6 +502,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) wl->psm = 0; wl->tx_queue_stopped = false; wl->power_level = WL1251_DEFAULT_POWER_LEVEL; + wl->rssi_thold = 0; wl->channel = WL1251_DEFAULT_CHANNEL; wl1251_debugfs_reset(wl); @@ -959,6 +960,16 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out; + if (changed & BSS_CHANGED_CQM) { + ret = wl1251_acx_low_rssi(wl, bss_conf->cqm_rssi_thold, + WL1251_DEFAULT_LOW_RSSI_WEIGHT, + WL1251_DEFAULT_LOW_RSSI_DEPTH, + WL1251_ACX_LOW_RSSI_TYPE_EDGE); + if (ret < 0) + goto out; + wl->rssi_thold = bss_conf->cqm_rssi_thold; + } + if (changed & BSS_CHANGED_BSSID) { memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); @@ -1313,9 +1324,11 @@ int wl1251_init_ieee80211(struct wl1251 *wl) wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_BEACON_FILTER | - IEEE80211_HW_SUPPORTS_UAPSD; + IEEE80211_HW_SUPPORTS_UAPSD | + IEEE80211_HW_SUPPORTS_CQM_RSSI; - wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); wl->hw->wiphy->max_scan_ssids = 1; wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; @@ -1377,6 +1390,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void) wl->psm_requested = false; wl->tx_queue_stopped = false; wl->power_level = WL1251_DEFAULT_POWER_LEVEL; + wl->rssi_thold = 0; wl->beacon_int = WL1251_DEFAULT_BEACON_INT; wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; wl->vif = NULL; diff --git a/drivers/net/wireless/wl1251/ps.c b/drivers/net/wireless/wl1251/ps.c index 5ed47c8373d2..9ba23ede51bd 100644 --- a/drivers/net/wireless/wl1251/ps.c +++ b/drivers/net/wireless/wl1251/ps.c @@ -153,6 +153,11 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) if (ret < 0) return ret; + ret = wl1251_acx_bet_enable(wl, WL1251_ACX_BET_ENABLE, + WL1251_DEFAULT_BET_CONSECUTIVE); + if (ret < 0) + return ret; + ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); if (ret < 0) return ret; @@ -170,6 +175,12 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) if (ret < 0) return ret; + /* disable BET */ + ret = wl1251_acx_bet_enable(wl, WL1251_ACX_BET_DISABLE, + WL1251_DEFAULT_BET_CONSECUTIVE); + if (ret < 0) + return ret; + /* disable beacon filtering */ ret = wl1251_acx_beacon_filter_opt(wl, false); if (ret < 0) diff --git a/drivers/net/wireless/wl1251/rx.c b/drivers/net/wireless/wl1251/rx.c index efa53607d5c9..b659e15c78df 100644 --- a/drivers/net/wireless/wl1251/rx.c +++ b/drivers/net/wireless/wl1251/rx.c @@ -78,7 +78,8 @@ static void wl1251_rx_status(struct wl1251 *wl, */ wl->noise = desc->rssi - desc->snr / 2; - status->freq = ieee80211_channel_to_frequency(desc->channel); + status->freq = ieee80211_channel_to_frequency(desc->channel, + status->band); status->flag |= RX_FLAG_TSFT; @@ -95,8 +96,52 @@ static void wl1251_rx_status(struct wl1251 *wl, if (unlikely(!(desc->flags & RX_DESC_VALID_FCS))) status->flag |= RX_FLAG_FAILED_FCS_CRC; + switch (desc->rate) { + /* skip 1 and 12 Mbps because they have same value 0x0a */ + case RATE_2MBPS: + status->rate_idx = 1; + break; + case RATE_5_5MBPS: + status->rate_idx = 2; + break; + case RATE_11MBPS: + status->rate_idx = 3; + break; + case RATE_6MBPS: + status->rate_idx = 4; + break; + case RATE_9MBPS: + status->rate_idx = 5; + break; + case RATE_18MBPS: + status->rate_idx = 7; + break; + case RATE_24MBPS: + status->rate_idx = 8; + break; + case RATE_36MBPS: + status->rate_idx = 9; + break; + case RATE_48MBPS: + status->rate_idx = 10; + break; + case RATE_54MBPS: + status->rate_idx = 11; + break; + } + + /* for 1 and 12 Mbps we have to check the modulation */ + if (desc->rate == RATE_1MBPS) { + if (!(desc->mod_pre & OFDM_RATE_BIT)) + /* CCK -> RATE_1MBPS */ + status->rate_idx = 0; + else + /* OFDM -> RATE_12MBPS */ + status->rate_idx = 6; + } - /* FIXME: set status->rate_idx */ + if (desc->mod_pre & SHORT_PREAMBLE_BIT) + status->flag |= RX_FLAG_SHORTPRE; } static void wl1251_rx_body(struct wl1251 *wl, diff --git a/drivers/net/wireless/wl1251/tx.c b/drivers/net/wireless/wl1251/tx.c index 554b4f9a3d3e..28121c590a2b 100644 --- a/drivers/net/wireless/wl1251/tx.c +++ b/drivers/net/wireless/wl1251/tx.c @@ -213,16 +213,30 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb, wl1251_debug(DEBUG_TX, "skb offset %d", offset); /* check whether the current skb can be used */ - if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { - unsigned char *src = skb->data; + if (skb_cloned(skb) || (skb_tailroom(skb) < offset)) { + struct sk_buff *newskb = skb_copy_expand(skb, 0, 3, + GFP_KERNEL); + + if (unlikely(newskb == NULL)) { + wl1251_error("Can't allocate skb!"); + return -EINVAL; + } - /* align the buffer on a 4-byte boundary */ + tx_hdr = (struct tx_double_buffer_desc *) newskb->data; + + dev_kfree_skb_any(skb); + wl->tx_frames[tx_hdr->id] = skb = newskb; + + offset = (4 - (long)skb->data) & 0x03; + wl1251_debug(DEBUG_TX, "new skb offset %d", offset); + } + + /* align the buffer on a 4-byte boundary */ + if (offset) { + unsigned char *src = skb->data; skb_reserve(skb, offset); memmove(skb->data, src, skb->len); tx_hdr = (struct tx_double_buffer_desc *) skb->data; - } else { - wl1251_info("No handler, fixme!"); - return -EINVAL; } } @@ -368,7 +382,7 @@ static void wl1251_tx_packet_cb(struct wl1251 *wl, { struct ieee80211_tx_info *info; struct sk_buff *skb; - int hdrlen, ret; + int hdrlen; u8 *frame; skb = wl->tx_frames[result->id]; @@ -407,40 +421,12 @@ static void wl1251_tx_packet_cb(struct wl1251 *wl, ieee80211_tx_status(wl->hw, skb); wl->tx_frames[result->id] = NULL; - - if (wl->tx_queue_stopped) { - wl1251_debug(DEBUG_TX, "cb: queue was stopped"); - - skb = skb_dequeue(&wl->tx_queue); - - /* The skb can be NULL because tx_work might have been - scheduled before the queue was stopped making the - queue empty */ - - if (skb) { - ret = wl1251_tx_frame(wl, skb); - if (ret == -EBUSY) { - /* firmware buffer is still full */ - wl1251_debug(DEBUG_TX, "cb: fw buffer " - "still full"); - skb_queue_head(&wl->tx_queue, skb); - return; - } else if (ret < 0) { - dev_kfree_skb(skb); - return; - } - } - - wl1251_debug(DEBUG_TX, "cb: waking queues"); - ieee80211_wake_queues(wl->hw); - wl->tx_queue_stopped = false; - } } /* Called upon reception of a TX complete interrupt */ void wl1251_tx_complete(struct wl1251 *wl) { - int i, result_index, num_complete = 0; + int i, result_index, num_complete = 0, queue_len; struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr; unsigned long flags; @@ -471,18 +457,22 @@ void wl1251_tx_complete(struct wl1251 *wl) } } - if (wl->tx_queue_stopped - && - skb_queue_len(&wl->tx_queue) <= WL1251_TX_QUEUE_LOW_WATERMARK){ + queue_len = skb_queue_len(&wl->tx_queue); - /* firmware buffer has space, restart queues */ + if ((num_complete > 0) && (queue_len > 0)) { + /* firmware buffer has space, reschedule tx_work */ + wl1251_debug(DEBUG_TX, "tx_complete: reschedule tx_work"); + ieee80211_queue_work(wl->hw, &wl->tx_work); + } + + if (wl->tx_queue_stopped && + queue_len <= WL1251_TX_QUEUE_LOW_WATERMARK) { + /* tx_queue has space, restart queues */ wl1251_debug(DEBUG_TX, "tx_complete: waking queues"); spin_lock_irqsave(&wl->wl_lock, flags); ieee80211_wake_queues(wl->hw); wl->tx_queue_stopped = false; spin_unlock_irqrestore(&wl->wl_lock, flags); - ieee80211_queue_work(wl->hw, &wl->tx_work); - } /* Every completed frame needs to be acknowledged */ diff --git a/drivers/net/wireless/wl1251/wl1251.h b/drivers/net/wireless/wl1251/wl1251.h index c0ce2c8b43b8..bb23cd522b22 100644 --- a/drivers/net/wireless/wl1251/wl1251.h +++ b/drivers/net/wireless/wl1251/wl1251.h @@ -370,6 +370,8 @@ struct wl1251 { /* in dBm */ int power_level; + int rssi_thold; + struct wl1251_stats stats; struct wl1251_debugfs debugfs; @@ -410,6 +412,8 @@ void wl1251_disable_interrupts(struct wl1251 *wl); #define WL1251_DEFAULT_CHANNEL 0 +#define WL1251_DEFAULT_BET_CONSECUTIVE 10 + #define CHIP_ID_1251_PG10 (0x7010101) #define CHIP_ID_1251_PG11 (0x7020101) #define CHIP_ID_1251_PG12 (0x7030101) @@ -431,4 +435,7 @@ void wl1251_disable_interrupts(struct wl1251 *wl); #define WL1251_PART_WORK_REG_START REGISTERS_BASE #define WL1251_PART_WORK_REG_SIZE REGISTERS_WORK_SIZE +#define WL1251_DEFAULT_LOW_RSSI_WEIGHT 10 +#define WL1251_DEFAULT_LOW_RSSI_DEPTH 10 + #endif diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index cc4068d2b4a8..afdc601aa7ea 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -751,10 +751,10 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) return 0; } -int wl1271_acx_rate_policies(struct wl1271 *wl) +int wl1271_acx_sta_rate_policies(struct wl1271 *wl) { - struct acx_rate_policy *acx; - struct conf_tx_rate_class *c = &wl->conf.tx.rc_conf; + struct acx_sta_rate_policy *acx; + struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf; int idx = 0; int ret = 0; @@ -794,6 +794,38 @@ out: return ret; } +int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c, + u8 idx) +{ + struct acx_ap_rate_policy *acx; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx ap rate policy"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->rate_policy.enabled_rates = cpu_to_le32(c->enabled_rates); + acx->rate_policy.short_retry_limit = c->short_retry_limit; + acx->rate_policy.long_retry_limit = c->long_retry_limit; + acx->rate_policy.aflags = c->aflags; + + acx->rate_policy_idx = cpu_to_le32(idx); + + ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of ap rate policy failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, u8 aifsn, u16 txop) { @@ -1233,6 +1265,7 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, struct wl1271_acx_ht_capabilities *acx; u8 mac_address[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; int ret = 0; + u32 ht_capabilites = 0; wl1271_debug(DEBUG_ACX, "acx ht capabilities setting"); @@ -1244,16 +1277,16 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, /* Allow HT Operation ? */ if (allow_ht_operation) { - acx->ht_capabilites = + ht_capabilites = WL1271_ACX_FW_CAP_HT_OPERATION; if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD) - acx->ht_capabilites |= + ht_capabilites |= WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT; if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20) - acx->ht_capabilites |= + ht_capabilites |= WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS; if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT) - acx->ht_capabilites |= + ht_capabilites |= WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION; /* get data from A-MPDU parameters field */ @@ -1261,10 +1294,10 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, acx->ampdu_min_spacing = ht_cap->ampdu_density; memcpy(acx->mac_address, mac_address, ETH_ALEN); - } else { /* HT operations are not allowed */ - acx->ht_capabilites = 0; } + acx->ht_capabilites = cpu_to_le32(ht_capabilites); + ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("acx ht capabilities setting failed: %d", ret); @@ -1309,6 +1342,91 @@ out: return ret; } +/* Configure BA session initiator/receiver parameters setting in the FW. */ +int wl1271_acx_set_ba_session(struct wl1271 *wl, + enum ieee80211_back_parties direction, + u8 tid_index, u8 policy) +{ + struct wl1271_acx_ba_session_policy *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx ba session setting"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* ANY role */ + acx->role_id = 0xff; + acx->tid = tid_index; + acx->enable = policy; + acx->ba_direction = direction; + + switch (direction) { + case WLAN_BACK_INITIATOR: + acx->win_size = wl->conf.ht.tx_ba_win_size; + acx->inactivity_timeout = wl->conf.ht.inactivity_timeout; + break; + case WLAN_BACK_RECIPIENT: + acx->win_size = RX_BA_WIN_SIZE; + acx->inactivity_timeout = 0; + break; + default: + wl1271_error("Incorrect acx command id=%x\n", direction); + ret = -EINVAL; + goto out; + } + + ret = wl1271_cmd_configure(wl, + ACX_BA_SESSION_POLICY_CFG, + acx, + sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx ba session setting failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +/* setup BA session receiver setting in the FW. */ +int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, + bool enable) +{ + struct wl1271_acx_ba_receiver_setup *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx ba receiver session setting"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* Single link for now */ + acx->link_id = 1; + acx->tid = tid_index; + acx->enable = enable; + acx->win_size = 0; + acx->ssn = ssn; + + ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx, + sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx ba receiver session failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime) { struct wl1271_acx_fw_tsf_information *tsf_info; @@ -1334,3 +1452,27 @@ out: kfree(tsf_info); return ret; } + +int wl1271_acx_max_tx_retry(struct wl1271 *wl) +{ + struct wl1271_acx_max_tx_retry *acx = NULL; + int ret; + + wl1271_debug(DEBUG_ACX, "acx max tx retry"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) + return -ENOMEM; + + acx->max_tx_retry = cpu_to_le16(wl->conf.tx.ap_max_tx_retries); + + ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx max tx retry failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 7bd8e4db4a71..4bbaf04f434e 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -747,13 +747,23 @@ struct acx_rate_class { #define ACX_TX_BASIC_RATE 0 #define ACX_TX_AP_FULL_RATE 1 #define ACX_TX_RATE_POLICY_CNT 2 -struct acx_rate_policy { +struct acx_sta_rate_policy { struct acx_header header; __le32 rate_class_cnt; struct acx_rate_class rate_class[CONF_TX_MAX_RATE_CLASSES]; } __packed; + +#define ACX_TX_AP_MODE_MGMT_RATE 4 +#define ACX_TX_AP_MODE_BCST_RATE 5 +struct acx_ap_rate_policy { + struct acx_header header; + + __le32 rate_policy_idx; + struct acx_rate_class rate_policy; +} __packed; + struct acx_ac_cfg { struct acx_header header; u8 ac; @@ -1051,6 +1061,59 @@ struct wl1271_acx_ht_information { u8 padding[3]; } __packed; +#define RX_BA_WIN_SIZE 8 + +struct wl1271_acx_ba_session_policy { + struct acx_header header; + /* + * Specifies role Id, Range 0-7, 0xFF means ANY role. + * Future use. For now this field is irrelevant + */ + u8 role_id; + /* + * Specifies Link Id, Range 0-31, 0xFF means ANY Link Id. + * Not applicable if Role Id is set to ANY. + */ + u8 link_id; + + u8 tid; + + u8 enable; + + /* Windows size in number of packets */ + u16 win_size; + + /* + * As initiator inactivity timeout in time units(TU) of 1024us. + * As receiver reserved + */ + u16 inactivity_timeout; + + /* Initiator = 1/Receiver = 0 */ + u8 ba_direction; + + u8 padding[3]; +} __packed; + +struct wl1271_acx_ba_receiver_setup { + struct acx_header header; + + /* Specifies Link Id, Range 0-31, 0xFF means ANY Link Id */ + u8 link_id; + + u8 tid; + + u8 enable; + + u8 padding[1]; + + /* Windows size in number of packets */ + u16 win_size; + + /* BA session starting sequence number. RANGE 0-FFF */ + u16 ssn; +} __packed; + struct wl1271_acx_fw_tsf_information { struct acx_header header; @@ -1062,6 +1125,17 @@ struct wl1271_acx_fw_tsf_information { u8 padding[3]; } __packed; +struct wl1271_acx_max_tx_retry { + struct acx_header header; + + /* + * the number of frames transmission failures before + * issuing the aging event. + */ + __le16 max_tx_retry; + u8 padding_1[2]; +} __packed; + enum { ACX_WAKE_UP_CONDITIONS = 0x0002, ACX_MEM_CFG = 0x0003, @@ -1113,12 +1187,13 @@ enum { ACX_RSSI_SNR_WEIGHTS = 0x0052, ACX_KEEP_ALIVE_MODE = 0x0053, ACX_SET_KEEP_ALIVE_CONFIG = 0x0054, - ACX_BA_SESSION_RESPONDER_POLICY = 0x0055, - ACX_BA_SESSION_INITIATOR_POLICY = 0x0056, + ACX_BA_SESSION_POLICY_CFG = 0x0055, + ACX_BA_SESSION_RX_SETUP = 0x0056, ACX_PEER_HT_CAP = 0x0057, ACX_HT_BSS_OPERATION = 0x0058, ACX_COEX_ACTIVITY = 0x0059, ACX_SET_DCO_ITRIM_PARAMS = 0x0061, + ACX_MAX_TX_FAILURE = 0x0072, DOT11_RX_MSDU_LIFE_TIME = 0x1004, DOT11_CUR_TX_PWR = 0x100D, DOT11_RX_DOT11_MODE = 0x1012, @@ -1160,7 +1235,9 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble); int wl1271_acx_cts_protect(struct wl1271 *wl, enum acx_ctsprotect_type ctsprotect); int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats); -int wl1271_acx_rate_policies(struct wl1271 *wl); +int wl1271_acx_sta_rate_policies(struct wl1271 *wl); +int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c, + u8 idx); int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, u8 aifsn, u16 txop); int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, @@ -1185,6 +1262,12 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, bool allow_ht_operation); int wl1271_acx_set_ht_information(struct wl1271 *wl, u16 ht_operation_mode); +int wl1271_acx_set_ba_session(struct wl1271 *wl, + enum ieee80211_back_parties direction, + u8 tid_index, u8 policy); +int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, + bool enable); int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); +int wl1271_acx_max_tx_retry(struct wl1271 *wl); #endif /* __WL1271_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 4df04f84d7f1..1ffbad67d2d8 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -28,6 +28,7 @@ #include "boot.h" #include "io.h" #include "event.h" +#include "rx.h" static struct wl1271_partition_set part_table[PART_TABLE_LEN] = { [PART_DOWN] = { @@ -100,6 +101,22 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); } +static void wl1271_parse_fw_ver(struct wl1271 *wl) +{ + int ret; + + ret = sscanf(wl->chip.fw_ver_str + 4, "%u.%u.%u.%u.%u", + &wl->chip.fw_ver[0], &wl->chip.fw_ver[1], + &wl->chip.fw_ver[2], &wl->chip.fw_ver[3], + &wl->chip.fw_ver[4]); + + if (ret != 5) { + wl1271_warning("fw version incorrect value"); + memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver)); + return; + } +} + static void wl1271_boot_fw_version(struct wl1271 *wl) { struct wl1271_static_data static_data; @@ -107,11 +124,13 @@ static void wl1271_boot_fw_version(struct wl1271 *wl) wl1271_read(wl, wl->cmd_box_addr, &static_data, sizeof(static_data), false); - strncpy(wl->chip.fw_ver, static_data.fw_version, - sizeof(wl->chip.fw_ver)); + strncpy(wl->chip.fw_ver_str, static_data.fw_version, + sizeof(wl->chip.fw_ver_str)); /* make sure the string is NULL-terminated */ - wl->chip.fw_ver[sizeof(wl->chip.fw_ver) - 1] = '\0'; + wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0'; + + wl1271_parse_fw_ver(wl); } static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, @@ -231,7 +250,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) */ if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { - if (wl->nvs->general_params.dual_mode_select) + /* for now 11a is unsupported in AP mode */ + if (wl->bss_type != BSS_TYPE_AP_BSS && + wl->nvs->general_params.dual_mode_select) wl->enable_11a = true; } @@ -431,6 +452,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) PSPOLL_DELIVERY_FAILURE_EVENT_ID | SOFT_GEMINI_SENSE_EVENT_ID; + if (wl->bss_type == BSS_TYPE_AP_BSS) + wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID; + ret = wl1271_event_unmask(wl); if (ret < 0) { wl1271_error("EVENT mask setting failed"); @@ -595,8 +619,7 @@ int wl1271_boot(struct wl1271 *wl) wl1271_boot_enable_interrupts(wl); /* set the wl1271 default filters */ - wl->rx_config = WL1271_DEFAULT_RX_CONFIG; - wl->rx_filter = WL1271_DEFAULT_RX_FILTER; + wl1271_set_default_filters(wl); wl1271_event_mbox_config(wl); diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 0106628aa5a2..1bb8be5e805b 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -36,6 +36,7 @@ #include "wl12xx_80211.h" #include "cmd.h" #include "event.h" +#include "tx.h" #define WL1271_CMD_FAST_POLL_COUNT 50 @@ -221,7 +222,7 @@ int wl1271_cmd_ext_radio_parms(struct wl1271 *wl) * Poll the mailbox event field until any of the bits in the mask is set or a * timeout occurs (WL1271_EVENT_TIMEOUT in msecs) */ -static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) +static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask) { u32 events_vector, event; unsigned long timeout; @@ -230,7 +231,8 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) do { if (time_after(jiffies, timeout)) { - ieee80211_queue_work(wl->hw, &wl->recovery_work); + wl1271_debug(DEBUG_CMD, "timeout waiting for event %d", + (int)mask); return -ETIMEDOUT; } @@ -248,6 +250,19 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) return 0; } +static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) +{ + int ret; + + ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask); + if (ret != 0) { + ieee80211_queue_work(wl->hw, &wl->recovery_work); + return ret; + } + + return 0; +} + int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type) { struct wl1271_cmd_join *join; @@ -490,8 +505,8 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, cmd->len = cpu_to_le16(buf_len); cmd->template_type = template_id; cmd->enabled_rates = cpu_to_le32(rates); - cmd->short_retry_limit = wl->conf.tx.rc_conf.short_retry_limit; - cmd->long_retry_limit = wl->conf.tx.rc_conf.long_retry_limit; + cmd->short_retry_limit = wl->conf.tx.tmpl_short_retry_limit; + cmd->long_retry_limit = wl->conf.tx.tmpl_long_retry_limit; cmd->index = index; if (buf) @@ -659,15 +674,15 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr) /* llc layer */ memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header)); - tmpl.llc_type = htons(ETH_P_ARP); + tmpl.llc_type = cpu_to_be16(ETH_P_ARP); /* arp header */ arp_hdr = &tmpl.arp_hdr; - arp_hdr->ar_hrd = htons(ARPHRD_ETHER); - arp_hdr->ar_pro = htons(ETH_P_IP); + arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER); + arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP); arp_hdr->ar_hln = ETH_ALEN; arp_hdr->ar_pln = 4; - arp_hdr->ar_op = htons(ARPOP_REPLY); + arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY); /* arp payload */ memcpy(tmpl.sender_hw, wl->vif->addr, ETH_ALEN); @@ -702,9 +717,9 @@ int wl1271_build_qos_null_data(struct wl1271 *wl) wl->basic_rate); } -int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) +int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id) { - struct wl1271_cmd_set_keys *cmd; + struct wl1271_cmd_set_sta_keys *cmd; int ret = 0; wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id); @@ -731,11 +746,42 @@ out: return ret; } -int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, +int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id) +{ + struct wl1271_cmd_set_ap_keys *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd set_ap_default_wep_key %d", id); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->hlid = WL1271_AP_BROADCAST_HLID; + cmd->key_id = id; + cmd->lid_key_type = WEP_DEFAULT_LID_TYPE; + cmd->key_action = cpu_to_le16(KEY_SET_ID); + cmd->key_type = KEY_WEP; + + ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_warning("cmd set_ap_default_wep_key failed: %d", ret); + goto out; + } + +out: + kfree(cmd); + + return ret; +} + +int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, const u8 *addr, u32 tx_seq_32, u16 tx_seq_16) { - struct wl1271_cmd_set_keys *cmd; + struct wl1271_cmd_set_sta_keys *cmd; int ret = 0; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -788,6 +834,67 @@ out: return ret; } +int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, + u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, + u16 tx_seq_16) +{ + struct wl1271_cmd_set_ap_keys *cmd; + int ret = 0; + u8 lid_type; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + if (hlid == WL1271_AP_BROADCAST_HLID) { + if (key_type == KEY_WEP) + lid_type = WEP_DEFAULT_LID_TYPE; + else + lid_type = BROADCAST_LID_TYPE; + } else { + lid_type = UNICAST_LID_TYPE; + } + + wl1271_debug(DEBUG_CRYPT, "ap key action: %d id: %d lid: %d type: %d" + " hlid: %d", (int)action, (int)id, (int)lid_type, + (int)key_type, (int)hlid); + + cmd->lid_key_type = lid_type; + cmd->hlid = hlid; + cmd->key_action = cpu_to_le16(action); + cmd->key_size = key_size; + cmd->key_type = key_type; + cmd->key_id = id; + cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16); + cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32); + + if (key_type == KEY_TKIP) { + /* + * We get the key in the following form: + * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) + * but the target is expecting: + * TKIP - RX MIC - TX MIC + */ + memcpy(cmd->key, key, 16); + memcpy(cmd->key + 16, key + 24, 8); + memcpy(cmd->key + 24, key + 16, 8); + } else { + memcpy(cmd->key, key, key_size); + } + + wl1271_dump(DEBUG_CRYPT, "TARGET AP KEY: ", cmd, sizeof(*cmd)); + + ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_warning("could not set ap keys"); + goto out; + } + +out: + kfree(cmd); + return ret; +} + int wl1271_cmd_disconnect(struct wl1271 *wl) { struct wl1271_cmd_disconnect *cmd; @@ -850,3 +957,180 @@ out_free: out: return ret; } + +int wl1271_cmd_start_bss(struct wl1271 *wl) +{ + struct wl1271_cmd_bss_start *cmd; + struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd start bss"); + + /* + * FIXME: We currently do not support hidden SSID. The real SSID + * should be fetched from mac80211 first. + */ + if (wl->ssid_len == 0) { + wl1271_warning("Hidden SSID currently not supported for AP"); + ret = -EINVAL; + goto out; + } + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN); + + cmd->aging_period = cpu_to_le16(WL1271_AP_DEF_INACTIV_SEC); + cmd->bss_index = WL1271_AP_BSS_INDEX; + cmd->global_hlid = WL1271_AP_GLOBAL_HLID; + cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID; + cmd->basic_rate_set = cpu_to_le32(wl->basic_rate_set); + cmd->beacon_interval = cpu_to_le16(wl->beacon_int); + cmd->dtim_interval = bss_conf->dtim_period; + cmd->beacon_expiry = WL1271_AP_DEF_BEACON_EXP; + cmd->channel = wl->channel; + cmd->ssid_len = wl->ssid_len; + cmd->ssid_type = SSID_TYPE_PUBLIC; + memcpy(cmd->ssid, wl->ssid, wl->ssid_len); + + switch (wl->band) { + case IEEE80211_BAND_2GHZ: + cmd->band = RADIO_BAND_2_4GHZ; + break; + case IEEE80211_BAND_5GHZ: + cmd->band = RADIO_BAND_5GHZ; + break; + default: + wl1271_warning("bss start - unknown band: %d", (int)wl->band); + cmd->band = RADIO_BAND_2_4GHZ; + break; + } + + ret = wl1271_cmd_send(wl, CMD_BSS_START, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd start bss"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl1271_cmd_stop_bss(struct wl1271 *wl) +{ + struct wl1271_cmd_bss_start *cmd; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd stop bss"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->bss_index = WL1271_AP_BSS_INDEX; + + ret = wl1271_cmd_send(wl, CMD_BSS_STOP, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd stop bss"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) +{ + struct wl1271_cmd_add_sta *cmd; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd add sta %d", (int)hlid); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + /* currently we don't support UAPSD */ + cmd->sp_len = 0; + + memcpy(cmd->addr, sta->addr, ETH_ALEN); + cmd->bss_index = WL1271_AP_BSS_INDEX; + cmd->aid = sta->aid; + cmd->hlid = hlid; + + /* + * FIXME: Does STA support QOS? We need to propagate this info from + * hostapd. Currently not that important since this is only used for + * sending the correct flavor of null-data packet in response to a + * trigger. + */ + cmd->wmm = 0; + + cmd->supported_rates = cpu_to_le32(wl1271_tx_enabled_rates_get(wl, + sta->supp_rates[wl->band])); + + wl1271_debug(DEBUG_CMD, "new sta rates: 0x%x", cmd->supported_rates); + + ret = wl1271_cmd_send(wl, CMD_ADD_STA, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd add sta"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid) +{ + struct wl1271_cmd_remove_sta *cmd; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd remove sta %d", (int)hlid); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->hlid = hlid; + /* We never send a deauth, mac80211 is in charge of this */ + cmd->reason_opcode = 0; + cmd->send_deauth_flag = 0; + + ret = wl1271_cmd_send(wl, CMD_REMOVE_STA, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd remove sta"); + goto out_free; + } + + /* + * We are ok with a timeout here. The event is sometimes not sent + * due to a firmware bug. + */ + wl1271_cmd_wait_for_event_or_timeout(wl, STA_REMOVE_COMPLETE_EVENT_ID); + +out_free: + kfree(cmd); + +out: + return ret; +} diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index 2a1d9db7ceb8..751281414006 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -54,12 +54,20 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr); int wl1271_build_qos_null_data(struct wl1271 *wl); int wl1271_cmd_build_klv_null_data(struct wl1271 *wl); -int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id); -int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, - u8 key_size, const u8 *key, const u8 *addr, - u32 tx_seq_32, u16 tx_seq_16); +int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id); +int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id); +int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, + u8 key_size, const u8 *key, const u8 *addr, + u32 tx_seq_32, u16 tx_seq_16); +int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, + u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, + u16 tx_seq_16); int wl1271_cmd_disconnect(struct wl1271 *wl); int wl1271_cmd_set_sta_state(struct wl1271 *wl); +int wl1271_cmd_start_bss(struct wl1271 *wl); +int wl1271_cmd_stop_bss(struct wl1271 *wl); +int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid); +int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid); enum wl1271_commands { CMD_INTERROGATE = 1, /*use this to read information elements*/ @@ -98,6 +106,12 @@ enum wl1271_commands { CMD_STOP_PERIODIC_SCAN = 51, CMD_SET_STA_STATE = 52, + /* AP mode commands */ + CMD_BSS_START = 60, + CMD_BSS_STOP = 61, + CMD_ADD_STA = 62, + CMD_REMOVE_STA = 63, + NUM_COMMANDS, MAX_COMMAND_ID = 0xFFFF, }; @@ -126,6 +140,13 @@ enum cmd_templ { * For CTS-to-self (FastCTS) mechanism * for BT/WLAN coexistence (SoftGemini). */ CMD_TEMPL_ARP_RSP, + + /* AP-mode specific */ + CMD_TEMPL_AP_BEACON = 13, + CMD_TEMPL_AP_PROBE_RESPONSE, + CMD_TEMPL_AP_ARP_RSP, + CMD_TEMPL_DEAUTH_AP, + CMD_TEMPL_MAX = 0xff }; @@ -270,7 +291,6 @@ struct wl1271_cmd_ps_params { /* HW encryption keys */ #define NUM_ACCESS_CATEGORIES_COPY 4 -#define MAX_KEY_SIZE 32 enum wl1271_cmd_key_action { KEY_ADD_OR_REPLACE = 1, @@ -289,7 +309,7 @@ enum wl1271_cmd_key_type { /* FIXME: Add description for key-types */ -struct wl1271_cmd_set_keys { +struct wl1271_cmd_set_sta_keys { struct wl1271_cmd_header header; /* Ignored for default WEP key */ @@ -318,6 +338,57 @@ struct wl1271_cmd_set_keys { __le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; } __packed; +enum wl1271_cmd_lid_key_type { + UNICAST_LID_TYPE = 0, + BROADCAST_LID_TYPE = 1, + WEP_DEFAULT_LID_TYPE = 2 +}; + +struct wl1271_cmd_set_ap_keys { + struct wl1271_cmd_header header; + + /* + * Indicates whether the HLID is a unicast key set + * or broadcast key set. A special value 0xFF is + * used to indicate that the HLID is on WEP-default + * (multi-hlids). of type wl1271_cmd_lid_key_type. + */ + u8 hlid; + + /* + * In WEP-default network (hlid == 0xFF) used to + * indicate which network STA/IBSS/AP role should be + * changed + */ + u8 lid_key_type; + + /* + * Key ID - For TKIP and AES key types, this field + * indicates the value that should be inserted into + * the KeyID field of frames transmitted using this + * key entry. For broadcast keys the index use as a + * marker for TX/RX key. + * For WEP default network (HLID=0xFF), this field + * indicates the ID of the key to add or remove. + */ + u8 key_id; + u8 reserved_1; + + /* key_action_e */ + __le16 key_action; + + /* key size in bytes */ + u8 key_size; + + /* key_type_e */ + u8 key_type; + + /* This field holds the security key data to add to the STA table */ + u8 key[MAX_KEY_SIZE]; + __le16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; + __le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; +} __packed; + struct wl1271_cmd_test_header { u8 id; u8 padding[3]; @@ -412,4 +483,68 @@ struct wl1271_cmd_set_sta_state { u8 padding[3]; } __packed; +enum wl1271_ssid_type { + SSID_TYPE_PUBLIC = 0, + SSID_TYPE_HIDDEN = 1 +}; + +struct wl1271_cmd_bss_start { + struct wl1271_cmd_header header; + + /* wl1271_ssid_type */ + u8 ssid_type; + u8 ssid_len; + u8 ssid[IW_ESSID_MAX_SIZE]; + u8 padding_1[2]; + + /* Basic rate set */ + __le32 basic_rate_set; + /* Aging period in seconds*/ + __le16 aging_period; + + /* + * This field specifies the time between target beacon + * transmission times (TBTTs), in time units (TUs). + * Valid values are 1 to 1024. + */ + __le16 beacon_interval; + u8 bssid[ETH_ALEN]; + u8 bss_index; + /* Radio band */ + u8 band; + u8 channel; + /* The host link id for the AP's global queue */ + u8 global_hlid; + /* The host link id for the AP's broadcast queue */ + u8 broadcast_hlid; + /* DTIM count */ + u8 dtim_interval; + /* Beacon expiry time in ms */ + u8 beacon_expiry; + u8 padding_2[3]; +} __packed; + +struct wl1271_cmd_add_sta { + struct wl1271_cmd_header header; + + u8 addr[ETH_ALEN]; + u8 hlid; + u8 aid; + u8 psd_type[NUM_ACCESS_CATEGORIES_COPY]; + __le32 supported_rates; + u8 bss_index; + u8 sp_len; + u8 wmm; + u8 padding1; +} __packed; + +struct wl1271_cmd_remove_sta { + struct wl1271_cmd_header header; + + u8 hlid; + u8 reason_opcode; + u8 send_deauth_flag; + u8 padding1; +} __packed; + #endif /* __WL1271_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index a16b3616e430..fd1dac9ab4db 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -496,6 +496,26 @@ struct conf_rx_settings { CONF_HW_BIT_RATE_2MBPS) #define CONF_TX_RATE_RETRY_LIMIT 10 +/* + * Rates supported for data packets when operating as AP. Note the absense + * of the 22Mbps rate. There is a FW limitation on 12 rates so we must drop + * one. The rate dropped is not mandatory under any operating mode. + */ +#define CONF_TX_AP_ENABLED_RATES (CONF_HW_BIT_RATE_1MBPS | \ + CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ + CONF_HW_BIT_RATE_6MBPS | CONF_HW_BIT_RATE_9MBPS | \ + CONF_HW_BIT_RATE_11MBPS | CONF_HW_BIT_RATE_12MBPS | \ + CONF_HW_BIT_RATE_18MBPS | CONF_HW_BIT_RATE_24MBPS | \ + CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \ + CONF_HW_BIT_RATE_54MBPS) + +/* + * Default rates for management traffic when operating in AP mode. This + * should be configured according to the basic rate set of the AP + */ +#define CONF_TX_AP_DEFAULT_MGMT_RATES (CONF_HW_BIT_RATE_1MBPS | \ + CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS) + struct conf_tx_rate_class { /* @@ -636,9 +656,9 @@ struct conf_tx_settings { /* * Configuration for rate classes for TX (currently only one - * rate class supported.) + * rate class supported). Used in non-AP mode. */ - struct conf_tx_rate_class rc_conf; + struct conf_tx_rate_class sta_rc_conf; /* * Configuration for access categories for TX rate control. @@ -647,6 +667,28 @@ struct conf_tx_settings { struct conf_tx_ac_category ac_conf[CONF_TX_MAX_AC_COUNT]; /* + * Configuration for rate classes in AP-mode. These rate classes + * are for the AC TX queues + */ + struct conf_tx_rate_class ap_rc_conf[CONF_TX_MAX_AC_COUNT]; + + /* + * Management TX rate class for AP-mode. + */ + struct conf_tx_rate_class ap_mgmt_conf; + + /* + * Broadcast TX rate class for AP-mode. + */ + struct conf_tx_rate_class ap_bcst_conf; + + /* + * AP-mode - allow this number of TX retries to a station before an + * event is triggered from FW. + */ + u16 ap_max_tx_retries; + + /* * Configuration for TID parameters. */ u8 tid_conf_count; @@ -687,6 +729,12 @@ struct conf_tx_settings { * Range: CONF_HW_BIT_RATE_* bit mask */ u32 basic_rate_5; + + /* + * TX retry limits for templates + */ + u8 tmpl_short_retry_limit; + u8 tmpl_long_retry_limit; }; enum { @@ -1036,30 +1084,30 @@ struct conf_scan_settings { /* * The minimum time to wait on each channel for active scans * - * Range: 0 - 65536 tu + * Range: u32 tu/1000 */ - u16 min_dwell_time_active; + u32 min_dwell_time_active; /* * The maximum time to wait on each channel for active scans * - * Range: 0 - 65536 tu + * Range: u32 tu/1000 */ - u16 max_dwell_time_active; + u32 max_dwell_time_active; /* - * The maximum time to wait on each channel for passive scans + * The minimum time to wait on each channel for passive scans * - * Range: 0 - 65536 tu + * Range: u32 tu/1000 */ - u16 min_dwell_time_passive; + u32 min_dwell_time_passive; /* * The maximum time to wait on each channel for passive scans * - * Range: 0 - 65536 tu + * Range: u32 tu/1000 */ - u16 max_dwell_time_passive; + u32 max_dwell_time_passive; /* * Number of probe requests to transmit on each active scan channel @@ -1090,6 +1138,11 @@ struct conf_rf_settings { u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5]; }; +struct conf_ht_setting { + u16 tx_ba_win_size; + u16 inactivity_timeout; +}; + struct conf_drv_settings { struct conf_sg_settings sg; struct conf_rx_settings rx; @@ -1100,6 +1153,7 @@ struct conf_drv_settings { struct conf_roam_trigger_settings roam_trigger; struct conf_scan_settings scan; struct conf_rf_settings rf; + struct conf_ht_setting ht; }; #endif diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index ec6077760157..bebfa28a171a 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -261,27 +261,25 @@ static ssize_t gpio_power_write(struct file *file, unsigned long value; int ret; - mutex_lock(&wl->mutex); - len = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, len)) { - ret = -EFAULT; - goto out; + return -EFAULT; } buf[len] = '\0'; ret = strict_strtoul(buf, 0, &value); if (ret < 0) { wl1271_warning("illegal value in gpio_power"); - goto out; + return -EINVAL; } + mutex_lock(&wl->mutex); + if (value) wl1271_power_on(wl); else wl1271_power_off(wl); -out: mutex_unlock(&wl->mutex); return count; } @@ -293,12 +291,13 @@ static const struct file_operations gpio_power_ops = { .llseek = default_llseek, }; -static int wl1271_debugfs_add_files(struct wl1271 *wl) +static int wl1271_debugfs_add_files(struct wl1271 *wl, + struct dentry *rootdir) { int ret = 0; struct dentry *entry, *stats; - stats = debugfs_create_dir("fw-statistics", wl->rootdir); + stats = debugfs_create_dir("fw-statistics", rootdir); if (!stats || IS_ERR(stats)) { entry = stats; goto err; @@ -395,16 +394,11 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl) DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); - DEBUGFS_ADD(tx_queue_len, wl->rootdir); - DEBUGFS_ADD(retry_count, wl->rootdir); - DEBUGFS_ADD(excessive_retries, wl->rootdir); - - DEBUGFS_ADD(gpio_power, wl->rootdir); + DEBUGFS_ADD(tx_queue_len, rootdir); + DEBUGFS_ADD(retry_count, rootdir); + DEBUGFS_ADD(excessive_retries, rootdir); - entry = debugfs_create_x32("debug_level", 0600, wl->rootdir, - &wl12xx_debug_level); - if (!entry || IS_ERR(entry)) - goto err; + DEBUGFS_ADD(gpio_power, rootdir); return 0; @@ -419,7 +413,7 @@ err: void wl1271_debugfs_reset(struct wl1271 *wl) { - if (!wl->rootdir) + if (!wl->stats.fw_stats) return; memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); @@ -430,13 +424,13 @@ void wl1271_debugfs_reset(struct wl1271 *wl) int wl1271_debugfs_init(struct wl1271 *wl) { int ret; + struct dentry *rootdir; - wl->rootdir = debugfs_create_dir(KBUILD_MODNAME, - wl->hw->wiphy->debugfsdir); + rootdir = debugfs_create_dir(KBUILD_MODNAME, + wl->hw->wiphy->debugfsdir); - if (IS_ERR(wl->rootdir)) { - ret = PTR_ERR(wl->rootdir); - wl->rootdir = NULL; + if (IS_ERR(rootdir)) { + ret = PTR_ERR(rootdir); goto err; } @@ -450,7 +444,7 @@ int wl1271_debugfs_init(struct wl1271 *wl) wl->stats.fw_stats_update = jiffies; - ret = wl1271_debugfs_add_files(wl); + ret = wl1271_debugfs_add_files(wl, rootdir); if (ret < 0) goto err_file; @@ -462,8 +456,7 @@ err_file: wl->stats.fw_stats = NULL; err_fw: - debugfs_remove_recursive(wl->rootdir); - wl->rootdir = NULL; + debugfs_remove_recursive(rootdir); err: return ret; @@ -473,8 +466,4 @@ void wl1271_debugfs_exit(struct wl1271 *wl) { kfree(wl->stats.fw_stats); wl->stats.fw_stats = NULL; - - debugfs_remove_recursive(wl->rootdir); - wl->rootdir = NULL; - } diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index f9146f5242fb..3376a5de09d7 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -186,6 +186,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) int ret; u32 vector; bool beacon_loss = false; + bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); wl1271_event_mbox_dump(mbox); @@ -218,21 +219,21 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) * BSS_LOSE_EVENT, beacon loss has to be reported to the stack. * */ - if (vector & BSS_LOSE_EVENT_ID) { + if ((vector & BSS_LOSE_EVENT_ID) && !is_ap) { wl1271_info("Beacon loss detected."); /* indicate to the stack, that beacons have been lost */ beacon_loss = true; } - if (vector & PS_REPORT_EVENT_ID) { + if ((vector & PS_REPORT_EVENT_ID) && !is_ap) { wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT"); ret = wl1271_event_ps_report(wl, mbox, &beacon_loss); if (ret < 0) return ret; } - if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) + if ((vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) && !is_ap) wl1271_event_pspoll_delivery_fail(wl); if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) { diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h index 6cce0143adb5..1d5ef670d480 100644 --- a/drivers/net/wireless/wl12xx/event.h +++ b/drivers/net/wireless/wl12xx/event.h @@ -59,6 +59,7 @@ enum { BSS_LOSE_EVENT_ID = BIT(18), REGAINED_BSS_EVENT_ID = BIT(19), ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20), + STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), /* AP */ SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), @@ -115,7 +116,12 @@ struct event_mailbox { u8 scheduled_scan_status; u8 ps_status; - u8 reserved_5[29]; + /* AP FW only */ + u8 hlid_removed; + __le16 sta_aging_status; + __le16 sta_tx_retry_exceeded; + + u8 reserved_5[24]; } __packed; int wl1271_event_unmask(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 785a5304bfc4..70b3dc88a219 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -30,27 +30,9 @@ #include "acx.h" #include "cmd.h" #include "reg.h" +#include "tx.h" -static int wl1271_init_hwenc_config(struct wl1271 *wl) -{ - int ret; - - ret = wl1271_acx_feature_cfg(wl); - if (ret < 0) { - wl1271_warning("couldn't set feature config"); - return ret; - } - - ret = wl1271_cmd_set_default_wep_key(wl, wl->default_key); - if (ret < 0) { - wl1271_warning("couldn't set default key"); - return ret; - } - - return 0; -} - -int wl1271_init_templates_config(struct wl1271 *wl) +int wl1271_sta_init_templates_config(struct wl1271 *wl) { int ret, i; @@ -118,6 +100,132 @@ int wl1271_init_templates_config(struct wl1271 *wl) return 0; } +static int wl1271_ap_init_deauth_template(struct wl1271 *wl) +{ + struct wl12xx_disconn_template *tmpl; + int ret; + + tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL); + if (!tmpl) { + ret = -ENOMEM; + goto out; + } + + tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_DEAUTH); + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, + tmpl, sizeof(*tmpl), 0, + wl1271_tx_min_rate_get(wl)); + +out: + kfree(tmpl); + return ret; +} + +static int wl1271_ap_init_null_template(struct wl1271 *wl) +{ + struct ieee80211_hdr_3addr *nullfunc; + int ret; + + nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL); + if (!nullfunc) { + ret = -ENOMEM; + goto out; + } + + nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_FROMDS); + + /* nullfunc->addr1 is filled by FW */ + + memcpy(nullfunc->addr2, wl->mac_addr, ETH_ALEN); + memcpy(nullfunc->addr3, wl->mac_addr, ETH_ALEN); + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc, + sizeof(*nullfunc), 0, + wl1271_tx_min_rate_get(wl)); + +out: + kfree(nullfunc); + return ret; +} + +static int wl1271_ap_init_qos_null_template(struct wl1271 *wl) +{ + struct ieee80211_qos_hdr *qosnull; + int ret; + + qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL); + if (!qosnull) { + ret = -ENOMEM; + goto out; + } + + qosnull->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_QOS_NULLFUNC | + IEEE80211_FCTL_FROMDS); + + /* qosnull->addr1 is filled by FW */ + + memcpy(qosnull->addr2, wl->mac_addr, ETH_ALEN); + memcpy(qosnull->addr3, wl->mac_addr, ETH_ALEN); + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull, + sizeof(*qosnull), 0, + wl1271_tx_min_rate_get(wl)); + +out: + kfree(qosnull); + return ret; +} + +static int wl1271_ap_init_templates_config(struct wl1271 *wl) +{ + int ret; + + /* + * Put very large empty placeholders for all templates. These + * reserve memory for later. + */ + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_PROBE_RESPONSE, NULL, + sizeof + (struct wl12xx_probe_resp_template), + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_BEACON, NULL, + sizeof + (struct wl12xx_beacon_template), + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, NULL, + sizeof + (struct wl12xx_disconn_template), + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL, + sizeof(struct wl12xx_null_data_template), + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL, + sizeof + (struct wl12xx_qos_null_data_template), + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + return 0; +} + static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter) { int ret; @@ -145,10 +253,6 @@ int wl1271_init_phy_config(struct wl1271 *wl) if (ret < 0) return ret; - ret = wl1271_acx_group_address_tbl(wl, true, NULL, 0); - if (ret < 0) - return ret; - ret = wl1271_acx_service_period_timeout(wl); if (ret < 0) return ret; @@ -213,11 +317,186 @@ static int wl1271_init_beacon_broadcast(struct wl1271 *wl) return 0; } +static int wl1271_sta_hw_init(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_cmd_ext_radio_parms(wl); + if (ret < 0) + return ret; + + ret = wl1271_sta_init_templates_config(wl); + if (ret < 0) + return ret; + + ret = wl1271_acx_group_address_tbl(wl, true, NULL, 0); + if (ret < 0) + return ret; + + /* Initialize connection monitoring thresholds */ + ret = wl1271_acx_conn_monit_params(wl, false); + if (ret < 0) + return ret; + + /* Beacon filtering */ + ret = wl1271_init_beacon_filter(wl); + if (ret < 0) + return ret; + + /* Bluetooth WLAN coexistence */ + ret = wl1271_init_pta(wl); + if (ret < 0) + return ret; + + /* Beacons and broadcast settings */ + ret = wl1271_init_beacon_broadcast(wl); + if (ret < 0) + return ret; + + /* Configure for ELP power saving */ + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); + if (ret < 0) + return ret; + + /* Configure rssi/snr averaging weights */ + ret = wl1271_acx_rssi_snr_avg_weights(wl); + if (ret < 0) + return ret; + + ret = wl1271_acx_sta_rate_policies(wl); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl) +{ + int ret, i; + + ret = wl1271_cmd_set_sta_default_wep_key(wl, wl->default_key); + if (ret < 0) { + wl1271_warning("couldn't set default key"); + return ret; + } + + /* disable all keep-alive templates */ + for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { + ret = wl1271_acx_keep_alive_config(wl, i, + ACX_KEEP_ALIVE_TPL_INVALID); + if (ret < 0) + return ret; + } + + /* disable the keep-alive feature */ + ret = wl1271_acx_keep_alive_mode(wl, false); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_ap_hw_init(struct wl1271 *wl) +{ + int ret, i; + + ret = wl1271_ap_init_templates_config(wl); + if (ret < 0) + return ret; + + /* Configure for power always on */ + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); + if (ret < 0) + return ret; + + /* Configure initial TX rate classes */ + for (i = 0; i < wl->conf.tx.ac_conf_count; i++) { + ret = wl1271_acx_ap_rate_policy(wl, + &wl->conf.tx.ap_rc_conf[i], i); + if (ret < 0) + return ret; + } + + ret = wl1271_acx_ap_rate_policy(wl, + &wl->conf.tx.ap_mgmt_conf, + ACX_TX_AP_MODE_MGMT_RATE); + if (ret < 0) + return ret; + + ret = wl1271_acx_ap_rate_policy(wl, + &wl->conf.tx.ap_bcst_conf, + ACX_TX_AP_MODE_BCST_RATE); + if (ret < 0) + return ret; + + ret = wl1271_acx_max_tx_retry(wl); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_ap_init_deauth_template(wl); + if (ret < 0) + return ret; + + ret = wl1271_ap_init_null_template(wl); + if (ret < 0) + return ret; + + ret = wl1271_ap_init_qos_null_template(wl); + if (ret < 0) + return ret; + + return 0; +} + +static void wl1271_check_ba_support(struct wl1271 *wl) +{ + /* validate FW cose ver x.x.x.50-60.x */ + if ((wl->chip.fw_ver[3] >= WL12XX_BA_SUPPORT_FW_COST_VER2_START) && + (wl->chip.fw_ver[3] < WL12XX_BA_SUPPORT_FW_COST_VER2_END)) { + wl->ba_support = true; + return; + } + + wl->ba_support = false; +} + +static int wl1271_set_ba_policies(struct wl1271 *wl) +{ + u8 tid_index; + u8 ret = 0; + + /* Reset the BA RX indicators */ + wl->ba_rx_bitmap = 0; + + /* validate that FW support BA */ + wl1271_check_ba_support(wl); + + if (wl->ba_support) + /* 802.11n initiator BA session setting */ + for (tid_index = 0; tid_index < CONF_TX_MAX_TID_COUNT; + ++tid_index) { + ret = wl1271_acx_set_ba_session(wl, WLAN_BACK_INITIATOR, + tid_index, true); + if (ret < 0) + break; + } + + return ret; +} + int wl1271_hw_init(struct wl1271 *wl) { struct conf_tx_ac_category *conf_ac; struct conf_tx_tid *conf_tid; int ret, i; + bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); ret = wl1271_cmd_general_parms(wl); if (ret < 0) @@ -227,12 +506,12 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) return ret; - ret = wl1271_cmd_ext_radio_parms(wl); - if (ret < 0) - return ret; + /* Mode specific init */ + if (is_ap) + ret = wl1271_ap_hw_init(wl); + else + ret = wl1271_sta_hw_init(wl); - /* Template settings */ - ret = wl1271_init_templates_config(wl); if (ret < 0) return ret; @@ -259,16 +538,6 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; - /* Initialize connection monitoring thresholds */ - ret = wl1271_acx_conn_monit_params(wl, false); - if (ret < 0) - goto out_free_memmap; - - /* Beacon filtering */ - ret = wl1271_init_beacon_filter(wl); - if (ret < 0) - goto out_free_memmap; - /* Configure TX patch complete interrupt behavior */ ret = wl1271_acx_tx_config_options(wl); if (ret < 0) @@ -279,21 +548,11 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; - /* Bluetooth WLAN coexistence */ - ret = wl1271_init_pta(wl); - if (ret < 0) - goto out_free_memmap; - /* Energy detection */ ret = wl1271_init_energy_detection(wl); if (ret < 0) goto out_free_memmap; - /* Beacons and boradcast settings */ - ret = wl1271_init_beacon_broadcast(wl); - if (ret < 0) - goto out_free_memmap; - /* Default fragmentation threshold */ ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold); if (ret < 0) @@ -321,23 +580,13 @@ int wl1271_hw_init(struct wl1271 *wl) goto out_free_memmap; } - /* Configure TX rate classes */ - ret = wl1271_acx_rate_policies(wl); - if (ret < 0) - goto out_free_memmap; - /* Enable data path */ ret = wl1271_cmd_data_path(wl, 1); if (ret < 0) goto out_free_memmap; - /* Configure for ELP power saving */ - ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); - if (ret < 0) - goto out_free_memmap; - /* Configure HW encryption */ - ret = wl1271_init_hwenc_config(wl); + ret = wl1271_acx_feature_cfg(wl); if (ret < 0) goto out_free_memmap; @@ -346,21 +595,17 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; - /* disable all keep-alive templates */ - for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { - ret = wl1271_acx_keep_alive_config(wl, i, - ACX_KEEP_ALIVE_TPL_INVALID); - if (ret < 0) - goto out_free_memmap; - } + /* Mode specific init - post mem init */ + if (is_ap) + ret = wl1271_ap_hw_init_post_mem(wl); + else + ret = wl1271_sta_hw_init_post_mem(wl); - /* disable the keep-alive feature */ - ret = wl1271_acx_keep_alive_mode(wl, false); if (ret < 0) goto out_free_memmap; - /* Configure rssi/snr averaging weights */ - ret = wl1271_acx_rssi_snr_avg_weights(wl); + /* Configure initiator BA sessions policies */ + ret = wl1271_set_ba_policies(wl); if (ret < 0) goto out_free_memmap; diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/init.h index 7762421f8602..3a8bd3f426d2 100644 --- a/drivers/net/wireless/wl12xx/init.h +++ b/drivers/net/wireless/wl12xx/init.h @@ -27,7 +27,7 @@ #include "wl12xx.h" int wl1271_hw_init_power_auth(struct wl1271 *wl); -int wl1271_init_templates_config(struct wl1271 *wl); +int wl1271_sta_init_templates_config(struct wl1271 *wl); int wl1271_init_phy_config(struct wl1271 *wl); int wl1271_init_pta(struct wl1271 *wl); int wl1271_init_energy_detection(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 062247ef3ad2..254b7daccee1 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -116,11 +116,11 @@ static struct conf_drv_settings default_conf = { }, .tx = { .tx_energy_detection = 0, - .rc_conf = { + .sta_rc_conf = { .enabled_rates = 0, .short_retry_limit = 10, .long_retry_limit = 10, - .aflags = 0 + .aflags = 0, }, .ac_conf_count = 4, .ac_conf = { @@ -153,6 +153,45 @@ static struct conf_drv_settings default_conf = { .tx_op_limit = 1504, }, }, + .ap_rc_conf = { + [0] = { + .enabled_rates = CONF_TX_AP_ENABLED_RATES, + .short_retry_limit = 10, + .long_retry_limit = 10, + .aflags = 0, + }, + [1] = { + .enabled_rates = CONF_TX_AP_ENABLED_RATES, + .short_retry_limit = 10, + .long_retry_limit = 10, + .aflags = 0, + }, + [2] = { + .enabled_rates = CONF_TX_AP_ENABLED_RATES, + .short_retry_limit = 10, + .long_retry_limit = 10, + .aflags = 0, + }, + [3] = { + .enabled_rates = CONF_TX_AP_ENABLED_RATES, + .short_retry_limit = 10, + .long_retry_limit = 10, + .aflags = 0, + }, + }, + .ap_mgmt_conf = { + .enabled_rates = CONF_TX_AP_DEFAULT_MGMT_RATES, + .short_retry_limit = 10, + .long_retry_limit = 10, + .aflags = 0, + }, + .ap_bcst_conf = { + .enabled_rates = CONF_HW_BIT_RATE_1MBPS, + .short_retry_limit = 10, + .long_retry_limit = 10, + .aflags = 0, + }, + .ap_max_tx_retries = 100, .tid_conf_count = 4, .tid_conf = { [CONF_TX_AC_BE] = { @@ -193,6 +232,8 @@ static struct conf_drv_settings default_conf = { .tx_compl_threshold = 4, .basic_rate = CONF_HW_BIT_RATE_1MBPS, .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS, + .tmpl_short_retry_limit = 10, + .tmpl_long_retry_limit = 10, }, .conn = { .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, @@ -233,13 +274,13 @@ static struct conf_drv_settings default_conf = { .avg_weight_rssi_beacon = 20, .avg_weight_rssi_data = 10, .avg_weight_snr_beacon = 20, - .avg_weight_snr_data = 10 + .avg_weight_snr_data = 10, }, .scan = { .min_dwell_time_active = 7500, .max_dwell_time_active = 30000, - .min_dwell_time_passive = 30000, - .max_dwell_time_passive = 60000, + .min_dwell_time_passive = 100000, + .max_dwell_time_passive = 100000, .num_probe_reqs = 2, }, .rf = { @@ -252,9 +293,14 @@ static struct conf_drv_settings default_conf = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, }, + .ht = { + .tx_ba_win_size = 64, + .inactivity_timeout = 10000, + }, }; static void __wl1271_op_remove_interface(struct wl1271 *wl); +static void wl1271_free_ap_keys(struct wl1271 *wl); static void wl1271_device_release(struct device *dev) @@ -393,7 +439,7 @@ static int wl1271_plt_init(struct wl1271 *wl) if (ret < 0) return ret; - ret = wl1271_init_templates_config(wl); + ret = wl1271_sta_init_templates_config(wl); if (ret < 0) return ret; @@ -616,9 +662,26 @@ out: static int wl1271_fetch_firmware(struct wl1271 *wl) { const struct firmware *fw; + const char *fw_name; int ret; - ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl)); + switch (wl->bss_type) { + case BSS_TYPE_AP_BSS: + fw_name = WL1271_AP_FW_NAME; + break; + case BSS_TYPE_IBSS: + case BSS_TYPE_STA_BSS: + fw_name = WL1271_FW_NAME; + break; + default: + wl1271_error("no compatible firmware for bss_type %d", + wl->bss_type); + return -EINVAL; + } + + wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name); + + ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl)); if (ret < 0) { wl1271_error("could not get firmware: %d", ret); @@ -632,6 +695,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) goto out; } + vfree(wl->fw); wl->fw_len = fw->size; wl->fw = vmalloc(wl->fw_len); @@ -642,7 +706,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) } memcpy(wl->fw, fw->data, wl->fw_len); - + wl->fw_bss_type = wl->bss_type; ret = 0; out: @@ -778,7 +842,8 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) goto out; } - if (wl->fw == NULL) { + /* Make sure the firmware type matches the BSS type */ + if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) { ret = wl1271_fetch_firmware(wl); if (ret < 0) goto out; @@ -811,6 +876,8 @@ int wl1271_plt_start(struct wl1271 *wl) goto out; } + wl->bss_type = BSS_TYPE_STA_BSS; + while (retries) { retries--; ret = wl1271_chip_wakeup(wl); @@ -827,7 +894,7 @@ int wl1271_plt_start(struct wl1271 *wl) wl->state = WL1271_STATE_PLT; wl1271_notice("firmware booted in PLT mode (%s)", - wl->chip.fw_ver); + wl->chip.fw_ver_str); goto out; irq_disable: @@ -854,12 +921,10 @@ out: return ret; } -int wl1271_plt_stop(struct wl1271 *wl) +int __wl1271_plt_stop(struct wl1271 *wl) { int ret = 0; - mutex_lock(&wl->mutex); - wl1271_notice("power down"); if (wl->state != WL1271_STATE_PLT) { @@ -875,12 +940,21 @@ int wl1271_plt_stop(struct wl1271 *wl) wl->state = WL1271_STATE_OFF; wl->rx_counter = 0; -out: mutex_unlock(&wl->mutex); - cancel_work_sync(&wl->irq_work); cancel_work_sync(&wl->recovery_work); + mutex_lock(&wl->mutex); +out: + return ret; +} + +int wl1271_plt_stop(struct wl1271 *wl) +{ + int ret; + mutex_lock(&wl->mutex); + ret = __wl1271_plt_stop(wl); + mutex_unlock(&wl->mutex); return ret; } @@ -902,7 +976,8 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) spin_lock_irqsave(&wl->wl_lock, flags); if (sta && (sta->supp_rates[conf->channel->band] != - (wl->sta_rate_set & HW_BG_RATES_MASK))) { + (wl->sta_rate_set & HW_BG_RATES_MASK)) && + wl->bss_type != BSS_TYPE_AP_BSS) { wl->sta_rate_set = sta->supp_rates[conf->channel->band]; set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags); } @@ -967,6 +1042,9 @@ static int wl1271_op_start(struct ieee80211_hw *hw) * * The MAC address is first known when the corresponding interface * is added. That is where we will initialize the hardware. + * + * In addition, we currently have different firmwares for AP and managed + * operation. We will know which to boot according to interface type. */ return 0; @@ -1006,6 +1084,9 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, wl->bss_type = BSS_TYPE_IBSS; wl->set_bss_type = BSS_TYPE_STA_BSS; break; + case NL80211_IFTYPE_AP: + wl->bss_type = BSS_TYPE_AP_BSS; + break; default: ret = -EOPNOTSUPP; goto out; @@ -1061,11 +1142,11 @@ power_off: wl->vif = vif; wl->state = WL1271_STATE_ON; - wl1271_info("firmware booted (%s)", wl->chip.fw_ver); + wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str); /* update hw/fw version info in wiphy struct */ wiphy->hw_version = wl->chip.id; - strncpy(wiphy->fw_version, wl->chip.fw_ver, + strncpy(wiphy->fw_version, wl->chip.fw_ver_str, sizeof(wiphy->fw_version)); /* @@ -1151,6 +1232,8 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) wl->flags = 0; wl->vif = NULL; wl->filters = 0; + wl1271_free_ap_keys(wl); + memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map)); for (i = 0; i < NUM_TX_QUEUES; i++) wl->tx_blocks_freed[i] = 0; @@ -1186,8 +1269,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) { - wl->rx_config = WL1271_DEFAULT_RX_CONFIG; - wl->rx_filter = WL1271_DEFAULT_RX_FILTER; + wl1271_set_default_filters(wl); /* combine requested filters with current filter config */ filters = wl->filters | filters; @@ -1322,25 +1404,7 @@ static void wl1271_set_band_rate(struct wl1271 *wl) wl->basic_rate_set = wl->conf.tx.basic_rate_5; } -static u32 wl1271_min_rate_get(struct wl1271 *wl) -{ - int i; - u32 rate = 0; - - if (!wl->basic_rate_set) { - WARN_ON(1); - wl->basic_rate_set = wl->conf.tx.basic_rate; - } - - for (i = 0; !rate; i++) { - if ((wl->basic_rate_set >> i) & 0x1) - rate = 1 << i; - } - - return rate; -} - -static int wl1271_handle_idle(struct wl1271 *wl, bool idle) +static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle) { int ret; @@ -1350,9 +1414,9 @@ static int wl1271_handle_idle(struct wl1271 *wl, bool idle) if (ret < 0) goto out; } - wl->rate_set = wl1271_min_rate_get(wl); + wl->rate_set = wl1271_tx_min_rate_get(wl); wl->sta_rate_set = 0; - ret = wl1271_acx_rate_policies(wl); + ret = wl1271_acx_sta_rate_policies(wl); if (ret < 0) goto out; ret = wl1271_acx_keep_alive_config( @@ -1381,14 +1445,17 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) struct wl1271 *wl = hw->priv; struct ieee80211_conf *conf = &hw->conf; int channel, ret = 0; + bool is_ap; channel = ieee80211_frequency_to_channel(conf->channel->center_freq); - wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s", + wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s" + " changed 0x%x", channel, conf->flags & IEEE80211_CONF_PS ? "on" : "off", conf->power_level, - conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use"); + conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use", + changed); /* * mac80211 will go to idle nearly immediately after transmitting some @@ -1406,6 +1473,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) goto out; } + is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); + ret = wl1271_ps_elp_wakeup(wl, false); if (ret < 0) goto out; @@ -1417,31 +1486,34 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) wl->band = conf->channel->band; wl->channel = channel; - /* - * FIXME: the mac80211 should really provide a fixed rate - * to use here. for now, just use the smallest possible rate - * for the band as a fixed rate for association frames and - * other control messages. - */ - if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) - wl1271_set_band_rate(wl); - - wl->basic_rate = wl1271_min_rate_get(wl); - ret = wl1271_acx_rate_policies(wl); - if (ret < 0) - wl1271_warning("rate policy for update channel " - "failed %d", ret); + if (!is_ap) { + /* + * FIXME: the mac80211 should really provide a fixed + * rate to use here. for now, just use the smallest + * possible rate for the band as a fixed rate for + * association frames and other control messages. + */ + if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) + wl1271_set_band_rate(wl); - if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) { - ret = wl1271_join(wl, false); + wl->basic_rate = wl1271_tx_min_rate_get(wl); + ret = wl1271_acx_sta_rate_policies(wl); if (ret < 0) - wl1271_warning("cmd join to update channel " + wl1271_warning("rate policy for channel " "failed %d", ret); + + if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) { + ret = wl1271_join(wl, false); + if (ret < 0) + wl1271_warning("cmd join on channel " + "failed %d", ret); + } } } - if (changed & IEEE80211_CONF_CHANGE_IDLE) { - ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE); + if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) { + ret = wl1271_sta_handle_idle(wl, + conf->flags & IEEE80211_CONF_IDLE); if (ret < 0) wl1271_warning("idle mode change failed %d", ret); } @@ -1548,7 +1620,8 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw, struct wl1271 *wl = hw->priv; int ret; - wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter"); + wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x" + " total %x", changed, *total); mutex_lock(&wl->mutex); @@ -1562,15 +1635,16 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw, if (ret < 0) goto out; - - if (*total & FIF_ALLMULTI) - ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0); - else if (fp) - ret = wl1271_acx_group_address_tbl(wl, fp->enabled, - fp->mc_list, - fp->mc_list_length); - if (ret < 0) - goto out_sleep; + if (wl->bss_type != BSS_TYPE_AP_BSS) { + if (*total & FIF_ALLMULTI) + ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0); + else if (fp) + ret = wl1271_acx_group_address_tbl(wl, fp->enabled, + fp->mc_list, + fp->mc_list_length); + if (ret < 0) + goto out_sleep; + } /* determine, whether supported filter values have changed */ if (changed == 0) @@ -1593,38 +1667,192 @@ out: kfree(fp); } +static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type, + u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, + u16 tx_seq_16) +{ + struct wl1271_ap_key *ap_key; + int i; + + wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id); + + if (key_size > MAX_KEY_SIZE) + return -EINVAL; + + /* + * Find next free entry in ap_keys. Also check we are not replacing + * an existing key. + */ + for (i = 0; i < MAX_NUM_KEYS; i++) { + if (wl->recorded_ap_keys[i] == NULL) + break; + + if (wl->recorded_ap_keys[i]->id == id) { + wl1271_warning("trying to record key replacement"); + return -EINVAL; + } + } + + if (i == MAX_NUM_KEYS) + return -EBUSY; + + ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL); + if (!ap_key) + return -ENOMEM; + + ap_key->id = id; + ap_key->key_type = key_type; + ap_key->key_size = key_size; + memcpy(ap_key->key, key, key_size); + ap_key->hlid = hlid; + ap_key->tx_seq_32 = tx_seq_32; + ap_key->tx_seq_16 = tx_seq_16; + + wl->recorded_ap_keys[i] = ap_key; + return 0; +} + +static void wl1271_free_ap_keys(struct wl1271 *wl) +{ + int i; + + for (i = 0; i < MAX_NUM_KEYS; i++) { + kfree(wl->recorded_ap_keys[i]); + wl->recorded_ap_keys[i] = NULL; + } +} + +static int wl1271_ap_init_hwenc(struct wl1271 *wl) +{ + int i, ret = 0; + struct wl1271_ap_key *key; + bool wep_key_added = false; + + for (i = 0; i < MAX_NUM_KEYS; i++) { + if (wl->recorded_ap_keys[i] == NULL) + break; + + key = wl->recorded_ap_keys[i]; + ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE, + key->id, key->key_type, + key->key_size, key->key, + key->hlid, key->tx_seq_32, + key->tx_seq_16); + if (ret < 0) + goto out; + + if (key->key_type == KEY_WEP) + wep_key_added = true; + } + + if (wep_key_added) { + ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key); + if (ret < 0) + goto out; + } + +out: + wl1271_free_ap_keys(wl); + return ret; +} + +static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, + u8 key_size, const u8 *key, u32 tx_seq_32, + u16 tx_seq_16, struct ieee80211_sta *sta) +{ + int ret; + bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); + + if (is_ap) { + struct wl1271_station *wl_sta; + u8 hlid; + + if (sta) { + wl_sta = (struct wl1271_station *)sta->drv_priv; + hlid = wl_sta->hlid; + } else { + hlid = WL1271_AP_BROADCAST_HLID; + } + + if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) { + /* + * We do not support removing keys after AP shutdown. + * Pretend we do to make mac80211 happy. + */ + if (action != KEY_ADD_OR_REPLACE) + return 0; + + ret = wl1271_record_ap_key(wl, id, + key_type, key_size, + key, hlid, tx_seq_32, + tx_seq_16); + } else { + ret = wl1271_cmd_set_ap_key(wl, action, + id, key_type, key_size, + key, hlid, tx_seq_32, + tx_seq_16); + } + + if (ret < 0) + return ret; + } else { + const u8 *addr; + static const u8 bcast_addr[ETH_ALEN] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + addr = sta ? sta->addr : bcast_addr; + + if (is_zero_ether_addr(addr)) { + /* We dont support TX only encryption */ + return -EOPNOTSUPP; + } + + /* The wl1271 does not allow to remove unicast keys - they + will be cleared automatically on next CMD_JOIN. Ignore the + request silently, as we dont want the mac80211 to emit + an error message. */ + if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr)) + return 0; + + ret = wl1271_cmd_set_sta_key(wl, action, + id, key_type, key_size, + key, addr, tx_seq_32, + tx_seq_16); + if (ret < 0) + return ret; + + /* the default WEP key needs to be configured at least once */ + if (key_type == KEY_WEP) { + ret = wl1271_cmd_set_sta_default_wep_key(wl, + wl->default_key); + if (ret < 0) + return ret; + } + } + + return 0; +} + static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key_conf) { struct wl1271 *wl = hw->priv; - const u8 *addr; int ret; u32 tx_seq_32 = 0; u16 tx_seq_16 = 0; u8 key_type; - static const u8 bcast_addr[ETH_ALEN] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - wl1271_debug(DEBUG_MAC80211, "mac80211 set key"); - addr = sta ? sta->addr : bcast_addr; - - wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); - wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); + wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta); wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", key_conf->cipher, key_conf->keyidx, key_conf->keylen, key_conf->flags); wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen); - if (is_zero_ether_addr(addr)) { - /* We dont support TX only encryption */ - ret = -EOPNOTSUPP; - goto out; - } - mutex_lock(&wl->mutex); if (unlikely(wl->state == WL1271_STATE_OFF)) { @@ -1671,36 +1899,21 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, switch (cmd) { case SET_KEY: - ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE, - key_conf->keyidx, key_type, - key_conf->keylen, key_conf->key, - addr, tx_seq_32, tx_seq_16); + ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE, + key_conf->keyidx, key_type, + key_conf->keylen, key_conf->key, + tx_seq_32, tx_seq_16, sta); if (ret < 0) { wl1271_error("Could not add or replace key"); goto out_sleep; } - - /* the default WEP key needs to be configured at least once */ - if (key_type == KEY_WEP) { - ret = wl1271_cmd_set_default_wep_key(wl, - wl->default_key); - if (ret < 0) - goto out_sleep; - } break; case DISABLE_KEY: - /* The wl1271 does not allow to remove unicast keys - they - will be cleared automatically on next CMD_JOIN. Ignore the - request silently, as we dont want the mac80211 to emit - an error message. */ - if (!is_broadcast_ether_addr(addr)) - break; - - ret = wl1271_cmd_set_key(wl, KEY_REMOVE, - key_conf->keyidx, key_type, - key_conf->keylen, key_conf->key, - addr, 0, 0); + ret = wl1271_set_key(wl, KEY_REMOVE, + key_conf->keyidx, key_type, + key_conf->keylen, key_conf->key, + 0, 0, sta); if (ret < 0) { wl1271_error("Could not remove key"); goto out_sleep; @@ -1719,7 +1932,6 @@ out_sleep: out_unlock: mutex_unlock(&wl->mutex); -out: return ret; } @@ -1821,7 +2033,7 @@ out: return ret; } -static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb, +static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb, int offset) { u8 *ptr = skb->data + offset; @@ -1831,89 +2043,210 @@ static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb, if (ptr[0] == WLAN_EID_SSID) { wl->ssid_len = ptr[1]; memcpy(wl->ssid, ptr+2, wl->ssid_len); - return; + return 0; } ptr += (ptr[1] + 2); } + wl1271_error("No SSID in IEs!\n"); + return -ENOENT; } -static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, +static int wl1271_bss_erp_info_changed(struct wl1271 *wl, struct ieee80211_bss_conf *bss_conf, u32 changed) { - enum wl1271_cmd_ps_mode mode; - struct wl1271 *wl = hw->priv; - struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid); - bool do_join = false; - bool set_assoc = false; - int ret; + int ret = 0; - wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed"); + if (changed & BSS_CHANGED_ERP_SLOT) { + if (bss_conf->use_short_slot) + ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT); + else + ret = wl1271_acx_slot(wl, SLOT_TIME_LONG); + if (ret < 0) { + wl1271_warning("Set slot time failed %d", ret); + goto out; + } + } - mutex_lock(&wl->mutex); + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + if (bss_conf->use_short_preamble) + wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); + else + wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG); + } - if (unlikely(wl->state == WL1271_STATE_OFF)) - goto out; + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + if (bss_conf->use_cts_prot) + ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE); + else + ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE); + if (ret < 0) { + wl1271_warning("Set ctsprotect failed %d", ret); + goto out; + } + } - ret = wl1271_ps_elp_wakeup(wl, false); - if (ret < 0) - goto out; +out: + return ret; +} - if ((changed & BSS_CHANGED_BEACON_INT) && - (wl->bss_type == BSS_TYPE_IBSS)) { - wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d", +static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); + int ret = 0; + + if ((changed & BSS_CHANGED_BEACON_INT)) { + wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d", bss_conf->beacon_int); wl->beacon_int = bss_conf->beacon_int; - do_join = true; } - if ((changed & BSS_CHANGED_BEACON) && - (wl->bss_type == BSS_TYPE_IBSS)) { - struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); + if ((changed & BSS_CHANGED_BEACON)) { + struct ieee80211_hdr *hdr; + int ieoffset = offsetof(struct ieee80211_mgmt, + u.beacon.variable); + struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif); + u16 tmpl_id; - wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated"); + if (!beacon) + goto out; - if (beacon) { - struct ieee80211_hdr *hdr; - int ieoffset = offsetof(struct ieee80211_mgmt, - u.beacon.variable); + wl1271_debug(DEBUG_MASTER, "beacon updated"); - wl1271_ssid_set(wl, beacon, ieoffset); + ret = wl1271_ssid_set(wl, beacon, ieoffset); + if (ret < 0) { + dev_kfree_skb(beacon); + goto out; + } + tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON : + CMD_TEMPL_BEACON; + ret = wl1271_cmd_template_set(wl, tmpl_id, + beacon->data, + beacon->len, 0, + wl1271_tx_min_rate_get(wl)); + if (ret < 0) { + dev_kfree_skb(beacon); + goto out; + } - ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, - beacon->data, - beacon->len, 0, - wl1271_min_rate_get(wl)); + hdr = (struct ieee80211_hdr *) beacon->data; + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_PROBE_RESP); + + tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE : + CMD_TEMPL_PROBE_RESPONSE; + ret = wl1271_cmd_template_set(wl, + tmpl_id, + beacon->data, + beacon->len, 0, + wl1271_tx_min_rate_get(wl)); + dev_kfree_skb(beacon); + if (ret < 0) + goto out; + } - if (ret < 0) { - dev_kfree_skb(beacon); - goto out_sleep; - } +out: + return ret; +} - hdr = (struct ieee80211_hdr *) beacon->data; - hdr->frame_control = cpu_to_le16( - IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_PROBE_RESP); +/* AP mode changes */ +static void wl1271_bss_info_changed_ap(struct wl1271 *wl, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + int ret = 0; - ret = wl1271_cmd_template_set(wl, - CMD_TEMPL_PROBE_RESPONSE, - beacon->data, - beacon->len, 0, - wl1271_min_rate_get(wl)); - dev_kfree_skb(beacon); - if (ret < 0) - goto out_sleep; + if ((changed & BSS_CHANGED_BASIC_RATES)) { + u32 rates = bss_conf->basic_rates; + struct conf_tx_rate_class mgmt_rc; + + wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates); + wl->basic_rate = wl1271_tx_min_rate_get(wl); + wl1271_debug(DEBUG_AP, "basic rates: 0x%x", + wl->basic_rate_set); + + /* update the AP management rate policy with the new rates */ + mgmt_rc.enabled_rates = wl->basic_rate_set; + mgmt_rc.long_retry_limit = 10; + mgmt_rc.short_retry_limit = 10; + mgmt_rc.aflags = 0; + ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc, + ACX_TX_AP_MODE_MGMT_RATE); + if (ret < 0) { + wl1271_error("AP mgmt policy change failed %d", ret); + goto out; + } + } - /* Need to update the SSID (for filtering etc) */ - do_join = true; + ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed); + if (ret < 0) + goto out; + + if ((changed & BSS_CHANGED_BEACON_ENABLED)) { + if (bss_conf->enable_beacon) { + if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) { + ret = wl1271_cmd_start_bss(wl); + if (ret < 0) + goto out; + + set_bit(WL1271_FLAG_AP_STARTED, &wl->flags); + wl1271_debug(DEBUG_AP, "started AP"); + + ret = wl1271_ap_init_hwenc(wl); + if (ret < 0) + goto out; + } + } else { + if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) { + ret = wl1271_cmd_stop_bss(wl); + if (ret < 0) + goto out; + + clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags); + wl1271_debug(DEBUG_AP, "stopped AP"); + } } } - if ((changed & BSS_CHANGED_BEACON_ENABLED) && - (wl->bss_type == BSS_TYPE_IBSS)) { + ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed); + if (ret < 0) + goto out; +out: + return; +} + +/* STA/IBSS mode changes */ +static void wl1271_bss_info_changed_sta(struct wl1271 *wl, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + bool do_join = false, set_assoc = false; + bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS); + int ret; + struct ieee80211_sta *sta; + + if (is_ibss) { + ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, + changed); + if (ret < 0) + goto out; + } + + if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss) + do_join = true; + + /* Need to update the SSID (for filtering etc) */ + if ((changed & BSS_CHANGED_BEACON) && is_ibss) + do_join = true; + + if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) { wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s", bss_conf->enable_beacon ? "enabled" : "disabled"); @@ -1924,7 +2257,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, do_join = true; } - if (changed & BSS_CHANGED_CQM) { + if ((changed & BSS_CHANGED_CQM)) { bool enable = false; if (bss_conf->cqm_rssi_thold) enable = true; @@ -1942,24 +2275,26 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, * and enable the BSSID filter */ memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) { - memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); + memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); + if (!is_zero_ether_addr(wl->bssid)) { ret = wl1271_cmd_build_null_data(wl); if (ret < 0) - goto out_sleep; + goto out; ret = wl1271_build_qos_null_data(wl); if (ret < 0) - goto out_sleep; + goto out; /* filter out all packets not from this BSSID */ wl1271_configure_filters(wl, 0); /* Need to update the BSSID (for filtering etc) */ do_join = true; + } } - if (changed & BSS_CHANGED_ASSOC) { + if ((changed & BSS_CHANGED_ASSOC)) { if (bss_conf->assoc) { u32 rates; int ieoffset; @@ -1975,10 +2310,10 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, rates = bss_conf->basic_rates; wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates); - wl->basic_rate = wl1271_min_rate_get(wl); - ret = wl1271_acx_rate_policies(wl); + wl->basic_rate = wl1271_tx_min_rate_get(wl); + ret = wl1271_acx_sta_rate_policies(wl); if (ret < 0) - goto out_sleep; + goto out; /* * with wl1271, we don't need to update the @@ -1988,7 +2323,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, */ ret = wl1271_cmd_build_ps_poll(wl, wl->aid); if (ret < 0) - goto out_sleep; + goto out; /* * Get a template for hardware connection maintenance @@ -2002,17 +2337,19 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, /* enable the connection monitoring feature */ ret = wl1271_acx_conn_monit_params(wl, true); if (ret < 0) - goto out_sleep; + goto out; /* If we want to go in PSM but we're not there yet */ if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) && !test_bit(WL1271_FLAG_PSM, &wl->flags)) { + enum wl1271_cmd_ps_mode mode; + mode = STATION_POWER_SAVE_MODE; ret = wl1271_ps_set_mode(wl, mode, wl->basic_rate, true); if (ret < 0) - goto out_sleep; + goto out; } } else { /* use defaults when not associated */ @@ -2029,10 +2366,10 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, /* revert back to minimum rates for the current band */ wl1271_set_band_rate(wl); - wl->basic_rate = wl1271_min_rate_get(wl); - ret = wl1271_acx_rate_policies(wl); + wl->basic_rate = wl1271_tx_min_rate_get(wl); + ret = wl1271_acx_sta_rate_policies(wl); if (ret < 0) - goto out_sleep; + goto out; /* disable connection monitor features */ ret = wl1271_acx_conn_monit_params(wl, false); @@ -2040,74 +2377,54 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, /* Disable the keep-alive feature */ ret = wl1271_acx_keep_alive_mode(wl, false); if (ret < 0) - goto out_sleep; + goto out; /* restore the bssid filter and go to dummy bssid */ wl1271_unjoin(wl); wl1271_dummy_join(wl); } - - } - - if (changed & BSS_CHANGED_ERP_SLOT) { - if (bss_conf->use_short_slot) - ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT); - else - ret = wl1271_acx_slot(wl, SLOT_TIME_LONG); - if (ret < 0) { - wl1271_warning("Set slot time failed %d", ret); - goto out_sleep; - } - } - - if (changed & BSS_CHANGED_ERP_PREAMBLE) { - if (bss_conf->use_short_preamble) - wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); - else - wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG); } - if (changed & BSS_CHANGED_ERP_CTS_PROT) { - if (bss_conf->use_cts_prot) - ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE); - else - ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE); - if (ret < 0) { - wl1271_warning("Set ctsprotect failed %d", ret); - goto out_sleep; - } - } + ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed); + if (ret < 0) + goto out; - /* - * Takes care of: New association with HT enable, - * HT information change in beacon. - */ - if (sta && - (changed & BSS_CHANGED_HT) && - (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { - ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true); - if (ret < 0) { - wl1271_warning("Set ht cap true failed %d", ret); - goto out_sleep; - } + rcu_read_lock(); + sta = ieee80211_find_sta(vif, bss_conf->bssid); + if (sta) { + /* handle new association with HT and HT information change */ + if ((changed & BSS_CHANGED_HT) && + (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { + ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, + true); + if (ret < 0) { + wl1271_warning("Set ht cap true failed %d", + ret); + rcu_read_unlock(); + goto out; + } ret = wl1271_acx_set_ht_information(wl, - bss_conf->ht_operation_mode); - if (ret < 0) { - wl1271_warning("Set ht information failed %d", ret); - goto out_sleep; + bss_conf->ht_operation_mode); + if (ret < 0) { + wl1271_warning("Set ht information failed %d", + ret); + rcu_read_unlock(); + goto out; + } } - } - /* - * Takes care of: New association without HT, - * Disassociation. - */ - else if (sta && (changed & BSS_CHANGED_ASSOC)) { - ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false); - if (ret < 0) { - wl1271_warning("Set ht cap false failed %d", ret); - goto out_sleep; + /* handle new association without HT and disassociation */ + else if (changed & BSS_CHANGED_ASSOC) { + ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, + false); + if (ret < 0) { + wl1271_warning("Set ht cap false failed %d", + ret); + rcu_read_unlock(); + goto out; + } } } + rcu_read_unlock(); if (changed & BSS_CHANGED_ARP_FILTER) { __be32 addr = bss_conf->arp_addr_list[0]; @@ -2124,76 +2441,128 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, ret = wl1271_cmd_build_arp_rsp(wl, addr); if (ret < 0) { wl1271_warning("build arp rsp failed: %d", ret); - goto out_sleep; + goto out; } ret = wl1271_acx_arp_ip_filter(wl, - (ACX_ARP_FILTER_ARP_FILTERING | - ACX_ARP_FILTER_AUTO_ARP), + ACX_ARP_FILTER_ARP_FILTERING, addr); } else ret = wl1271_acx_arp_ip_filter(wl, 0, addr); if (ret < 0) - goto out_sleep; + goto out; } if (do_join) { ret = wl1271_join(wl, set_assoc); if (ret < 0) { wl1271_warning("cmd join failed %d", ret); - goto out_sleep; + goto out; } } -out_sleep: - wl1271_ps_elp_sleep(wl); - out: - mutex_unlock(&wl->mutex); + return; } -static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *params) +static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) { struct wl1271 *wl = hw->priv; - u8 ps_scheme; + bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); int ret; - mutex_lock(&wl->mutex); + wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x", + (int)changed); - wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); + mutex_lock(&wl->mutex); - if (unlikely(wl->state == WL1271_STATE_OFF)) { - ret = -EAGAIN; + if (unlikely(wl->state == WL1271_STATE_OFF)) goto out; - } ret = wl1271_ps_elp_wakeup(wl, false); if (ret < 0) goto out; - /* the txop is confed in units of 32us by the mac80211, we need us */ - ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue), - params->cw_min, params->cw_max, - params->aifs, params->txop << 5); - if (ret < 0) - goto out_sleep; + if (is_ap) + wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed); + else + wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed); + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct wl1271 *wl = hw->priv; + u8 ps_scheme; + int ret = 0; + + mutex_lock(&wl->mutex); + + wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); if (params->uapsd) ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER; else ps_scheme = CONF_PS_SCHEME_LEGACY; - ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue), - CONF_CHANNEL_TYPE_EDCF, - wl1271_tx_get_queue(queue), - ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0); - if (ret < 0) - goto out_sleep; + if (wl->state == WL1271_STATE_OFF) { + /* + * If the state is off, the parameters will be recorded and + * configured on init. This happens in AP-mode. + */ + struct conf_tx_ac_category *conf_ac = + &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)]; + struct conf_tx_tid *conf_tid = + &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)]; + + conf_ac->ac = wl1271_tx_get_queue(queue); + conf_ac->cw_min = (u8)params->cw_min; + conf_ac->cw_max = params->cw_max; + conf_ac->aifsn = params->aifs; + conf_ac->tx_op_limit = params->txop << 5; + + conf_tid->queue_id = wl1271_tx_get_queue(queue); + conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF; + conf_tid->tsid = wl1271_tx_get_queue(queue); + conf_tid->ps_scheme = ps_scheme; + conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY; + conf_tid->apsd_conf[0] = 0; + conf_tid->apsd_conf[1] = 0; + } else { + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + /* + * the txop is confed in units of 32us by the mac80211, + * we need us + */ + ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue), + params->cw_min, params->cw_max, + params->aifs, params->txop << 5); + if (ret < 0) + goto out_sleep; + + ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue), + CONF_CHANNEL_TYPE_EDCF, + wl1271_tx_get_queue(queue), + ps_scheme, CONF_ACK_POLICY_LEGACY, + 0, 0); + if (ret < 0) + goto out_sleep; out_sleep: - wl1271_ps_elp_sleep(wl); + wl1271_ps_elp_sleep(wl); + } out: mutex_unlock(&wl->mutex); @@ -2247,6 +2616,173 @@ static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx, return 0; } +static int wl1271_allocate_hlid(struct wl1271 *wl, + struct ieee80211_sta *sta, + u8 *hlid) +{ + struct wl1271_station *wl_sta; + int id; + + id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS); + if (id >= AP_MAX_STATIONS) { + wl1271_warning("could not allocate HLID - too much stations"); + return -EBUSY; + } + + wl_sta = (struct wl1271_station *)sta->drv_priv; + + __set_bit(id, wl->ap_hlid_map); + wl_sta->hlid = WL1271_AP_STA_HLID_START + id; + *hlid = wl_sta->hlid; + return 0; +} + +static void wl1271_free_hlid(struct wl1271 *wl, u8 hlid) +{ + int id = hlid - WL1271_AP_STA_HLID_START; + + __clear_bit(id, wl->ap_hlid_map); +} + +static int wl1271_op_sta_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct wl1271 *wl = hw->priv; + int ret = 0; + u8 hlid; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + if (wl->bss_type != BSS_TYPE_AP_BSS) + goto out; + + wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid); + + ret = wl1271_allocate_hlid(wl, sta, &hlid); + if (ret < 0) + goto out; + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + ret = wl1271_cmd_add_sta(wl, sta, hlid); + if (ret < 0) + goto out_sleep; + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + return ret; +} + +static int wl1271_op_sta_remove(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct wl1271 *wl = hw->priv; + struct wl1271_station *wl_sta; + int ret = 0, id; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + if (wl->bss_type != BSS_TYPE_AP_BSS) + goto out; + + wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid); + + wl_sta = (struct wl1271_station *)sta->drv_priv; + id = wl_sta->hlid - WL1271_AP_STA_HLID_START; + if (WARN_ON(!test_bit(id, wl->ap_hlid_map))) + goto out; + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid); + if (ret < 0) + goto out_sleep; + + wl1271_free_hlid(wl, wl_sta->hlid); + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + return ret; +} + +int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size) +{ + struct wl1271 *wl = hw->priv; + int ret; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) { + ret = -EAGAIN; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + + switch (action) { + case IEEE80211_AMPDU_RX_START: + if (wl->ba_support) { + ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn, + true); + if (!ret) + wl->ba_rx_bitmap |= BIT(tid); + } else { + ret = -ENOTSUPP; + } + break; + + case IEEE80211_AMPDU_RX_STOP: + ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false); + if (!ret) + wl->ba_rx_bitmap &= ~BIT(tid); + break; + + /* + * The BA initiator session management in FW independently. + * Falling break here on purpose for all TX APDU commands. + */ + case IEEE80211_AMPDU_TX_START: + case IEEE80211_AMPDU_TX_STOP: + case IEEE80211_AMPDU_TX_OPERATIONAL: + ret = -EINVAL; + break; + + default: + wl1271_error("Incorrect ampdu action id=%x\n", action); + ret = -EINVAL; + } + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + /* can't be const, mac80211 writes to this */ static struct ieee80211_rate wl1271_rates[] = { { .bitrate = 10, @@ -2305,6 +2841,7 @@ static struct ieee80211_channel wl1271_channels[] = { { .hw_value = 11, .center_freq = 2462, .max_power = 25 }, { .hw_value = 12, .center_freq = 2467, .max_power = 25 }, { .hw_value = 13, .center_freq = 2472, .max_power = 25 }, + { .hw_value = 14, .center_freq = 2484, .max_power = 25 }, }; /* mapping to indexes for wl1271_rates */ @@ -2493,6 +3030,9 @@ static const struct ieee80211_ops wl1271_ops = { .conf_tx = wl1271_op_conf_tx, .get_tsf = wl1271_op_get_tsf, .get_survey = wl1271_op_get_survey, + .sta_add = wl1271_op_sta_add, + .sta_remove = wl1271_op_sta_remove, + .ampdu_action = wl1271_op_ampdu_action, CFG80211_TESTMODE_CMD(wl1271_tm_cmd) }; @@ -2607,6 +3147,18 @@ int wl1271_register_hw(struct wl1271 *wl) if (wl->mac80211_registered) return 0; + ret = wl1271_fetch_nvs(wl); + if (ret == 0) { + u8 *nvs_ptr = (u8 *)wl->nvs->nvs; + + wl->mac_addr[0] = nvs_ptr[11]; + wl->mac_addr[1] = nvs_ptr[10]; + wl->mac_addr[2] = nvs_ptr[6]; + wl->mac_addr[3] = nvs_ptr[5]; + wl->mac_addr[4] = nvs_ptr[4]; + wl->mac_addr[5] = nvs_ptr[3]; + } + SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); ret = ieee80211_register_hw(wl->hw); @@ -2629,6 +3181,9 @@ EXPORT_SYMBOL_GPL(wl1271_register_hw); void wl1271_unregister_hw(struct wl1271 *wl) { + if (wl->state == WL1271_STATE_PLT) + __wl1271_plt_stop(wl); + unregister_netdevice_notifier(&wl1271_dev_notifier); ieee80211_unregister_hw(wl->hw); wl->mac80211_registered = false; @@ -2667,7 +3222,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); + BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); wl->hw->wiphy->max_scan_ssids = 1; /* * Maximum length of elements in scanning probe request templates @@ -2676,8 +3231,20 @@ int wl1271_init_ieee80211(struct wl1271 *wl) */ wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - sizeof(struct ieee80211_header); - wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz; - wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz; + + /* + * We keep local copies of the band structs because we need to + * modify them on a per-device basis. + */ + memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz, + sizeof(wl1271_band_2ghz)); + memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz, + sizeof(wl1271_band_5ghz)); + + wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &wl->bands[IEEE80211_BAND_2GHZ]; + wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &wl->bands[IEEE80211_BAND_5GHZ]; wl->hw->queues = 4; wl->hw->max_rates = 1; @@ -2686,6 +3253,10 @@ int wl1271_init_ieee80211(struct wl1271 *wl) SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl)); + wl->hw->sta_data_size = sizeof(struct wl1271_station); + + wl->hw->max_rx_aggregation_subframes = 8; + return 0; } EXPORT_SYMBOL_GPL(wl1271_init_ieee80211); @@ -2735,8 +3306,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->beacon_int = WL1271_DEFAULT_BEACON_INT; wl->default_key = 0; wl->rx_counter = 0; - wl->rx_config = WL1271_DEFAULT_RX_CONFIG; - wl->rx_filter = WL1271_DEFAULT_RX_FILTER; + wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG; + wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER; wl->psm_entry_retry = 0; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; @@ -2748,6 +3319,9 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->flags = 0; wl->sg_enabled = true; wl->hw_pg_ver = -1; + wl->bss_type = MAX_BSS_TYPE; + wl->set_bss_type = MAX_BSS_TYPE; + wl->fw_bss_type = MAX_BSS_TYPE; memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); for (i = 0; i < ACX_TX_DESCRIPTORS; i++) @@ -2837,9 +3411,9 @@ int wl1271_free_hw(struct wl1271 *wl) } EXPORT_SYMBOL_GPL(wl1271_free_hw); -u32 wl12xx_debug_level; +u32 wl12xx_debug_level = DEBUG_NONE; EXPORT_SYMBOL_GPL(wl12xx_debug_level); -module_param_named(debug_level, wl12xx_debug_level, uint, DEBUG_NONE); +module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR); MODULE_PARM_DESC(debug_level, "wl12xx debugging level"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 682304c30b81..b0c6ddc2a945 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -76,7 +76,7 @@ static void wl1271_rx_status(struct wl1271 *wl, */ wl->noise = desc->rssi - (desc->snr >> 1); - status->freq = ieee80211_channel_to_frequency(desc->channel); + status->freq = ieee80211_channel_to_frequency(desc->channel, desc_band); if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; @@ -198,6 +198,16 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) pkt_offset += pkt_length; } } - wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, - cpu_to_le32(wl->rx_counter)); + wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); +} + +void wl1271_set_default_filters(struct wl1271 *wl) +{ + if (wl->bss_type == BSS_TYPE_AP_BSS) { + wl->rx_config = WL1271_DEFAULT_AP_RX_CONFIG; + wl->rx_filter = WL1271_DEFAULT_AP_RX_FILTER; + } else { + wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG; + wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER; + } } diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h index 3abb26fe0364..8d048b36bbba 100644 --- a/drivers/net/wireless/wl12xx/rx.h +++ b/drivers/net/wireless/wl12xx/rx.h @@ -86,8 +86,9 @@ /* * RX Descriptor status * - * Bits 0-2 - status - * Bits 3-7 - reserved + * Bits 0-2 - error code + * Bits 3-5 - process_id tag (AP mode FW) + * Bits 6-7 - reserved */ #define WL1271_RX_DESC_STATUS_MASK 0x07 @@ -110,12 +111,16 @@ struct wl1271_rx_descriptor { u8 snr; __le32 timestamp; u8 packet_class; - u8 process_id; + union { + u8 process_id; /* STA FW */ + u8 hlid; /* AP FW */ + } __packed; u8 pad_len; u8 reserved; } __packed; void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status); u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); +void wl1271_set_default_filters(struct wl1271 *wl); #endif diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index 93cbb8d5aba9..d5e874825069 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -345,3 +345,4 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); MODULE_FIRMWARE(WL1271_FW_NAME); +MODULE_FIRMWARE(WL1271_AP_FW_NAME); diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index 7145ea543783..0132dad756c4 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -110,6 +110,7 @@ static void wl1271_spi_reset(struct wl1271 *wl) spi_message_add_tail(&t, &m); spi_sync(wl_to_spi(wl), &m); + wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); kfree(cmd); } @@ -494,4 +495,5 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); MODULE_FIRMWARE(WL1271_FW_NAME); +MODULE_FIRMWARE(WL1271_AP_FW_NAME); MODULE_ALIAS("spi:wl1271"); diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index b44c75cd8c1e..3507c81c7500 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -23,6 +23,7 @@ #include <linux/kernel.h> #include <linux/module.h> +#include <linux/etherdevice.h> #include "wl12xx.h" #include "io.h" @@ -30,6 +31,23 @@ #include "ps.h" #include "tx.h" +static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id) +{ + int ret; + bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); + + if (is_ap) + ret = wl1271_cmd_set_ap_default_wep_key(wl, id); + else + ret = wl1271_cmd_set_sta_default_wep_key(wl, id); + + if (ret < 0) + return ret; + + wl1271_debug(DEBUG_CRYPT, "default wep key idx: %d", (int)id); + return 0; +} + static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb) { int id; @@ -99,7 +117,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, { struct timespec ts; struct wl1271_tx_hw_descr *desc; - int pad, ac; + int pad, ac, rate_idx; s64 hosttime; u16 tx_attr; @@ -117,7 +135,11 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, getnstimeofday(&ts); hosttime = (timespec_to_ns(&ts) >> 10); desc->start_time = cpu_to_le32(hosttime - wl->time_offset); - desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); + + if (wl->bss_type != BSS_TYPE_AP_BSS) + desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); + else + desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); /* configure the tx attributes */ tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; @@ -125,7 +147,41 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, /* queue (we use same identifiers for tid's and ac's */ ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); desc->tid = ac; - desc->aid = TX_HW_DEFAULT_AID; + + if (wl->bss_type != BSS_TYPE_AP_BSS) { + desc->aid = TX_HW_DEFAULT_AID; + + /* if the packets are destined for AP (have a STA entry) + send them with AP rate policies, otherwise use default + basic rates */ + if (control->control.sta) + rate_idx = ACX_TX_AP_FULL_RATE; + else + rate_idx = ACX_TX_BASIC_RATE; + } else { + if (control->control.sta) { + struct wl1271_station *wl_sta; + + wl_sta = (struct wl1271_station *) + control->control.sta->drv_priv; + desc->hlid = wl_sta->hlid; + rate_idx = ac; + } else { + struct ieee80211_hdr *hdr; + + hdr = (struct ieee80211_hdr *) + (skb->data + sizeof(*desc)); + if (ieee80211_is_mgmt(hdr->frame_control)) { + desc->hlid = WL1271_AP_GLOBAL_HLID; + rate_idx = ACX_TX_AP_MODE_MGMT_RATE; + } else { + desc->hlid = WL1271_AP_BROADCAST_HLID; + rate_idx = ACX_TX_AP_MODE_BCST_RATE; + } + } + } + + tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; desc->reserved = 0; /* align the length (and store in terms of words) */ @@ -136,14 +192,12 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, pad = pad - skb->len; tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; - /* if the packets are destined for AP (have a STA entry) send them - with AP rate policies, otherwise use default basic rates */ - if (control->control.sta) - tx_attr |= ACX_TX_AP_FULL_RATE << TX_HW_ATTR_OFST_RATE_POLICY; - desc->tx_attr = cpu_to_le16(tx_attr); - wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad); + wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d " + "tx_attr: 0x%x len: %d life: %d mem: %d", pad, desc->hlid, + le16_to_cpu(desc->tx_attr), le16_to_cpu(desc->length), + le16_to_cpu(desc->life_time), desc->total_mem_blocks); } /* caller must hold wl->mutex */ @@ -153,7 +207,6 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, struct ieee80211_tx_info *info; u32 extra = 0; int ret = 0; - u8 idx; u32 total_len; if (!skb) @@ -166,11 +219,15 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, extra = WL1271_TKIP_IV_SPACE; if (info->control.hw_key) { - idx = info->control.hw_key->hw_key_idx; + bool is_wep; + u8 idx = info->control.hw_key->hw_key_idx; + u32 cipher = info->control.hw_key->cipher; + + is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) || + (cipher == WLAN_CIPHER_SUITE_WEP104); - /* FIXME: do we have to do this if we're not using WEP? */ - if (unlikely(wl->default_key != idx)) { - ret = wl1271_cmd_set_default_wep_key(wl, idx); + if (unlikely(is_wep && wl->default_key != idx)) { + ret = wl1271_set_default_wep_key(wl, idx); if (ret < 0) return ret; wl->default_key = idx; @@ -303,7 +360,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl) woken_up = true; wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates); - wl1271_acx_rate_policies(wl); + wl1271_acx_sta_rate_policies(wl); } while ((skb = wl1271_skb_dequeue(wl))) { @@ -521,3 +578,21 @@ void wl1271_tx_flush(struct wl1271 *wl) wl1271_warning("Unable to flush all TX buffers, timed out."); } + +u32 wl1271_tx_min_rate_get(struct wl1271 *wl) +{ + int i; + u32 rate = 0; + + if (!wl->basic_rate_set) { + WARN_ON(1); + wl->basic_rate_set = wl->conf.tx.basic_rate; + } + + for (i = 0; !rate; i++) { + if ((wl->basic_rate_set >> i) & 0x1) + rate = 1 << i; + } + + return rate; +} diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index 903e5dc69b7a..05722a560d91 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h @@ -29,6 +29,7 @@ #define TX_HW_BLOCK_SIZE 252 #define TX_HW_MGMT_PKT_LIFETIME_TU 2000 +#define TX_HW_AP_MODE_PKT_LIFETIME_TU 8000 /* The chipset reference driver states, that the "aid" value 1 * is for infra-BSS, but is still always used */ #define TX_HW_DEFAULT_AID 1 @@ -77,8 +78,12 @@ struct wl1271_tx_hw_descr { u8 id; /* The packet TID value (as User-Priority) */ u8 tid; - /* Identifier of the remote STA in IBSS, 1 in infra-BSS */ - u8 aid; + union { + /* STA - Identifier of the remote STA in IBSS, 1 in infra-BSS */ + u8 aid; + /* AP - host link ID (HLID) */ + u8 hlid; + } __packed; u8 reserved; } __packed; @@ -146,5 +151,6 @@ void wl1271_tx_reset(struct wl1271 *wl); void wl1271_tx_flush(struct wl1271 *wl); u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); +u32 wl1271_tx_min_rate_get(struct wl1271 *wl); #endif diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 9050dd9b62d2..d1de13fe7d9a 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -38,6 +38,13 @@ #define DRIVER_NAME "wl1271" #define DRIVER_PREFIX DRIVER_NAME ": " +/* + * FW versions support BA 11n + * versions marks x.x.x.50-60.x + */ +#define WL12XX_BA_SUPPORT_FW_COST_VER2_START 50 +#define WL12XX_BA_SUPPORT_FW_COST_VER2_END 60 + enum { DEBUG_NONE = 0, DEBUG_IRQ = BIT(0), @@ -57,6 +64,8 @@ enum { DEBUG_SDIO = BIT(14), DEBUG_FILTERS = BIT(15), DEBUG_ADHOC = BIT(16), + DEBUG_AP = BIT(17), + DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP), DEBUG_ALL = ~0, }; @@ -103,16 +112,27 @@ extern u32 wl12xx_debug_level; true); \ } while (0) -#define WL1271_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ +#define WL1271_DEFAULT_STA_RX_CONFIG (CFG_UNI_FILTER_EN | \ CFG_BSSID_FILTER_EN | \ CFG_MC_FILTER_EN) -#define WL1271_DEFAULT_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \ +#define WL1271_DEFAULT_STA_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \ CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \ CFG_RX_CTL_EN | CFG_RX_BCN_EN | \ CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) +#define WL1271_DEFAULT_AP_RX_CONFIG 0 + +#define WL1271_DEFAULT_AP_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PREQ_EN | \ + CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \ + CFG_RX_CTL_EN | CFG_RX_AUTH_EN | \ + CFG_RX_ASSOC_EN) + + + #define WL1271_FW_NAME "wl1271-fw.bin" +#define WL1271_AP_FW_NAME "wl1271-fw-ap.bin" + #define WL1271_NVS_NAME "wl1271-nvs.bin" #define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) @@ -129,6 +149,14 @@ extern u32 wl12xx_debug_level; #define WL1271_DEFAULT_BEACON_INT 100 #define WL1271_DEFAULT_DTIM_PERIOD 1 +#define WL1271_AP_GLOBAL_HLID 0 +#define WL1271_AP_BROADCAST_HLID 1 +#define WL1271_AP_STA_HLID_START 2 + +#define WL1271_AP_BSS_INDEX 0 +#define WL1271_AP_DEF_INACTIV_SEC 300 +#define WL1271_AP_DEF_BEACON_EXP 20 + #define ACX_TX_DESCRIPTORS 32 #define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) @@ -161,10 +189,13 @@ struct wl1271_partition_set { struct wl1271; +#define WL12XX_NUM_FW_VER 5 + /* FIXME: I'm not sure about this structure name */ struct wl1271_chip { u32 id; - char fw_ver[21]; + char fw_ver_str[ETHTOOL_BUSINFO_LEN]; + unsigned int fw_ver[WL12XX_NUM_FW_VER]; }; struct wl1271_stats { @@ -178,6 +209,11 @@ struct wl1271_stats { #define NUM_TX_QUEUES 4 #define NUM_RX_PKT_DESC 8 +#define AP_MAX_STATIONS 5 + +/* Broadcast and Global links + links to stations */ +#define AP_MAX_LINKS (AP_MAX_STATIONS + 2) + /* FW status registers */ struct wl1271_fw_status { __le32 intr; @@ -188,7 +224,18 @@ struct wl1271_fw_status { __le32 rx_pkt_descs[NUM_RX_PKT_DESC]; __le32 tx_released_blks[NUM_TX_QUEUES]; __le32 fw_localtime; - __le32 padding[2]; + + /* Next fields valid only in AP FW */ + + /* + * A bitmap (where each bit represents a single HLID) + * to indicate if the station is in PS mode. + */ + __le32 link_ps_bitmap; + + /* Number of freed MBs per HLID */ + u8 tx_lnk_free_blks[AP_MAX_LINKS]; + u8 padding_1[1]; } __packed; struct wl1271_rx_mem_pool_addr { @@ -218,6 +265,19 @@ struct wl1271_if_operations { void (*disable_irq)(struct wl1271 *wl); }; +#define MAX_NUM_KEYS 14 +#define MAX_KEY_SIZE 32 + +struct wl1271_ap_key { + u8 id; + u8 key_type; + u8 key_size; + u8 key[MAX_KEY_SIZE]; + u8 hlid; + u32 tx_seq_32; + u16 tx_seq_16; +}; + struct wl1271 { struct platform_device *plat_dev; struct ieee80211_hw *hw; @@ -251,6 +311,7 @@ struct wl1271 { #define WL1271_FLAG_PSPOLL_FAILURE (12) #define WL1271_FLAG_STA_STATE_SENT (13) #define WL1271_FLAG_FW_TX_BUSY (14) +#define WL1271_FLAG_AP_STARTED (15) unsigned long flags; struct wl1271_partition_set part; @@ -262,6 +323,7 @@ struct wl1271 { u8 *fw; size_t fw_len; + u8 fw_bss_type; struct wl1271_nvs_file *nvs; size_t nvs_len; @@ -378,7 +440,6 @@ struct wl1271 { int last_rssi_event; struct wl1271_stats stats; - struct dentry *rootdir; __le32 buffer_32; u32 buffer_cmd; @@ -400,6 +461,23 @@ struct wl1271 { /* Most recently reported noise in dBm */ s8 noise; + + /* map for HLIDs of associated stations - when operating in AP mode */ + unsigned long ap_hlid_map[BITS_TO_LONGS(AP_MAX_STATIONS)]; + + /* recoreded keys for AP-mode - set here before AP startup */ + struct wl1271_ap_key *recorded_ap_keys[MAX_NUM_KEYS]; + + /* bands supported by this instance of wl12xx */ + struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; + + /* RX BA constraint value */ + bool ba_support; + u8 ba_rx_bitmap; +}; + +struct wl1271_station { + u8 hlid; }; int wl1271_plt_start(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h index be21032f4dc1..67dcf8f28cd3 100644 --- a/drivers/net/wireless/wl12xx/wl12xx_80211.h +++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h @@ -138,13 +138,13 @@ struct wl12xx_arp_rsp_template { struct ieee80211_hdr_3addr hdr; u8 llc_hdr[sizeof(rfc1042_header)]; - u16 llc_type; + __be16 llc_type; struct arphdr arp_hdr; u8 sender_hw[ETH_ALEN]; - u32 sender_ip; + __be32 sender_ip; u8 target_hw[ETH_ALEN]; - u32 target_ip; + __be32 target_ip; } __packed; @@ -160,4 +160,9 @@ struct wl12xx_probe_resp_template { struct wl12xx_ie_country country; } __packed; +struct wl12xx_disconn_template { + struct ieee80211_header header; + __le16 disconn_reason; +} __packed; + #endif diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 6a9b66051cf7..54f68f134ea7 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -108,25 +108,17 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr { int r; int i; - zd_addr_t *a16; - u16 *v16; + zd_addr_t a16[USB_MAX_IOREAD32_COUNT * 2]; + u16 v16[USB_MAX_IOREAD32_COUNT * 2]; unsigned int count16; if (count > USB_MAX_IOREAD32_COUNT) return -EINVAL; - /* Allocate a single memory block for values and addresses. */ - count16 = 2*count; - /* zd_addr_t is __nocast, so the kmalloc needs an explicit cast */ - a16 = (zd_addr_t *) kmalloc(count16 * (sizeof(zd_addr_t) + sizeof(u16)), - GFP_KERNEL); - if (!a16) { - dev_dbg_f(zd_chip_dev(chip), - "error ENOMEM in allocation of a16\n"); - r = -ENOMEM; - goto out; - } - v16 = (u16 *)(a16 + count16); + /* Use stack for values and addresses. */ + count16 = 2 * count; + BUG_ON(count16 * sizeof(zd_addr_t) > sizeof(a16)); + BUG_ON(count16 * sizeof(u16) > sizeof(v16)); for (i = 0; i < count; i++) { int j = 2*i; @@ -139,7 +131,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr if (r) { dev_dbg_f(zd_chip_dev(chip), "error: zd_ioread16v_locked. Error number %d\n", r); - goto out; + return r; } for (i = 0; i < count; i++) { @@ -147,18 +139,18 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr values[i] = (v16[j] << 16) | v16[j+1]; } -out: - kfree((void *)a16); - return r; + return 0; } int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs, unsigned int count) { int i, j, r; - struct zd_ioreq16 *ioreqs16; + struct zd_ioreq16 ioreqs16[USB_MAX_IOWRITE32_COUNT * 2]; unsigned int count16; + /* Use stack for values and addresses. */ + ZD_ASSERT(mutex_is_locked(&chip->mutex)); if (count == 0) @@ -166,15 +158,8 @@ int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs, if (count > USB_MAX_IOWRITE32_COUNT) return -EINVAL; - /* Allocate a single memory block for values and addresses. */ - count16 = 2*count; - ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_KERNEL); - if (!ioreqs16) { - r = -ENOMEM; - dev_dbg_f(zd_chip_dev(chip), - "error %d in ioreqs16 allocation\n", r); - goto out; - } + count16 = 2 * count; + BUG_ON(count16 * sizeof(struct zd_ioreq16) > sizeof(ioreqs16)); for (i = 0; i < count; i++) { j = 2*i; @@ -192,8 +177,6 @@ int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs, "error %d in zd_usb_write16v\n", r); } #endif /* DEBUG */ -out: - kfree(ioreqs16); return r; } @@ -370,16 +353,12 @@ error: return r; } -/* MAC address: if custom mac addresses are to be used CR_MAC_ADDR_P1 and - * CR_MAC_ADDR_P2 must be overwritten - */ -int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr) +static int zd_write_mac_addr_common(struct zd_chip *chip, const u8 *mac_addr, + const struct zd_ioreq32 *in_reqs, + const char *type) { int r; - struct zd_ioreq32 reqs[2] = { - [0] = { .addr = CR_MAC_ADDR_P1 }, - [1] = { .addr = CR_MAC_ADDR_P2 }, - }; + struct zd_ioreq32 reqs[2] = {in_reqs[0], in_reqs[1]}; if (mac_addr) { reqs[0].value = (mac_addr[3] << 24) @@ -388,9 +367,9 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr) | mac_addr[0]; reqs[1].value = (mac_addr[5] << 8) | mac_addr[4]; - dev_dbg_f(zd_chip_dev(chip), "mac addr %pM\n", mac_addr); + dev_dbg_f(zd_chip_dev(chip), "%s addr %pM\n", type, mac_addr); } else { - dev_dbg_f(zd_chip_dev(chip), "set NULL mac\n"); + dev_dbg_f(zd_chip_dev(chip), "set NULL %s\n", type); } mutex_lock(&chip->mutex); @@ -399,6 +378,29 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr) return r; } +/* MAC address: if custom mac addresses are to be used CR_MAC_ADDR_P1 and + * CR_MAC_ADDR_P2 must be overwritten + */ +int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr) +{ + static const struct zd_ioreq32 reqs[2] = { + [0] = { .addr = CR_MAC_ADDR_P1 }, + [1] = { .addr = CR_MAC_ADDR_P2 }, + }; + + return zd_write_mac_addr_common(chip, mac_addr, reqs, "mac"); +} + +int zd_write_bssid(struct zd_chip *chip, const u8 *bssid) +{ + static const struct zd_ioreq32 reqs[2] = { + [0] = { .addr = CR_BSSID_P1 }, + [1] = { .addr = CR_BSSID_P2 }, + }; + + return zd_write_mac_addr_common(chip, bssid, reqs, "bssid"); +} + int zd_read_regdomain(struct zd_chip *chip, u8 *regdomain) { int r; @@ -849,11 +851,12 @@ static int get_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s) static int set_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s) { struct zd_ioreq32 reqs[3]; + u16 b_interval = s->beacon_interval & 0xffff; - if (s->beacon_interval <= 5) - s->beacon_interval = 5; - if (s->pre_tbtt < 4 || s->pre_tbtt >= s->beacon_interval) - s->pre_tbtt = s->beacon_interval - 1; + if (b_interval <= 5) + b_interval = 5; + if (s->pre_tbtt < 4 || s->pre_tbtt >= b_interval) + s->pre_tbtt = b_interval - 1; if (s->atim_wnd_period >= s->pre_tbtt) s->atim_wnd_period = s->pre_tbtt - 1; @@ -862,31 +865,57 @@ static int set_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s) reqs[1].addr = CR_PRE_TBTT; reqs[1].value = s->pre_tbtt; reqs[2].addr = CR_BCN_INTERVAL; - reqs[2].value = s->beacon_interval; + reqs[2].value = (s->beacon_interval & ~0xffff) | b_interval; return zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs)); } -static int set_beacon_interval(struct zd_chip *chip, u32 interval) +static int set_beacon_interval(struct zd_chip *chip, u16 interval, + u8 dtim_period, int type) { int r; struct aw_pt_bi s; + u32 b_interval, mode_flag; ZD_ASSERT(mutex_is_locked(&chip->mutex)); + + if (interval > 0) { + switch (type) { + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + mode_flag = BCN_MODE_IBSS; + break; + case NL80211_IFTYPE_AP: + mode_flag = BCN_MODE_AP; + break; + default: + mode_flag = 0; + break; + } + } else { + dtim_period = 0; + mode_flag = 0; + } + + b_interval = mode_flag | (dtim_period << 16) | interval; + + r = zd_iowrite32_locked(chip, b_interval, CR_BCN_INTERVAL); + if (r) + return r; r = get_aw_pt_bi(chip, &s); if (r) return r; - s.beacon_interval = interval; return set_aw_pt_bi(chip, &s); } -int zd_set_beacon_interval(struct zd_chip *chip, u32 interval) +int zd_set_beacon_interval(struct zd_chip *chip, u16 interval, u8 dtim_period, + int type) { int r; mutex_lock(&chip->mutex); - r = set_beacon_interval(chip, interval); + r = set_beacon_interval(chip, interval, dtim_period, type); mutex_unlock(&chip->mutex); return r; } @@ -905,7 +934,7 @@ static int hw_init(struct zd_chip *chip) if (r) return r; - return set_beacon_interval(chip, 100); + return set_beacon_interval(chip, 100, 0, NL80211_IFTYPE_UNSPECIFIED); } static zd_addr_t fw_reg_addr(struct zd_chip *chip, u16 offset) @@ -1407,6 +1436,9 @@ void zd_chip_disable_int(struct zd_chip *chip) mutex_lock(&chip->mutex); zd_usb_disable_int(&chip->usb); mutex_unlock(&chip->mutex); + + /* cancel pending interrupt work */ + cancel_work_sync(&zd_chip_to_mac(chip)->process_intr); } int zd_chip_enable_rxtx(struct zd_chip *chip) @@ -1416,6 +1448,7 @@ int zd_chip_enable_rxtx(struct zd_chip *chip) mutex_lock(&chip->mutex); zd_usb_enable_tx(&chip->usb); r = zd_usb_enable_rx(&chip->usb); + zd_tx_watchdog_enable(&chip->usb); mutex_unlock(&chip->mutex); return r; } @@ -1423,6 +1456,7 @@ int zd_chip_enable_rxtx(struct zd_chip *chip) void zd_chip_disable_rxtx(struct zd_chip *chip) { mutex_lock(&chip->mutex); + zd_tx_watchdog_disable(&chip->usb); zd_usb_disable_rx(&chip->usb); zd_usb_disable_tx(&chip->usb); mutex_unlock(&chip->mutex); diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index f8bbf7d302ae..14e4402a6111 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -546,6 +546,7 @@ enum { #define RX_FILTER_CTRL (RX_FILTER_RTS | RX_FILTER_CTS | \ RX_FILTER_CFEND | RX_FILTER_CFACK) +#define BCN_MODE_AP 0x1000000 #define BCN_MODE_IBSS 0x2000000 /* Monitor mode sets filter to 0xfffff */ @@ -881,6 +882,7 @@ static inline u8 _zd_chip_get_channel(struct zd_chip *chip) u8 zd_chip_get_channel(struct zd_chip *chip); int zd_read_regdomain(struct zd_chip *chip, u8 *regdomain); int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr); +int zd_write_bssid(struct zd_chip *chip, const u8 *bssid); int zd_chip_switch_radio_on(struct zd_chip *chip); int zd_chip_switch_radio_off(struct zd_chip *chip); int zd_chip_enable_int(struct zd_chip *chip); @@ -920,7 +922,8 @@ enum led_status { int zd_chip_control_leds(struct zd_chip *chip, enum led_status status); -int zd_set_beacon_interval(struct zd_chip *chip, u32 interval); +int zd_set_beacon_interval(struct zd_chip *chip, u16 interval, u8 dtim_period, + int type); static inline int zd_get_beacon_interval(struct zd_chip *chip, u32 *interval) { diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 6107304cb94c..74a269ebbeb9 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -138,6 +138,12 @@ static const struct ieee80211_channel zd_channels[] = { static void housekeeping_init(struct zd_mac *mac); static void housekeeping_enable(struct zd_mac *mac); static void housekeeping_disable(struct zd_mac *mac); +static void beacon_init(struct zd_mac *mac); +static void beacon_enable(struct zd_mac *mac); +static void beacon_disable(struct zd_mac *mac); +static void set_rts_cts(struct zd_mac *mac, unsigned int short_preamble); +static int zd_mac_config_beacon(struct ieee80211_hw *hw, + struct sk_buff *beacon); static int zd_reg2alpha2(u8 regdomain, char *alpha2) { @@ -231,6 +237,26 @@ static int set_rx_filter(struct zd_mac *mac) return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter); } +static int set_mac_and_bssid(struct zd_mac *mac) +{ + int r; + + if (!mac->vif) + return -1; + + r = zd_write_mac_addr(&mac->chip, mac->vif->addr); + if (r) + return r; + + /* Vendor driver after setting MAC either sets BSSID for AP or + * filter for other modes. + */ + if (mac->type != NL80211_IFTYPE_AP) + return set_rx_filter(mac); + else + return zd_write_bssid(&mac->chip, mac->vif->addr); +} + static int set_mc_hash(struct zd_mac *mac) { struct zd_mc_hash hash; @@ -238,7 +264,7 @@ static int set_mc_hash(struct zd_mac *mac) return zd_chip_set_multicast_hash(&mac->chip, &hash); } -static int zd_op_start(struct ieee80211_hw *hw) +int zd_op_start(struct ieee80211_hw *hw) { struct zd_mac *mac = zd_hw_mac(hw); struct zd_chip *chip = &mac->chip; @@ -275,6 +301,8 @@ static int zd_op_start(struct ieee80211_hw *hw) goto disable_rxtx; housekeeping_enable(mac); + beacon_enable(mac); + set_bit(ZD_DEVICE_RUNNING, &mac->flags); return 0; disable_rxtx: zd_chip_disable_rxtx(chip); @@ -286,19 +314,22 @@ out: return r; } -static void zd_op_stop(struct ieee80211_hw *hw) +void zd_op_stop(struct ieee80211_hw *hw) { struct zd_mac *mac = zd_hw_mac(hw); struct zd_chip *chip = &mac->chip; struct sk_buff *skb; struct sk_buff_head *ack_wait_queue = &mac->ack_wait_queue; + clear_bit(ZD_DEVICE_RUNNING, &mac->flags); + /* The order here deliberately is a little different from the open() * method, since we need to make sure there is no opportunity for RX * frames to be processed by mac80211 after we have stopped it. */ zd_chip_disable_rxtx(chip); + beacon_disable(mac); housekeeping_disable(mac); flush_workqueue(zd_workqueue); @@ -311,6 +342,68 @@ static void zd_op_stop(struct ieee80211_hw *hw) dev_kfree_skb_any(skb); } +int zd_restore_settings(struct zd_mac *mac) +{ + struct sk_buff *beacon; + struct zd_mc_hash multicast_hash; + unsigned int short_preamble; + int r, beacon_interval, beacon_period; + u8 channel; + + dev_dbg_f(zd_mac_dev(mac), "\n"); + + spin_lock_irq(&mac->lock); + multicast_hash = mac->multicast_hash; + short_preamble = mac->short_preamble; + beacon_interval = mac->beacon.interval; + beacon_period = mac->beacon.period; + channel = mac->channel; + spin_unlock_irq(&mac->lock); + + r = set_mac_and_bssid(mac); + if (r < 0) { + dev_dbg_f(zd_mac_dev(mac), "set_mac_and_bssid failed, %d\n", r); + return r; + } + + r = zd_chip_set_channel(&mac->chip, channel); + if (r < 0) { + dev_dbg_f(zd_mac_dev(mac), "zd_chip_set_channel failed, %d\n", + r); + return r; + } + + set_rts_cts(mac, short_preamble); + + r = zd_chip_set_multicast_hash(&mac->chip, &multicast_hash); + if (r < 0) { + dev_dbg_f(zd_mac_dev(mac), + "zd_chip_set_multicast_hash failed, %d\n", r); + return r; + } + + if (mac->type == NL80211_IFTYPE_MESH_POINT || + mac->type == NL80211_IFTYPE_ADHOC || + mac->type == NL80211_IFTYPE_AP) { + if (mac->vif != NULL) { + beacon = ieee80211_beacon_get(mac->hw, mac->vif); + if (beacon) { + zd_mac_config_beacon(mac->hw, beacon); + kfree_skb(beacon); + } + } + + zd_set_beacon_interval(&mac->chip, beacon_interval, + beacon_period, mac->type); + + spin_lock_irq(&mac->lock); + mac->beacon.last_update = jiffies; + spin_unlock_irq(&mac->lock); + } + + return 0; +} + /** * zd_mac_tx_status - reports tx status of a packet if required * @hw - a &struct ieee80211_hw pointer @@ -574,64 +667,120 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon) { struct zd_mac *mac = zd_hw_mac(hw); - int r; + int r, ret, num_cmds, req_pos = 0; u32 tmp, j = 0; /* 4 more bytes for tail CRC */ u32 full_len = beacon->len + 4; + unsigned long end_jiffies, message_jiffies; + struct zd_ioreq32 *ioreqs; + + /* Alloc memory for full beacon write at once. */ + num_cmds = 1 + zd_chip_is_zd1211b(&mac->chip) + full_len; + ioreqs = kmalloc(num_cmds * sizeof(struct zd_ioreq32), GFP_KERNEL); + if (!ioreqs) + return -ENOMEM; - r = zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 0); + mutex_lock(&mac->chip.mutex); + + r = zd_iowrite32_locked(&mac->chip, 0, CR_BCN_FIFO_SEMAPHORE); if (r < 0) - return r; - r = zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp); + goto out; + r = zd_ioread32_locked(&mac->chip, &tmp, CR_BCN_FIFO_SEMAPHORE); if (r < 0) - return r; + goto release_sema; + end_jiffies = jiffies + HZ / 2; /*~500ms*/ + message_jiffies = jiffies + HZ / 10; /*~100ms*/ while (tmp & 0x2) { - r = zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp); + r = zd_ioread32_locked(&mac->chip, &tmp, CR_BCN_FIFO_SEMAPHORE); if (r < 0) - return r; - if ((++j % 100) == 0) { - printk(KERN_ERR "CR_BCN_FIFO_SEMAPHORE not ready\n"); - if (j >= 500) { - printk(KERN_ERR "Giving up beacon config.\n"); - return -ETIMEDOUT; + goto release_sema; + if (time_is_before_eq_jiffies(message_jiffies)) { + message_jiffies = jiffies + HZ / 10; + dev_err(zd_mac_dev(mac), + "CR_BCN_FIFO_SEMAPHORE not ready\n"); + if (time_is_before_eq_jiffies(end_jiffies)) { + dev_err(zd_mac_dev(mac), + "Giving up beacon config.\n"); + r = -ETIMEDOUT; + goto reset_device; } } - msleep(1); + msleep(20); } - r = zd_iowrite32(&mac->chip, CR_BCN_FIFO, full_len - 1); - if (r < 0) - return r; + ioreqs[req_pos].addr = CR_BCN_FIFO; + ioreqs[req_pos].value = full_len - 1; + req_pos++; if (zd_chip_is_zd1211b(&mac->chip)) { - r = zd_iowrite32(&mac->chip, CR_BCN_LENGTH, full_len - 1); - if (r < 0) - return r; + ioreqs[req_pos].addr = CR_BCN_LENGTH; + ioreqs[req_pos].value = full_len - 1; + req_pos++; } for (j = 0 ; j < beacon->len; j++) { - r = zd_iowrite32(&mac->chip, CR_BCN_FIFO, - *((u8 *)(beacon->data + j))); - if (r < 0) - return r; + ioreqs[req_pos].addr = CR_BCN_FIFO; + ioreqs[req_pos].value = *((u8 *)(beacon->data + j)); + req_pos++; } for (j = 0; j < 4; j++) { - r = zd_iowrite32(&mac->chip, CR_BCN_FIFO, 0x0); - if (r < 0) - return r; + ioreqs[req_pos].addr = CR_BCN_FIFO; + ioreqs[req_pos].value = 0x0; + req_pos++; } - r = zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 1); - if (r < 0) - return r; + BUG_ON(req_pos != num_cmds); + + r = zd_iowrite32a_locked(&mac->chip, ioreqs, num_cmds); + +release_sema: + /* + * Try very hard to release device beacon semaphore, as otherwise + * device/driver can be left in unusable state. + */ + end_jiffies = jiffies + HZ / 2; /*~500ms*/ + ret = zd_iowrite32_locked(&mac->chip, 1, CR_BCN_FIFO_SEMAPHORE); + while (ret < 0) { + if (time_is_before_eq_jiffies(end_jiffies)) { + ret = -ETIMEDOUT; + break; + } + + msleep(20); + ret = zd_iowrite32_locked(&mac->chip, 1, CR_BCN_FIFO_SEMAPHORE); + } + + if (ret < 0) + dev_err(zd_mac_dev(mac), "Could not release " + "CR_BCN_FIFO_SEMAPHORE!\n"); + if (r < 0 || ret < 0) { + if (r >= 0) + r = ret; + goto out; + } /* 802.11b/g 2.4G CCK 1Mb * 802.11a, not yet implemented, uses different values (see GPL vendor * driver) */ - return zd_iowrite32(&mac->chip, CR_BCN_PLCP_CFG, 0x00000400 | - (full_len << 19)); + r = zd_iowrite32_locked(&mac->chip, 0x00000400 | (full_len << 19), + CR_BCN_PLCP_CFG); +out: + mutex_unlock(&mac->chip.mutex); + kfree(ioreqs); + return r; + +reset_device: + mutex_unlock(&mac->chip.mutex); + kfree(ioreqs); + + /* semaphore stuck, reset device to avoid fw freeze later */ + dev_warn(zd_mac_dev(mac), "CR_BCN_FIFO_SEMAPHORE stuck, " + "reseting device..."); + usb_queue_reset_device(mac->chip.usb.intf); + + return r; } static int fill_ctrlset(struct zd_mac *mac, @@ -779,6 +928,13 @@ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, mac->ack_pending = 1; mac->ack_signal = stats->signal; + + /* Prevent pending tx-packet on AP-mode */ + if (mac->type == NL80211_IFTYPE_AP) { + skb = __skb_dequeue(q); + zd_mac_tx_status(hw, skb, mac->ack_signal, NULL); + mac->ack_pending = 0; + } } spin_unlock_irqrestore(&q->lock, flags); @@ -882,13 +1038,16 @@ static int zd_op_add_interface(struct ieee80211_hw *hw, case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: mac->type = vif->type; break; default: return -EOPNOTSUPP; } - return zd_write_mac_addr(&mac->chip, vif->addr); + mac->vif = vif; + + return set_mac_and_bssid(mac); } static void zd_op_remove_interface(struct ieee80211_hw *hw, @@ -896,7 +1055,8 @@ static void zd_op_remove_interface(struct ieee80211_hw *hw, { struct zd_mac *mac = zd_hw_mac(hw); mac->type = NL80211_IFTYPE_UNSPECIFIED; - zd_set_beacon_interval(&mac->chip, 0); + mac->vif = NULL; + zd_set_beacon_interval(&mac->chip, 0, 0, NL80211_IFTYPE_UNSPECIFIED); zd_write_mac_addr(&mac->chip, NULL); } @@ -905,49 +1065,67 @@ static int zd_op_config(struct ieee80211_hw *hw, u32 changed) struct zd_mac *mac = zd_hw_mac(hw); struct ieee80211_conf *conf = &hw->conf; + spin_lock_irq(&mac->lock); + mac->channel = conf->channel->hw_value; + spin_unlock_irq(&mac->lock); + return zd_chip_set_channel(&mac->chip, conf->channel->hw_value); } -static void zd_process_intr(struct work_struct *work) +static void zd_beacon_done(struct zd_mac *mac) { - u16 int_status; - struct zd_mac *mac = container_of(work, struct zd_mac, process_intr); + struct sk_buff *skb, *beacon; - int_status = le16_to_cpu(*(__le16 *)(mac->intr_buffer+4)); - if (int_status & INT_CFG_NEXT_BCN) - dev_dbg_f_limit(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n"); - else - dev_dbg_f(zd_mac_dev(mac), "Unsupported interrupt\n"); - - zd_chip_enable_hwint(&mac->chip); -} + if (!test_bit(ZD_DEVICE_RUNNING, &mac->flags)) + return; + if (!mac->vif || mac->vif->type != NL80211_IFTYPE_AP) + return; + /* + * Send out buffered broad- and multicast frames. + */ + while (!ieee80211_queue_stopped(mac->hw, 0)) { + skb = ieee80211_get_buffered_bc(mac->hw, mac->vif); + if (!skb) + break; + zd_op_tx(mac->hw, skb); + } -static void set_multicast_hash_handler(struct work_struct *work) -{ - struct zd_mac *mac = - container_of(work, struct zd_mac, set_multicast_hash_work); - struct zd_mc_hash hash; + /* + * Fetch next beacon so that tim_count is updated. + */ + beacon = ieee80211_beacon_get(mac->hw, mac->vif); + if (beacon) { + zd_mac_config_beacon(mac->hw, beacon); + kfree_skb(beacon); + } spin_lock_irq(&mac->lock); - hash = mac->multicast_hash; + mac->beacon.last_update = jiffies; spin_unlock_irq(&mac->lock); - - zd_chip_set_multicast_hash(&mac->chip, &hash); } -static void set_rx_filter_handler(struct work_struct *work) +static void zd_process_intr(struct work_struct *work) { - struct zd_mac *mac = - container_of(work, struct zd_mac, set_rx_filter_work); - int r; + u16 int_status; + unsigned long flags; + struct zd_mac *mac = container_of(work, struct zd_mac, process_intr); - dev_dbg_f(zd_mac_dev(mac), "\n"); - r = set_rx_filter(mac); - if (r) - dev_err(zd_mac_dev(mac), "set_rx_filter_handler error %d\n", r); + spin_lock_irqsave(&mac->lock, flags); + int_status = le16_to_cpu(*(__le16 *)(mac->intr_buffer + 4)); + spin_unlock_irqrestore(&mac->lock, flags); + + if (int_status & INT_CFG_NEXT_BCN) { + /*dev_dbg_f_limit(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n");*/ + zd_beacon_done(mac); + } else { + dev_dbg_f(zd_mac_dev(mac), "Unsupported interrupt\n"); + } + + zd_chip_enable_hwint(&mac->chip); } + static u64 zd_op_prepare_multicast(struct ieee80211_hw *hw, struct netdev_hw_addr_list *mc_list) { @@ -979,6 +1157,7 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw, }; struct zd_mac *mac = zd_hw_mac(hw); unsigned long flags; + int r; /* Only deal with supported flags */ changed_flags &= SUPPORTED_FIF_FLAGS; @@ -1000,11 +1179,13 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw, mac->multicast_hash = hash; spin_unlock_irqrestore(&mac->lock, flags); - /* XXX: these can be called here now, can sleep now! */ - queue_work(zd_workqueue, &mac->set_multicast_hash_work); + zd_chip_set_multicast_hash(&mac->chip, &hash); - if (changed_flags & FIF_CONTROL) - queue_work(zd_workqueue, &mac->set_rx_filter_work); + if (changed_flags & FIF_CONTROL) { + r = set_rx_filter(mac); + if (r) + dev_err(zd_mac_dev(mac), "set_rx_filter error %d\n", r); + } /* no handling required for FIF_OTHER_BSS as we don't currently * do BSSID filtering */ @@ -1016,20 +1197,9 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw, * time. */ } -static void set_rts_cts_work(struct work_struct *work) +static void set_rts_cts(struct zd_mac *mac, unsigned int short_preamble) { - struct zd_mac *mac = - container_of(work, struct zd_mac, set_rts_cts_work); - unsigned long flags; - unsigned int short_preamble; - mutex_lock(&mac->chip.mutex); - - spin_lock_irqsave(&mac->lock, flags); - mac->updating_rts_rate = 0; - short_preamble = mac->short_preamble; - spin_unlock_irqrestore(&mac->lock, flags); - zd_chip_set_rts_cts_rate_locked(&mac->chip, short_preamble); mutex_unlock(&mac->chip.mutex); } @@ -1040,33 +1210,42 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw, u32 changes) { struct zd_mac *mac = zd_hw_mac(hw); - unsigned long flags; int associated; dev_dbg_f(zd_mac_dev(mac), "changes: %x\n", changes); if (mac->type == NL80211_IFTYPE_MESH_POINT || - mac->type == NL80211_IFTYPE_ADHOC) { + mac->type == NL80211_IFTYPE_ADHOC || + mac->type == NL80211_IFTYPE_AP) { associated = true; if (changes & BSS_CHANGED_BEACON) { struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); if (beacon) { + zd_chip_disable_hwint(&mac->chip); zd_mac_config_beacon(hw, beacon); + zd_chip_enable_hwint(&mac->chip); kfree_skb(beacon); } } if (changes & BSS_CHANGED_BEACON_ENABLED) { - u32 interval; + u16 interval = 0; + u8 period = 0; - if (bss_conf->enable_beacon) - interval = BCN_MODE_IBSS | - bss_conf->beacon_int; - else - interval = 0; + if (bss_conf->enable_beacon) { + period = bss_conf->dtim_period; + interval = bss_conf->beacon_int; + } - zd_set_beacon_interval(&mac->chip, interval); + spin_lock_irq(&mac->lock); + mac->beacon.period = period; + mac->beacon.interval = interval; + mac->beacon.last_update = jiffies; + spin_unlock_irq(&mac->lock); + + zd_set_beacon_interval(&mac->chip, interval, period, + mac->type); } } else associated = is_valid_ether_addr(bss_conf->bssid); @@ -1078,15 +1257,11 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw, /* TODO: do hardware bssid filtering */ if (changes & BSS_CHANGED_ERP_PREAMBLE) { - spin_lock_irqsave(&mac->lock, flags); + spin_lock_irq(&mac->lock); mac->short_preamble = bss_conf->use_short_preamble; - if (!mac->updating_rts_rate) { - mac->updating_rts_rate = 1; - /* FIXME: should disable TX here, until work has - * completed and RTS_CTS reg is updated */ - queue_work(zd_workqueue, &mac->set_rts_cts_work); - } - spin_unlock_irqrestore(&mac->lock, flags); + spin_unlock_irq(&mac->lock); + + set_rts_cts(mac, bss_conf->use_short_preamble); } } @@ -1138,12 +1313,14 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band; hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_SIGNAL_UNSPEC; + IEEE80211_HW_SIGNAL_UNSPEC | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_MESH_POINT) | BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP); hw->max_signal = 100; hw->queues = 1; @@ -1160,15 +1337,82 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) zd_chip_init(&mac->chip, hw, intf); housekeeping_init(mac); - INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler); - INIT_WORK(&mac->set_rts_cts_work, set_rts_cts_work); - INIT_WORK(&mac->set_rx_filter_work, set_rx_filter_handler); + beacon_init(mac); INIT_WORK(&mac->process_intr, zd_process_intr); SET_IEEE80211_DEV(hw, &intf->dev); return hw; } +#define BEACON_WATCHDOG_DELAY round_jiffies_relative(HZ) + +static void beacon_watchdog_handler(struct work_struct *work) +{ + struct zd_mac *mac = + container_of(work, struct zd_mac, beacon.watchdog_work.work); + struct sk_buff *beacon; + unsigned long timeout; + int interval, period; + + if (!test_bit(ZD_DEVICE_RUNNING, &mac->flags)) + goto rearm; + if (mac->type != NL80211_IFTYPE_AP || !mac->vif) + goto rearm; + + spin_lock_irq(&mac->lock); + interval = mac->beacon.interval; + period = mac->beacon.period; + timeout = mac->beacon.last_update + msecs_to_jiffies(interval) + HZ; + spin_unlock_irq(&mac->lock); + + if (interval > 0 && time_is_before_jiffies(timeout)) { + dev_dbg_f(zd_mac_dev(mac), "beacon interrupt stalled, " + "restarting. " + "(interval: %d, dtim: %d)\n", + interval, period); + + zd_chip_disable_hwint(&mac->chip); + + beacon = ieee80211_beacon_get(mac->hw, mac->vif); + if (beacon) { + zd_mac_config_beacon(mac->hw, beacon); + kfree_skb(beacon); + } + + zd_set_beacon_interval(&mac->chip, interval, period, mac->type); + + zd_chip_enable_hwint(&mac->chip); + + spin_lock_irq(&mac->lock); + mac->beacon.last_update = jiffies; + spin_unlock_irq(&mac->lock); + } + +rearm: + queue_delayed_work(zd_workqueue, &mac->beacon.watchdog_work, + BEACON_WATCHDOG_DELAY); +} + +static void beacon_init(struct zd_mac *mac) +{ + INIT_DELAYED_WORK(&mac->beacon.watchdog_work, beacon_watchdog_handler); +} + +static void beacon_enable(struct zd_mac *mac) +{ + dev_dbg_f(zd_mac_dev(mac), "\n"); + + mac->beacon.last_update = jiffies; + queue_delayed_work(zd_workqueue, &mac->beacon.watchdog_work, + BEACON_WATCHDOG_DELAY); +} + +static void beacon_disable(struct zd_mac *mac) +{ + dev_dbg_f(zd_mac_dev(mac), "\n"); + cancel_delayed_work_sync(&mac->beacon.watchdog_work); +} + #define LINK_LED_WORK_DELAY HZ static void link_led_handler(struct work_struct *work) @@ -1179,6 +1423,9 @@ static void link_led_handler(struct work_struct *work) int is_associated; int r; + if (!test_bit(ZD_DEVICE_RUNNING, &mac->flags)) + goto requeue; + spin_lock_irq(&mac->lock); is_associated = mac->associated; spin_unlock_irq(&mac->lock); @@ -1188,6 +1435,7 @@ static void link_led_handler(struct work_struct *work) if (r) dev_dbg_f(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r); +requeue: queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work, LINK_LED_WORK_DELAY); } diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index a6d86b996c79..f8c93c3fe755 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -163,6 +163,17 @@ struct housekeeping { struct delayed_work link_led_work; }; +struct beacon { + struct delayed_work watchdog_work; + unsigned long last_update; + u16 interval; + u8 period; +}; + +enum zd_device_flags { + ZD_DEVICE_RUNNING, +}; + #define ZD_MAC_STATS_BUFFER_SIZE 16 #define ZD_MAC_MAX_ACK_WAITERS 50 @@ -172,17 +183,19 @@ struct zd_mac { spinlock_t lock; spinlock_t intr_lock; struct ieee80211_hw *hw; + struct ieee80211_vif *vif; struct housekeeping housekeeping; - struct work_struct set_multicast_hash_work; + struct beacon beacon; struct work_struct set_rts_cts_work; - struct work_struct set_rx_filter_work; struct work_struct process_intr; struct zd_mc_hash multicast_hash; u8 intr_buffer[USB_MAX_EP_INT_BUFFER]; u8 regdomain; u8 default_regdomain; + u8 channel; int type; int associated; + unsigned long flags; struct sk_buff_head ack_wait_queue; struct ieee80211_channel channels[14]; struct ieee80211_rate rates[12]; @@ -191,9 +204,6 @@ struct zd_mac { /* Short preamble (used for RTS/CTS) */ unsigned int short_preamble:1; - /* flags to indicate update in progress */ - unsigned int updating_rts_rate:1; - /* whether to pass frames with CRC errors to stack */ unsigned int pass_failed_fcs:1; @@ -304,6 +314,10 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length); void zd_mac_tx_failed(struct urb *urb); void zd_mac_tx_to_dev(struct sk_buff *skb, int error); +int zd_op_start(struct ieee80211_hw *hw); +void zd_op_stop(struct ieee80211_hw *hw); +int zd_restore_settings(struct zd_mac *mac); + #ifdef DEBUG void zd_dump_rx_status(const struct rx_status *status); #else diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 06041cb1c422..f6df3665fdb6 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -377,8 +377,10 @@ static inline void handle_regs_int(struct urb *urb) int_num = le16_to_cpu(*(__le16 *)(urb->transfer_buffer+2)); if (int_num == CR_INTERRUPT) { struct zd_mac *mac = zd_hw_mac(zd_usb_to_hw(urb->context)); + spin_lock(&mac->lock); memcpy(&mac->intr_buffer, urb->transfer_buffer, USB_MAX_EP_INT_BUFFER); + spin_unlock(&mac->lock); schedule_work(&mac->process_intr); } else if (intr->read_regs_enabled) { intr->read_regs.length = len = urb->actual_length; @@ -409,8 +411,10 @@ static void int_urb_complete(struct urb *urb) case -ENOENT: case -ECONNRESET: case -EPIPE: - goto kfree; + dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status); + return; default: + dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status); goto resubmit; } @@ -441,12 +445,11 @@ static void int_urb_complete(struct urb *urb) resubmit: r = usb_submit_urb(urb, GFP_ATOMIC); if (r) { - dev_dbg_f(urb_dev(urb), "resubmit urb %p\n", urb); - goto kfree; + dev_dbg_f(urb_dev(urb), "error: resubmit urb %p err code %d\n", + urb, r); + /* TODO: add worker to reset intr->urb */ } return; -kfree: - kfree(urb->transfer_buffer); } static inline int int_urb_interval(struct usb_device *udev) @@ -477,9 +480,8 @@ static inline int usb_int_enabled(struct zd_usb *usb) int zd_usb_enable_int(struct zd_usb *usb) { int r; - struct usb_device *udev; + struct usb_device *udev = zd_usb_to_usbdev(usb); struct zd_usb_interrupt *intr = &usb->intr; - void *transfer_buffer = NULL; struct urb *urb; dev_dbg_f(zd_usb_dev(usb), "\n"); @@ -500,20 +502,21 @@ int zd_usb_enable_int(struct zd_usb *usb) intr->urb = urb; spin_unlock_irq(&intr->lock); - /* TODO: make it a DMA buffer */ r = -ENOMEM; - transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_KERNEL); - if (!transfer_buffer) { + intr->buffer = usb_alloc_coherent(udev, USB_MAX_EP_INT_BUFFER, + GFP_KERNEL, &intr->buffer_dma); + if (!intr->buffer) { dev_dbg_f(zd_usb_dev(usb), "couldn't allocate transfer_buffer\n"); goto error_set_urb_null; } - udev = zd_usb_to_usbdev(usb); usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, EP_INT_IN), - transfer_buffer, USB_MAX_EP_INT_BUFFER, + intr->buffer, USB_MAX_EP_INT_BUFFER, int_urb_complete, usb, intr->interval); + urb->transfer_dma = intr->buffer_dma; + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; dev_dbg_f(zd_usb_dev(usb), "submit urb %p\n", intr->urb); r = usb_submit_urb(urb, GFP_KERNEL); @@ -525,7 +528,8 @@ int zd_usb_enable_int(struct zd_usb *usb) return 0; error: - kfree(transfer_buffer); + usb_free_coherent(udev, USB_MAX_EP_INT_BUFFER, + intr->buffer, intr->buffer_dma); error_set_urb_null: spin_lock_irq(&intr->lock); intr->urb = NULL; @@ -539,8 +543,11 @@ out: void zd_usb_disable_int(struct zd_usb *usb) { unsigned long flags; + struct usb_device *udev = zd_usb_to_usbdev(usb); struct zd_usb_interrupt *intr = &usb->intr; struct urb *urb; + void *buffer; + dma_addr_t buffer_dma; spin_lock_irqsave(&intr->lock, flags); urb = intr->urb; @@ -549,11 +556,18 @@ void zd_usb_disable_int(struct zd_usb *usb) return; } intr->urb = NULL; + buffer = intr->buffer; + buffer_dma = intr->buffer_dma; + intr->buffer = NULL; spin_unlock_irqrestore(&intr->lock, flags); usb_kill_urb(urb); dev_dbg_f(zd_usb_dev(usb), "urb %p killed\n", urb); usb_free_urb(urb); + + if (buffer) + usb_free_coherent(udev, USB_MAX_EP_INT_BUFFER, + buffer, buffer_dma); } static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer, @@ -601,6 +615,7 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer, static void rx_urb_complete(struct urb *urb) { + int r; struct zd_usb *usb; struct zd_usb_rx *rx; const u8 *buffer; @@ -615,6 +630,7 @@ static void rx_urb_complete(struct urb *urb) case -ENOENT: case -ECONNRESET: case -EPIPE: + dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status); return; default: dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status); @@ -626,6 +642,8 @@ static void rx_urb_complete(struct urb *urb) usb = urb->context; rx = &usb->rx; + zd_usb_reset_rx_idle_timer(usb); + if (length%rx->usb_packet_size > rx->usb_packet_size-4) { /* If there is an old first fragment, we don't care. */ dev_dbg_f(urb_dev(urb), "*** first fragment ***\n"); @@ -654,7 +672,9 @@ static void rx_urb_complete(struct urb *urb) } resubmit: - usb_submit_urb(urb, GFP_ATOMIC); + r = usb_submit_urb(urb, GFP_ATOMIC); + if (r) + dev_dbg_f(urb_dev(urb), "urb %p resubmit error %d\n", urb, r); } static struct urb *alloc_rx_urb(struct zd_usb *usb) @@ -690,7 +710,7 @@ static void free_rx_urb(struct urb *urb) usb_free_urb(urb); } -int zd_usb_enable_rx(struct zd_usb *usb) +static int __zd_usb_enable_rx(struct zd_usb *usb) { int i, r; struct zd_usb_rx *rx = &usb->rx; @@ -742,7 +762,21 @@ error: return r; } -void zd_usb_disable_rx(struct zd_usb *usb) +int zd_usb_enable_rx(struct zd_usb *usb) +{ + int r; + struct zd_usb_rx *rx = &usb->rx; + + mutex_lock(&rx->setup_mutex); + r = __zd_usb_enable_rx(usb); + mutex_unlock(&rx->setup_mutex); + + zd_usb_reset_rx_idle_timer(usb); + + return r; +} + +static void __zd_usb_disable_rx(struct zd_usb *usb) { int i; unsigned long flags; @@ -769,6 +803,40 @@ void zd_usb_disable_rx(struct zd_usb *usb) spin_unlock_irqrestore(&rx->lock, flags); } +void zd_usb_disable_rx(struct zd_usb *usb) +{ + struct zd_usb_rx *rx = &usb->rx; + + mutex_lock(&rx->setup_mutex); + __zd_usb_disable_rx(usb); + mutex_unlock(&rx->setup_mutex); + + cancel_delayed_work_sync(&rx->idle_work); +} + +static void zd_usb_reset_rx(struct zd_usb *usb) +{ + bool do_reset; + struct zd_usb_rx *rx = &usb->rx; + unsigned long flags; + + mutex_lock(&rx->setup_mutex); + + spin_lock_irqsave(&rx->lock, flags); + do_reset = rx->urbs != NULL; + spin_unlock_irqrestore(&rx->lock, flags); + + if (do_reset) { + __zd_usb_disable_rx(usb); + __zd_usb_enable_rx(usb); + } + + mutex_unlock(&rx->setup_mutex); + + if (do_reset) + zd_usb_reset_rx_idle_timer(usb); +} + /** * zd_usb_disable_tx - disable transmission * @usb: the zd1211rw-private USB structure @@ -779,19 +847,21 @@ void zd_usb_disable_tx(struct zd_usb *usb) { struct zd_usb_tx *tx = &usb->tx; unsigned long flags; - struct list_head *pos, *n; + + atomic_set(&tx->enabled, 0); + + /* kill all submitted tx-urbs */ + usb_kill_anchored_urbs(&tx->submitted); spin_lock_irqsave(&tx->lock, flags); - list_for_each_safe(pos, n, &tx->free_urb_list) { - list_del(pos); - usb_free_urb(list_entry(pos, struct urb, urb_list)); - } - tx->enabled = 0; + WARN_ON(!skb_queue_empty(&tx->submitted_skbs)); + WARN_ON(tx->submitted_urbs != 0); tx->submitted_urbs = 0; + spin_unlock_irqrestore(&tx->lock, flags); + /* The stopped state is ignored, relying on ieee80211_wake_queues() * in a potentionally following zd_usb_enable_tx(). */ - spin_unlock_irqrestore(&tx->lock, flags); } /** @@ -807,63 +877,13 @@ void zd_usb_enable_tx(struct zd_usb *usb) struct zd_usb_tx *tx = &usb->tx; spin_lock_irqsave(&tx->lock, flags); - tx->enabled = 1; + atomic_set(&tx->enabled, 1); tx->submitted_urbs = 0; ieee80211_wake_queues(zd_usb_to_hw(usb)); tx->stopped = 0; spin_unlock_irqrestore(&tx->lock, flags); } -/** - * alloc_tx_urb - provides an tx URB - * @usb: a &struct zd_usb pointer - * - * Allocates a new URB. If possible takes the urb from the free list in - * usb->tx. - */ -static struct urb *alloc_tx_urb(struct zd_usb *usb) -{ - struct zd_usb_tx *tx = &usb->tx; - unsigned long flags; - struct list_head *entry; - struct urb *urb; - - spin_lock_irqsave(&tx->lock, flags); - if (list_empty(&tx->free_urb_list)) { - urb = usb_alloc_urb(0, GFP_ATOMIC); - goto out; - } - entry = tx->free_urb_list.next; - list_del(entry); - urb = list_entry(entry, struct urb, urb_list); -out: - spin_unlock_irqrestore(&tx->lock, flags); - return urb; -} - -/** - * free_tx_urb - frees a used tx URB - * @usb: a &struct zd_usb pointer - * @urb: URB to be freed - * - * Frees the transmission URB, which means to put it on the free URB - * list. - */ -static void free_tx_urb(struct zd_usb *usb, struct urb *urb) -{ - struct zd_usb_tx *tx = &usb->tx; - unsigned long flags; - - spin_lock_irqsave(&tx->lock, flags); - if (!tx->enabled) { - usb_free_urb(urb); - goto out; - } - list_add(&urb->urb_list, &tx->free_urb_list); -out: - spin_unlock_irqrestore(&tx->lock, flags); -} - static void tx_dec_submitted_urbs(struct zd_usb *usb) { struct zd_usb_tx *tx = &usb->tx; @@ -905,6 +925,16 @@ static void tx_urb_complete(struct urb *urb) struct sk_buff *skb; struct ieee80211_tx_info *info; struct zd_usb *usb; + struct zd_usb_tx *tx; + + skb = (struct sk_buff *)urb->context; + info = IEEE80211_SKB_CB(skb); + /* + * grab 'usb' pointer before handing off the skb (since + * it might be freed by zd_mac_tx_to_dev or mac80211) + */ + usb = &zd_hw_mac(info->rate_driver_data[0])->chip.usb; + tx = &usb->tx; switch (urb->status) { case 0: @@ -922,20 +952,16 @@ static void tx_urb_complete(struct urb *urb) goto resubmit; } free_urb: - skb = (struct sk_buff *)urb->context; - /* - * grab 'usb' pointer before handing off the skb (since - * it might be freed by zd_mac_tx_to_dev or mac80211) - */ - info = IEEE80211_SKB_CB(skb); - usb = &zd_hw_mac(info->rate_driver_data[0])->chip.usb; + skb_unlink(skb, &usb->tx.submitted_skbs); zd_mac_tx_to_dev(skb, urb->status); - free_tx_urb(usb, urb); + usb_free_urb(urb); tx_dec_submitted_urbs(usb); return; resubmit: + usb_anchor_urb(urb, &tx->submitted); r = usb_submit_urb(urb, GFP_ATOMIC); if (r) { + usb_unanchor_urb(urb); dev_dbg_f(urb_dev(urb), "error resubmit urb %p %d\n", urb, r); goto free_urb; } @@ -956,10 +982,17 @@ resubmit: int zd_usb_tx(struct zd_usb *usb, struct sk_buff *skb) { int r; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct usb_device *udev = zd_usb_to_usbdev(usb); struct urb *urb; + struct zd_usb_tx *tx = &usb->tx; - urb = alloc_tx_urb(usb); + if (!atomic_read(&tx->enabled)) { + r = -ENOENT; + goto out; + } + + urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { r = -ENOMEM; goto out; @@ -968,17 +1001,118 @@ int zd_usb_tx(struct zd_usb *usb, struct sk_buff *skb) usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT), skb->data, skb->len, tx_urb_complete, skb); + info->rate_driver_data[1] = (void *)jiffies; + skb_queue_tail(&tx->submitted_skbs, skb); + usb_anchor_urb(urb, &tx->submitted); + r = usb_submit_urb(urb, GFP_ATOMIC); - if (r) + if (r) { + dev_dbg_f(zd_usb_dev(usb), "error submit urb %p %d\n", urb, r); + usb_unanchor_urb(urb); + skb_unlink(skb, &tx->submitted_skbs); goto error; + } tx_inc_submitted_urbs(usb); return 0; error: - free_tx_urb(usb, urb); + usb_free_urb(urb); out: return r; } +static bool zd_tx_timeout(struct zd_usb *usb) +{ + struct zd_usb_tx *tx = &usb->tx; + struct sk_buff_head *q = &tx->submitted_skbs; + struct sk_buff *skb, *skbnext; + struct ieee80211_tx_info *info; + unsigned long flags, trans_start; + bool have_timedout = false; + + spin_lock_irqsave(&q->lock, flags); + skb_queue_walk_safe(q, skb, skbnext) { + info = IEEE80211_SKB_CB(skb); + trans_start = (unsigned long)info->rate_driver_data[1]; + + if (time_is_before_jiffies(trans_start + ZD_TX_TIMEOUT)) { + have_timedout = true; + break; + } + } + spin_unlock_irqrestore(&q->lock, flags); + + return have_timedout; +} + +static void zd_tx_watchdog_handler(struct work_struct *work) +{ + struct zd_usb *usb = + container_of(work, struct zd_usb, tx.watchdog_work.work); + struct zd_usb_tx *tx = &usb->tx; + + if (!atomic_read(&tx->enabled) || !tx->watchdog_enabled) + goto out; + if (!zd_tx_timeout(usb)) + goto out; + + /* TX halted, try reset */ + dev_warn(zd_usb_dev(usb), "TX-stall detected, reseting device..."); + + usb_queue_reset_device(usb->intf); + + /* reset will stop this worker, don't rearm */ + return; +out: + queue_delayed_work(zd_workqueue, &tx->watchdog_work, + ZD_TX_WATCHDOG_INTERVAL); +} + +void zd_tx_watchdog_enable(struct zd_usb *usb) +{ + struct zd_usb_tx *tx = &usb->tx; + + if (!tx->watchdog_enabled) { + dev_dbg_f(zd_usb_dev(usb), "\n"); + queue_delayed_work(zd_workqueue, &tx->watchdog_work, + ZD_TX_WATCHDOG_INTERVAL); + tx->watchdog_enabled = 1; + } +} + +void zd_tx_watchdog_disable(struct zd_usb *usb) +{ + struct zd_usb_tx *tx = &usb->tx; + + if (tx->watchdog_enabled) { + dev_dbg_f(zd_usb_dev(usb), "\n"); + tx->watchdog_enabled = 0; + cancel_delayed_work_sync(&tx->watchdog_work); + } +} + +static void zd_rx_idle_timer_handler(struct work_struct *work) +{ + struct zd_usb *usb = + container_of(work, struct zd_usb, rx.idle_work.work); + struct zd_mac *mac = zd_usb_to_mac(usb); + + if (!test_bit(ZD_DEVICE_RUNNING, &mac->flags)) + return; + + dev_dbg_f(zd_usb_dev(usb), "\n"); + + /* 30 seconds since last rx, reset rx */ + zd_usb_reset_rx(usb); +} + +void zd_usb_reset_rx_idle_timer(struct zd_usb *usb) +{ + struct zd_usb_rx *rx = &usb->rx; + + cancel_delayed_work(&rx->idle_work); + queue_delayed_work(zd_workqueue, &rx->idle_work, ZD_RX_IDLE_INTERVAL); +} + static inline void init_usb_interrupt(struct zd_usb *usb) { struct zd_usb_interrupt *intr = &usb->intr; @@ -993,22 +1127,27 @@ static inline void init_usb_rx(struct zd_usb *usb) { struct zd_usb_rx *rx = &usb->rx; spin_lock_init(&rx->lock); + mutex_init(&rx->setup_mutex); if (interface_to_usbdev(usb->intf)->speed == USB_SPEED_HIGH) { rx->usb_packet_size = 512; } else { rx->usb_packet_size = 64; } ZD_ASSERT(rx->fragment_length == 0); + INIT_DELAYED_WORK(&rx->idle_work, zd_rx_idle_timer_handler); } static inline void init_usb_tx(struct zd_usb *usb) { struct zd_usb_tx *tx = &usb->tx; spin_lock_init(&tx->lock); - tx->enabled = 0; + atomic_set(&tx->enabled, 0); tx->stopped = 0; - INIT_LIST_HEAD(&tx->free_urb_list); + skb_queue_head_init(&tx->submitted_skbs); + init_usb_anchor(&tx->submitted); tx->submitted_urbs = 0; + tx->watchdog_enabled = 0; + INIT_DELAYED_WORK(&tx->watchdog_work, zd_tx_watchdog_handler); } void zd_usb_init(struct zd_usb *usb, struct ieee80211_hw *hw, @@ -1240,6 +1379,7 @@ static void disconnect(struct usb_interface *intf) ieee80211_unregister_hw(hw); /* Just in case something has gone wrong! */ + zd_usb_disable_tx(usb); zd_usb_disable_rx(usb); zd_usb_disable_int(usb); @@ -1255,11 +1395,92 @@ static void disconnect(struct usb_interface *intf) dev_dbg(&intf->dev, "disconnected\n"); } +static void zd_usb_resume(struct zd_usb *usb) +{ + struct zd_mac *mac = zd_usb_to_mac(usb); + int r; + + dev_dbg_f(zd_usb_dev(usb), "\n"); + + r = zd_op_start(zd_usb_to_hw(usb)); + if (r < 0) { + dev_warn(zd_usb_dev(usb), "Device resume failed " + "with error code %d. Retrying...\n", r); + if (usb->was_running) + set_bit(ZD_DEVICE_RUNNING, &mac->flags); + usb_queue_reset_device(usb->intf); + return; + } + + if (mac->type != NL80211_IFTYPE_UNSPECIFIED) { + r = zd_restore_settings(mac); + if (r < 0) { + dev_dbg(zd_usb_dev(usb), + "failed to restore settings, %d\n", r); + return; + } + } +} + +static void zd_usb_stop(struct zd_usb *usb) +{ + dev_dbg_f(zd_usb_dev(usb), "\n"); + + zd_op_stop(zd_usb_to_hw(usb)); + + zd_usb_disable_tx(usb); + zd_usb_disable_rx(usb); + zd_usb_disable_int(usb); + + usb->initialized = 0; +} + +static int pre_reset(struct usb_interface *intf) +{ + struct ieee80211_hw *hw = usb_get_intfdata(intf); + struct zd_mac *mac; + struct zd_usb *usb; + + if (!hw || intf->condition != USB_INTERFACE_BOUND) + return 0; + + mac = zd_hw_mac(hw); + usb = &mac->chip.usb; + + usb->was_running = test_bit(ZD_DEVICE_RUNNING, &mac->flags); + + zd_usb_stop(usb); + + mutex_lock(&mac->chip.mutex); + return 0; +} + +static int post_reset(struct usb_interface *intf) +{ + struct ieee80211_hw *hw = usb_get_intfdata(intf); + struct zd_mac *mac; + struct zd_usb *usb; + + if (!hw || intf->condition != USB_INTERFACE_BOUND) + return 0; + + mac = zd_hw_mac(hw); + usb = &mac->chip.usb; + + mutex_unlock(&mac->chip.mutex); + + if (usb->was_running) + zd_usb_resume(usb); + return 0; +} + static struct usb_driver driver = { .name = KBUILD_MODNAME, .id_table = usb_ids, .probe = probe, .disconnect = disconnect, + .pre_reset = pre_reset, + .post_reset = post_reset, }; struct workqueue_struct *zd_workqueue; @@ -1393,15 +1614,20 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values, return -EWOULDBLOCK; } if (!usb_int_enabled(usb)) { - dev_dbg_f(zd_usb_dev(usb), + dev_dbg_f(zd_usb_dev(usb), "error: usb interrupt not enabled\n"); return -EWOULDBLOCK; } + ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex)); + BUILD_BUG_ON(sizeof(struct usb_req_read_regs) + USB_MAX_IOREAD16_COUNT * + sizeof(__le16) > sizeof(usb->req_buf)); + BUG_ON(sizeof(struct usb_req_read_regs) + count * sizeof(__le16) > + sizeof(usb->req_buf)); + req_len = sizeof(struct usb_req_read_regs) + count * sizeof(__le16); - req = kmalloc(req_len, GFP_KERNEL); - if (!req) - return -ENOMEM; + req = (void *)usb->req_buf; + req->id = cpu_to_le16(USB_REQ_READ_REGS); for (i = 0; i < count; i++) req->addr[i] = cpu_to_le16((u16)addresses[i]); @@ -1409,7 +1635,7 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values, udev = zd_usb_to_usbdev(usb); prepare_read_regs_int(usb); r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT), - req, req_len, &actual_req_len, 1000 /* ms */); + req, req_len, &actual_req_len, 50 /* ms */); if (r) { dev_dbg_f(zd_usb_dev(usb), "error in usb_bulk_msg(). Error number %d\n", r); @@ -1424,7 +1650,7 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values, } timeout = wait_for_completion_timeout(&usb->intr.read_regs.completion, - msecs_to_jiffies(1000)); + msecs_to_jiffies(50)); if (!timeout) { disable_read_regs_int(usb); dev_dbg_f(zd_usb_dev(usb), "read timed out\n"); @@ -1434,7 +1660,6 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values, r = get_results(usb, values, req, count); error: - kfree(req); return r; } @@ -1460,11 +1685,17 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, return -EWOULDBLOCK; } + ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex)); + BUILD_BUG_ON(sizeof(struct usb_req_write_regs) + + USB_MAX_IOWRITE16_COUNT * sizeof(struct reg_data) > + sizeof(usb->req_buf)); + BUG_ON(sizeof(struct usb_req_write_regs) + + count * sizeof(struct reg_data) > + sizeof(usb->req_buf)); + req_len = sizeof(struct usb_req_write_regs) + count * sizeof(struct reg_data); - req = kmalloc(req_len, GFP_KERNEL); - if (!req) - return -ENOMEM; + req = (void *)usb->req_buf; req->id = cpu_to_le16(USB_REQ_WRITE_REGS); for (i = 0; i < count; i++) { @@ -1475,7 +1706,7 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, udev = zd_usb_to_usbdev(usb); r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT), - req, req_len, &actual_req_len, 1000 /* ms */); + req, req_len, &actual_req_len, 50 /* ms */); if (r) { dev_dbg_f(zd_usb_dev(usb), "error in usb_bulk_msg(). Error number %d\n", r); @@ -1492,7 +1723,6 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, /* FALL-THROUGH with r == 0 */ error: - kfree(req); return r; } @@ -1537,14 +1767,19 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits) if (r) { dev_dbg_f(zd_usb_dev(usb), "error %d: Couldn't read CR203\n", r); - goto out; + return r; } bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA); + ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex)); + BUILD_BUG_ON(sizeof(struct usb_req_rfwrite) + + USB_MAX_RFWRITE_BIT_COUNT * sizeof(__le16) > + sizeof(usb->req_buf)); + BUG_ON(sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16) > + sizeof(usb->req_buf)); + req_len = sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16); - req = kmalloc(req_len, GFP_KERNEL); - if (!req) - return -ENOMEM; + req = (void *)usb->req_buf; req->id = cpu_to_le16(USB_REQ_WRITE_RF); /* 1: 3683a, but not used in ZYDAS driver */ @@ -1560,7 +1795,7 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits) udev = zd_usb_to_usbdev(usb); r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT), - req, req_len, &actual_req_len, 1000 /* ms */); + req, req_len, &actual_req_len, 50 /* ms */); if (r) { dev_dbg_f(zd_usb_dev(usb), "error in usb_bulk_msg(). Error number %d\n", r); @@ -1576,6 +1811,5 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits) /* FALL-THROUGH with r == 0 */ out: - kfree(req); return r; } diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h index 1b1655cb7cb4..2d688f48a34c 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.h +++ b/drivers/net/wireless/zd1211rw/zd_usb.h @@ -32,6 +32,10 @@ #define ZD_USB_TX_HIGH 5 #define ZD_USB_TX_LOW 2 +#define ZD_TX_TIMEOUT (HZ * 5) +#define ZD_TX_WATCHDOG_INTERVAL round_jiffies_relative(HZ) +#define ZD_RX_IDLE_INTERVAL round_jiffies_relative(30 * HZ) + enum devicetype { DEVICE_ZD1211 = 0, DEVICE_ZD1211B = 1, @@ -162,6 +166,8 @@ struct zd_usb_interrupt { struct read_regs_int read_regs; spinlock_t lock; struct urb *urb; + void *buffer; + dma_addr_t buffer_dma; int interval; u8 read_regs_enabled:1; }; @@ -175,7 +181,9 @@ static inline struct usb_int_regs *get_read_regs(struct zd_usb_interrupt *intr) struct zd_usb_rx { spinlock_t lock; - u8 fragment[2*USB_MAX_RX_SIZE]; + struct mutex setup_mutex; + struct delayed_work idle_work; + u8 fragment[2 * USB_MAX_RX_SIZE]; unsigned int fragment_length; unsigned int usb_packet_size; struct urb **urbs; @@ -184,19 +192,21 @@ struct zd_usb_rx { /** * struct zd_usb_tx - structure used for transmitting frames + * @enabled: atomic enabled flag, indicates whether tx is enabled * @lock: lock for transmission - * @free_urb_list: list of free URBs, contains all the URBs, which can be used + * @submitted: anchor for URBs sent to device * @submitted_urbs: atomic integer that counts the URBs having sent to the * device, which haven't been completed - * @enabled: enabled flag, indicates whether tx is enabled * @stopped: indicates whether higher level tx queues are stopped */ struct zd_usb_tx { + atomic_t enabled; spinlock_t lock; - struct list_head free_urb_list; + struct delayed_work watchdog_work; + struct sk_buff_head submitted_skbs; + struct usb_anchor submitted; int submitted_urbs; - int enabled; - int stopped; + u8 stopped:1, watchdog_enabled:1; }; /* Contains the usb parts. The structure doesn't require a lock because intf @@ -207,7 +217,8 @@ struct zd_usb { struct zd_usb_rx rx; struct zd_usb_tx tx; struct usb_interface *intf; - u8 is_zd1211b:1, initialized:1; + u8 req_buf[64]; /* zd_usb_iowrite16v needs 62 bytes */ + u8 is_zd1211b:1, initialized:1, was_running:1; }; #define zd_usb_dev(usb) (&usb->intf->dev) @@ -234,12 +245,17 @@ void zd_usb_clear(struct zd_usb *usb); int zd_usb_scnprint_id(struct zd_usb *usb, char *buffer, size_t size); +void zd_tx_watchdog_enable(struct zd_usb *usb); +void zd_tx_watchdog_disable(struct zd_usb *usb); + int zd_usb_enable_int(struct zd_usb *usb); void zd_usb_disable_int(struct zd_usb *usb); int zd_usb_enable_rx(struct zd_usb *usb); void zd_usb_disable_rx(struct zd_usb *usb); +void zd_usb_reset_rx_idle_timer(struct zd_usb *usb); + void zd_usb_enable_tx(struct zd_usb *usb); void zd_usb_disable_tx(struct zd_usb *usb); diff --git a/drivers/parport/share.c b/drivers/parport/share.c index a2d9d1e59260..a848e02e6be3 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -678,7 +678,7 @@ void parport_unregister_device(struct pardevice *dev) /* Make sure we haven't left any pointers around in the wait * list. */ - spin_lock (&port->waitlist_lock); + spin_lock_irq(&port->waitlist_lock); if (dev->waitprev || dev->waitnext || port->waithead == dev) { if (dev->waitprev) dev->waitprev->waitnext = dev->waitnext; @@ -689,7 +689,7 @@ void parport_unregister_device(struct pardevice *dev) else port->waittail = dev->waitprev; } - spin_unlock (&port->waitlist_lock); + spin_unlock_irq(&port->waitlist_lock); kfree(dev->state); kfree(dev); diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 8ecaac983923..ea25e5bfcf23 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -23,6 +23,7 @@ #include <linux/mm.h> #include <linux/fs.h> #include <linux/capability.h> +#include <linux/security.h> #include <linux/pci-aspm.h> #include <linux/slab.h> #include "pci.h" @@ -368,7 +369,7 @@ pci_read_config(struct file *filp, struct kobject *kobj, u8 *data = (u8*) buf; /* Several chips lock up trying to read undefined config space */ - if (cap_raised(filp->f_cred->cap_effective, CAP_SYS_ADMIN)) { + if (security_capable(filp->f_cred, CAP_SYS_ADMIN) == 0) { size = dev->cfg_size; } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { size = 128; diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 1752ef006d26..a91d510a798b 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -26,7 +26,6 @@ #include <linux/sfi.h> #include <asm/mrst.h> #include <asm/intel_scu_ipc.h> -#include <asm/mrst.h> /* IPC defines the following message types */ #define IPCMSG_WATCHDOG_TIMER 0xF8 /* Set Kernel Watchdog Threshold */ @@ -161,7 +160,7 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) { int i, nc, bytes, d; u32 offset = 0; - u32 err = 0; + int err; u8 cbuf[IPC_WWBUF_SIZE] = { }; u32 *wbuf = (u32 *)&cbuf; @@ -404,7 +403,7 @@ EXPORT_SYMBOL(intel_scu_ipc_update_register); */ int intel_scu_ipc_simple_command(int cmd, int sub) { - u32 err = 0; + int err; mutex_lock(&ipclock); if (ipcdev.pdev == NULL) { @@ -434,8 +433,7 @@ EXPORT_SYMBOL(intel_scu_ipc_simple_command); int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen, u32 *out, int outlen) { - u32 err = 0; - int i = 0; + int i, err; mutex_lock(&ipclock); if (ipcdev.pdev == NULL) { diff --git a/drivers/platform/x86/intel_scu_ipcutil.c b/drivers/platform/x86/intel_scu_ipcutil.c index ba3231d0819e..b93a03259c16 100644 --- a/drivers/platform/x86/intel_scu_ipcutil.c +++ b/drivers/platform/x86/intel_scu_ipcutil.c @@ -128,6 +128,6 @@ static void __exit ipc_module_exit(void) module_init(ipc_module_init); module_exit(ipc_module_exit); -MODULE_LICENSE("GPL V2"); +MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Utility driver for intel scu ipc"); MODULE_AUTHOR("Sreedhara <sreedhara.ds@intel.com>"); diff --git a/drivers/pps/clients/pps-ktimer.c b/drivers/pps/clients/pps-ktimer.c index 2728469d3884..82583b0ff82d 100644 --- a/drivers/pps/clients/pps-ktimer.c +++ b/drivers/pps/clients/pps-ktimer.c @@ -46,8 +46,6 @@ static void pps_ktimer_event(unsigned long ptr) /* First of all we get the time stamp... */ pps_get_ts(&ts); - dev_info(pps->dev, "PPS event at %lu\n", jiffies); - pps_event(pps, &ts, PPS_CAPTUREASSERT, NULL); mod_timer(&ktimer, jiffies + HZ); diff --git a/drivers/pps/clients/pps_parport.c b/drivers/pps/clients/pps_parport.c index 32221efd9ca9..c571d6dd8f61 100644 --- a/drivers/pps/clients/pps_parport.c +++ b/drivers/pps/clients/pps_parport.c @@ -163,7 +163,7 @@ static void parport_attach(struct parport *port) } device->pardev = parport_register_device(port, KBUILD_MODNAME, - NULL, NULL, parport_irq, 0, device); + NULL, NULL, parport_irq, PARPORT_FLAG_EXCL, device); if (!device->pardev) { pr_err("couldn't register with %s\n", port->name); goto err_free; diff --git a/drivers/pps/generators/pps_gen_parport.c b/drivers/pps/generators/pps_gen_parport.c index 5c32f8dacf56..b93af3ebb5ba 100644 --- a/drivers/pps/generators/pps_gen_parport.c +++ b/drivers/pps/generators/pps_gen_parport.c @@ -198,7 +198,7 @@ static void parport_attach(struct parport *port) } device.pardev = parport_register_device(port, KBUILD_MODNAME, - NULL, NULL, NULL, 0, &device); + NULL, NULL, NULL, PARPORT_FLAG_EXCL, &device); if (!device.pardev) { pr_err("couldn't register with %s\n", port->name); return; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index cdd97192dc69..4941cade319f 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -97,6 +97,18 @@ config RTC_INTF_DEV If unsure, say Y. +config RTC_INTF_DEV_UIE_EMUL + bool "RTC UIE emulation on dev interface" + depends on RTC_INTF_DEV + help + Provides an emulation for RTC_UIE if the underlying rtc chip + driver does not expose RTC_UIE ioctls. Those requests generate + once-per-second update interrupts, used for synchronization. + + The emulation code will read the time from the hardware + clock several times per second, please enable this option + only if you know that you really need it. + config RTC_DRV_TEST tristate "Test driver/device" help diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 9583cbcc6b79..c404b61386bf 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -143,6 +143,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, rtc->id = id; rtc->ops = ops; rtc->owner = owner; + rtc->irq_freq = 1; rtc->max_user_freq = 64; rtc->dev.parent = dev; rtc->dev.class = rtc_class; diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 925006d33109..cb2f0728fd70 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -209,9 +209,8 @@ int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) } if (err) - return err; - - if (!rtc->ops) + /* nothing */; + else if (!rtc->ops) err = -ENODEV; else if (!rtc->ops->alarm_irq_enable) err = -EINVAL; @@ -229,6 +228,12 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) if (err) return err; +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL + if (enabled == 0 && rtc->uie_irq_active) { + mutex_unlock(&rtc->ops_lock); + return rtc_dev_update_irq_enable_emul(rtc, 0); + } +#endif /* make sure we're changing state */ if (rtc->uie_rtctimer.enabled == enabled) goto out; @@ -248,6 +253,16 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) out: mutex_unlock(&rtc->ops_lock); +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL + /* + * Enable emulation if the driver did not provide + * the update_irq_enable function pointer or if returned + * -EINVAL to signal that it has been configured without + * interrupts or that are not available at the moment. + */ + if (err == -EINVAL) + err = rtc_dev_update_irq_enable_emul(rtc, enabled); +#endif return err; } @@ -263,7 +278,7 @@ EXPORT_SYMBOL_GPL(rtc_update_irq_enable); * * Triggers the registered irq_task function callback. */ -static void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) +void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) { unsigned long flags; @@ -464,6 +479,9 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) int err = 0; unsigned long flags; + if (freq <= 0) + return -EINVAL; + spin_lock_irqsave(&rtc->irq_task_lock, flags); if (rtc->irq_task != NULL && task == NULL) err = -EBUSY; diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c index b2752b6e7a2f..e725d51e773d 100644 --- a/drivers/rtc/rtc-at32ap700x.c +++ b/drivers/rtc/rtc-at32ap700x.c @@ -134,36 +134,29 @@ static int at32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; } -static int at32_rtc_ioctl(struct device *dev, unsigned int cmd, - unsigned long arg) +static int at32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct rtc_at32ap700x *rtc = dev_get_drvdata(dev); int ret = 0; spin_lock_irq(&rtc->lock); - switch (cmd) { - case RTC_AIE_ON: + if(enabled) { if (rtc_readl(rtc, VAL) > rtc->alarm_time) { ret = -EINVAL; - break; + goto out; } rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL) | RTC_BIT(CTRL_TOPEN)); rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI)); rtc_writel(rtc, IER, RTC_BIT(IER_TOPI)); - break; - case RTC_AIE_OFF: + } else { rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL) & ~RTC_BIT(CTRL_TOPEN)); rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI)); rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI)); - break; - default: - ret = -ENOIOCTLCMD; - break; } - +out: spin_unlock_irq(&rtc->lock); return ret; @@ -195,11 +188,11 @@ static irqreturn_t at32_rtc_interrupt(int irq, void *dev_id) } static struct rtc_class_ops at32_rtc_ops = { - .ioctl = at32_rtc_ioctl, .read_time = at32_rtc_readtime, .set_time = at32_rtc_settime, .read_alarm = at32_rtc_readalarm, .set_alarm = at32_rtc_setalarm, + .alarm_irq_enable = at32_rtc_alarm_irq_enable, }; static int __init at32_rtc_probe(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index bc8bbca9a2e2..26d1cf5d19ae 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -195,13 +195,6 @@ static int at91_rtc_ioctl(struct device *dev, unsigned int cmd, /* important: scrub old status before enabling IRQs */ switch (cmd) { - case RTC_AIE_OFF: /* alarm off */ - at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM); - break; - case RTC_AIE_ON: /* alarm on */ - at91_sys_write(AT91_RTC_SCCR, AT91_RTC_ALARM); - at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM); - break; case RTC_UIE_OFF: /* update off */ at91_sys_write(AT91_RTC_IDR, AT91_RTC_SECEV); break; @@ -217,6 +210,18 @@ static int at91_rtc_ioctl(struct device *dev, unsigned int cmd, return ret; } +static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + pr_debug("%s(): cmd=%08x\n", __func__, enabled); + + if (enabled) { + at91_sys_write(AT91_RTC_SCCR, AT91_RTC_ALARM); + at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM); + } else + at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM); + + return 0; +} /* * Provide additional RTC information in /proc/driver/rtc */ @@ -270,6 +275,7 @@ static const struct rtc_class_ops at91_rtc_ops = { .read_alarm = at91_rtc_readalarm, .set_alarm = at91_rtc_setalarm, .proc = at91_rtc_proc, + .alarm_irq_enable = at91_rtc_alarm_irq_enable, }; /* diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index f677e0710ca1..c36749e4c926 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -229,12 +229,6 @@ static int at91_rtc_ioctl(struct device *dev, unsigned int cmd, dev_dbg(dev, "ioctl: cmd=%08x, arg=%08lx, mr %08x\n", cmd, arg, mr); switch (cmd) { - case RTC_AIE_OFF: /* alarm off */ - rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN); - break; - case RTC_AIE_ON: /* alarm on */ - rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN); - break; case RTC_UIE_OFF: /* update off */ rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN); break; @@ -249,6 +243,19 @@ static int at91_rtc_ioctl(struct device *dev, unsigned int cmd, return ret; } +static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct sam9_rtc *rtc = dev_get_drvdata(dev); + u32 mr = rtt_readl(rtc, MR); + + dev_dbg(dev, "alarm_irq_enable: enabled=%08x, mr %08x\n", enabled, mr); + if (enabled) + rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN); + else + rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN); + return 0; +} + /* * Provide additional RTC information in /proc/driver/rtc */ @@ -302,6 +309,7 @@ static const struct rtc_class_ops at91_rtc_ops = { .read_alarm = at91_rtc_readalarm, .set_alarm = at91_rtc_setalarm, .proc = at91_rtc_proc, + .alarm_irq_enabled = at91_rtc_alarm_irq_enable, }; /* diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index b4b6087f2234..17971d93354d 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -259,15 +259,6 @@ static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long ar bfin_rtc_int_clear(~RTC_ISTAT_SEC); break; - case RTC_AIE_ON: - dev_dbg_stamp(dev); - bfin_rtc_int_set_alarm(rtc); - break; - case RTC_AIE_OFF: - dev_dbg_stamp(dev); - bfin_rtc_int_clear(~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)); - break; - default: dev_dbg_stamp(dev); ret = -ENOIOCTLCMD; @@ -276,6 +267,17 @@ static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long ar return ret; } +static int bfin_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct bfin_rtc *rtc = dev_get_drvdata(dev); + + dev_dbg_stamp(dev); + if (enabled) + bfin_rtc_int_set_alarm(rtc); + else + bfin_rtc_int_clear(~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)); +} + static int bfin_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct bfin_rtc *rtc = dev_get_drvdata(dev); @@ -362,6 +364,7 @@ static struct rtc_class_ops bfin_rtc_ops = { .read_alarm = bfin_rtc_read_alarm, .set_alarm = bfin_rtc_set_alarm, .proc = bfin_rtc_proc, + .alarm_irq_enable = bfin_rtc_alarm_irq_enable, }; static int __devinit bfin_rtc_probe(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 212b16edafc0..d0e06edb14c5 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -46,6 +46,105 @@ static int rtc_dev_open(struct inode *inode, struct file *file) return err; } +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL +/* + * Routine to poll RTC seconds field for change as often as possible, + * after first RTC_UIE use timer to reduce polling + */ +static void rtc_uie_task(struct work_struct *work) +{ + struct rtc_device *rtc = + container_of(work, struct rtc_device, uie_task); + struct rtc_time tm; + int num = 0; + int err; + + err = rtc_read_time(rtc, &tm); + + spin_lock_irq(&rtc->irq_lock); + if (rtc->stop_uie_polling || err) { + rtc->uie_task_active = 0; + } else if (rtc->oldsecs != tm.tm_sec) { + num = (tm.tm_sec + 60 - rtc->oldsecs) % 60; + rtc->oldsecs = tm.tm_sec; + rtc->uie_timer.expires = jiffies + HZ - (HZ/10); + rtc->uie_timer_active = 1; + rtc->uie_task_active = 0; + add_timer(&rtc->uie_timer); + } else if (schedule_work(&rtc->uie_task) == 0) { + rtc->uie_task_active = 0; + } + spin_unlock_irq(&rtc->irq_lock); + if (num) + rtc_handle_legacy_irq(rtc, num, RTC_UF); +} +static void rtc_uie_timer(unsigned long data) +{ + struct rtc_device *rtc = (struct rtc_device *)data; + unsigned long flags; + + spin_lock_irqsave(&rtc->irq_lock, flags); + rtc->uie_timer_active = 0; + rtc->uie_task_active = 1; + if ((schedule_work(&rtc->uie_task) == 0)) + rtc->uie_task_active = 0; + spin_unlock_irqrestore(&rtc->irq_lock, flags); +} + +static int clear_uie(struct rtc_device *rtc) +{ + spin_lock_irq(&rtc->irq_lock); + if (rtc->uie_irq_active) { + rtc->stop_uie_polling = 1; + if (rtc->uie_timer_active) { + spin_unlock_irq(&rtc->irq_lock); + del_timer_sync(&rtc->uie_timer); + spin_lock_irq(&rtc->irq_lock); + rtc->uie_timer_active = 0; + } + if (rtc->uie_task_active) { + spin_unlock_irq(&rtc->irq_lock); + flush_scheduled_work(); + spin_lock_irq(&rtc->irq_lock); + } + rtc->uie_irq_active = 0; + } + spin_unlock_irq(&rtc->irq_lock); + return 0; +} + +static int set_uie(struct rtc_device *rtc) +{ + struct rtc_time tm; + int err; + + err = rtc_read_time(rtc, &tm); + if (err) + return err; + spin_lock_irq(&rtc->irq_lock); + if (!rtc->uie_irq_active) { + rtc->uie_irq_active = 1; + rtc->stop_uie_polling = 0; + rtc->oldsecs = tm.tm_sec; + rtc->uie_task_active = 1; + if (schedule_work(&rtc->uie_task) == 0) + rtc->uie_task_active = 0; + } + rtc->irq_data = 0; + spin_unlock_irq(&rtc->irq_lock); + return 0; +} + +int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, unsigned int enabled) +{ + if (enabled) + return set_uie(rtc); + else + return clear_uie(rtc); +} +EXPORT_SYMBOL(rtc_dev_update_irq_enable_emul); + +#endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */ static ssize_t rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) @@ -154,19 +253,7 @@ static long rtc_dev_ioctl(struct file *file, if (err) goto done; - /* try the driver's ioctl interface */ - if (ops->ioctl) { - err = ops->ioctl(rtc->dev.parent, cmd, arg); - if (err != -ENOIOCTLCMD) { - mutex_unlock(&rtc->ops_lock); - return err; - } - } - - /* if the driver does not provide the ioctl interface - * or if that particular ioctl was not implemented - * (-ENOIOCTLCMD), we will try to emulate here. - * + /* * Drivers *SHOULD NOT* provide ioctl implementations * for these requests. Instead, provide methods to * support the following code, so that the RTC's main @@ -329,7 +416,12 @@ static long rtc_dev_ioctl(struct file *file, return err; default: - err = -ENOTTY; + /* Finally try the driver's ioctl interface */ + if (ops->ioctl) { + err = ops->ioctl(rtc->dev.parent, cmd, arg); + if (err == -ENOIOCTLCMD) + err = -ENOTTY; + } break; } @@ -394,6 +486,11 @@ void rtc_dev_prepare(struct rtc_device *rtc) rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id); +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL + INIT_WORK(&rtc->uie_task, rtc_uie_task); + setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc); +#endif + cdev_init(&rtc->char_dev, &rtc_dev_fops); rtc->char_dev.owner = rtc->owner; } diff --git a/drivers/rtc/rtc-ds1286.c b/drivers/rtc/rtc-ds1286.c index bf430f9091ed..60ce69600828 100644 --- a/drivers/rtc/rtc-ds1286.c +++ b/drivers/rtc/rtc-ds1286.c @@ -40,6 +40,26 @@ static inline void ds1286_rtc_write(struct ds1286_priv *priv, u8 data, int reg) __raw_writel(data, &priv->rtcregs[reg]); } + +static int ds1286_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct ds1286_priv *priv = dev_get_drvdata(dev); + unsigned long flags; + unsigned char val; + + /* Allow or mask alarm interrupts */ + spin_lock_irqsave(&priv->lock, flags); + val = ds1286_rtc_read(priv, RTC_CMD); + if (enabled) + val &= ~RTC_TDM; + else + val |= RTC_TDM; + ds1286_rtc_write(priv, val, RTC_CMD); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + #ifdef CONFIG_RTC_INTF_DEV static int ds1286_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) @@ -49,22 +69,6 @@ static int ds1286_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) unsigned char val; switch (cmd) { - case RTC_AIE_OFF: - /* Mask alarm int. enab. bit */ - spin_lock_irqsave(&priv->lock, flags); - val = ds1286_rtc_read(priv, RTC_CMD); - val |= RTC_TDM; - ds1286_rtc_write(priv, val, RTC_CMD); - spin_unlock_irqrestore(&priv->lock, flags); - break; - case RTC_AIE_ON: - /* Allow alarm interrupts. */ - spin_lock_irqsave(&priv->lock, flags); - val = ds1286_rtc_read(priv, RTC_CMD); - val &= ~RTC_TDM; - ds1286_rtc_write(priv, val, RTC_CMD); - spin_unlock_irqrestore(&priv->lock, flags); - break; case RTC_WIE_OFF: /* Mask watchdog int. enab. bit */ spin_lock_irqsave(&priv->lock, flags); @@ -316,12 +320,13 @@ static int ds1286_set_alarm(struct device *dev, struct rtc_wkalrm *alm) } static const struct rtc_class_ops ds1286_ops = { - .ioctl = ds1286_ioctl, - .proc = ds1286_proc, + .ioctl = ds1286_ioctl, + .proc = ds1286_proc, .read_time = ds1286_read_time, .set_time = ds1286_set_time, .read_alarm = ds1286_read_alarm, .set_alarm = ds1286_set_alarm, + .alarm_irq_enable = ds1286_alarm_irq_enable, }; static int __devinit ds1286_probe(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index 077af1d7b9e4..57fbcc149ba7 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -139,49 +139,32 @@ static u8 hour2bcd(bool hr12, int hour) * Interface to RTC framework */ -#ifdef CONFIG_RTC_INTF_DEV - -/* - * Context: caller holds rtc->ops_lock (to protect ds1305->ctrl) - */ -static int ds1305_ioctl(struct device *dev, unsigned cmd, unsigned long arg) +static int ds1305_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct ds1305 *ds1305 = dev_get_drvdata(dev); u8 buf[2]; - int status = -ENOIOCTLCMD; + long err = -EINVAL; buf[0] = DS1305_WRITE | DS1305_CONTROL; buf[1] = ds1305->ctrl[0]; - switch (cmd) { - case RTC_AIE_OFF: - status = 0; - if (!(buf[1] & DS1305_AEI0)) - goto done; - buf[1] &= ~DS1305_AEI0; - break; - - case RTC_AIE_ON: - status = 0; + if (enabled) { if (ds1305->ctrl[0] & DS1305_AEI0) goto done; buf[1] |= DS1305_AEI0; - break; - } - if (status == 0) { - status = spi_write_then_read(ds1305->spi, buf, sizeof buf, - NULL, 0); - if (status >= 0) - ds1305->ctrl[0] = buf[1]; + } else { + if (!(buf[1] & DS1305_AEI0)) + goto done; + buf[1] &= ~DS1305_AEI0; } - + err = spi_write_then_read(ds1305->spi, buf, sizeof buf, NULL, 0); + if (err >= 0) + ds1305->ctrl[0] = buf[1]; done: - return status; + return err; + } -#else -#define ds1305_ioctl NULL -#endif /* * Get/set of date and time is pretty normal. @@ -460,12 +443,12 @@ done: #endif static const struct rtc_class_ops ds1305_ops = { - .ioctl = ds1305_ioctl, .read_time = ds1305_get_time, .set_time = ds1305_set_time, .read_alarm = ds1305_get_alarm, .set_alarm = ds1305_set_alarm, .proc = ds1305_proc, + .alarm_irq_enable = ds1305_alarm_irq_enable, }; static void ds1305_work(struct work_struct *work) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 0d559b6416dd..4724ba3acf1a 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -495,50 +495,27 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t) return 0; } -static int ds1307_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +static int ds1307_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct i2c_client *client = to_i2c_client(dev); struct ds1307 *ds1307 = i2c_get_clientdata(client); int ret; - switch (cmd) { - case RTC_AIE_OFF: - if (!test_bit(HAS_ALARM, &ds1307->flags)) - return -ENOTTY; - - ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL); - if (ret < 0) - return ret; - - ret &= ~DS1337_BIT_A1IE; - - ret = i2c_smbus_write_byte_data(client, - DS1337_REG_CONTROL, ret); - if (ret < 0) - return ret; - - break; - - case RTC_AIE_ON: - if (!test_bit(HAS_ALARM, &ds1307->flags)) - return -ENOTTY; + if (!test_bit(HAS_ALARM, &ds1307->flags)) + return -ENOTTY; - ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL); - if (ret < 0) - return ret; + ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL); + if (ret < 0) + return ret; + if (enabled) ret |= DS1337_BIT_A1IE; + else + ret &= ~DS1337_BIT_A1IE; - ret = i2c_smbus_write_byte_data(client, - DS1337_REG_CONTROL, ret); - if (ret < 0) - return ret; - - break; - - default: - return -ENOIOCTLCMD; - } + ret = i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, ret); + if (ret < 0) + return ret; return 0; } @@ -548,7 +525,7 @@ static const struct rtc_class_ops ds13xx_rtc_ops = { .set_time = ds1307_set_time, .read_alarm = ds1337_read_alarm, .set_alarm = ds1337_set_alarm, - .ioctl = ds1307_ioctl, + .alarm_irq_enable = ds1307_alarm_irq_enable, }; /*----------------------------------------------------------------------*/ diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 47fb6357c346..d834a63ec4b0 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -307,42 +307,25 @@ unlock: mutex_unlock(&ds1374->mutex); } -static int ds1374_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +static int ds1374_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct i2c_client *client = to_i2c_client(dev); struct ds1374 *ds1374 = i2c_get_clientdata(client); - int ret = -ENOIOCTLCMD; + int ret; mutex_lock(&ds1374->mutex); - switch (cmd) { - case RTC_AIE_OFF: - ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR); - if (ret < 0) - goto out; - - ret &= ~DS1374_REG_CR_WACE; - - ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret); - if (ret < 0) - goto out; - - break; - - case RTC_AIE_ON: - ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR); - if (ret < 0) - goto out; + ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR); + if (ret < 0) + goto out; + if (enabled) { ret |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE; ret &= ~DS1374_REG_CR_WDALM; - - ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret); - if (ret < 0) - goto out; - - break; + } else { + ret &= ~DS1374_REG_CR_WACE; } + ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret); out: mutex_unlock(&ds1374->mutex); @@ -354,7 +337,7 @@ static const struct rtc_class_ops ds1374_rtc_ops = { .set_time = ds1374_set_time, .read_alarm = ds1374_read_alarm, .set_alarm = ds1374_set_alarm, - .ioctl = ds1374_ioctl, + .alarm_irq_enable = ds1374_alarm_irq_enable, }; static int ds1374_probe(struct i2c_client *client, diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 5a8daa358066..69fe664a2228 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -213,41 +213,27 @@ static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm) return m41t80_set_datetime(to_i2c_client(dev), tm); } -#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE) -static int -m41t80_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +static int m41t80_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct i2c_client *client = to_i2c_client(dev); int rc; - switch (cmd) { - case RTC_AIE_OFF: - case RTC_AIE_ON: - break; - default: - return -ENOIOCTLCMD; - } - rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON); if (rc < 0) goto err; - switch (cmd) { - case RTC_AIE_OFF: - rc &= ~M41T80_ALMON_AFE; - break; - case RTC_AIE_ON: + + if (enabled) rc |= M41T80_ALMON_AFE; - break; - } + else + rc &= ~M41T80_ALMON_AFE; + if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, rc) < 0) goto err; + return 0; err: return -EIO; } -#else -#define m41t80_rtc_ioctl NULL -#endif static int m41t80_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t) { @@ -374,7 +360,7 @@ static struct rtc_class_ops m41t80_rtc_ops = { .read_alarm = m41t80_rtc_read_alarm, .set_alarm = m41t80_rtc_set_alarm, .proc = m41t80_rtc_proc, - .ioctl = m41t80_rtc_ioctl, + .alarm_irq_enable = m41t80_rtc_alarm_irq_enable, }; #if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE) diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index a99a0b554eb8..3978f4caf724 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -263,30 +263,21 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) /* * Handle commands from user-space */ -static int m48t59_rtc_ioctl(struct device *dev, unsigned int cmd, - unsigned long arg) +static int m48t59_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct platform_device *pdev = to_platform_device(dev); struct m48t59_plat_data *pdata = pdev->dev.platform_data; struct m48t59_private *m48t59 = platform_get_drvdata(pdev); unsigned long flags; - int ret = 0; spin_lock_irqsave(&m48t59->lock, flags); - switch (cmd) { - case RTC_AIE_OFF: /* alarm interrupt off */ - M48T59_WRITE(0x00, M48T59_INTR); - break; - case RTC_AIE_ON: /* alarm interrupt on */ + if (enabled) M48T59_WRITE(M48T59_INTR_AFE, M48T59_INTR); - break; - default: - ret = -ENOIOCTLCMD; - break; - } + else + M48T59_WRITE(0x00, M48T59_INTR); spin_unlock_irqrestore(&m48t59->lock, flags); - return ret; + return 0; } static int m48t59_rtc_proc(struct device *dev, struct seq_file *seq) @@ -330,12 +321,12 @@ static irqreturn_t m48t59_rtc_interrupt(int irq, void *dev_id) } static const struct rtc_class_ops m48t59_rtc_ops = { - .ioctl = m48t59_rtc_ioctl, .read_time = m48t59_rtc_read_time, .set_time = m48t59_rtc_set_time, .read_alarm = m48t59_rtc_readalarm, .set_alarm = m48t59_rtc_setalarm, .proc = m48t59_rtc_proc, + .alarm_irq_enable = m48t59_rtc_alarm_irq_enable, }; static const struct rtc_class_ops m48t02_rtc_ops = { diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c index bcd0cf63eb16..1db62db8469d 100644 --- a/drivers/rtc/rtc-mrst.c +++ b/drivers/rtc/rtc-mrst.c @@ -255,42 +255,21 @@ static int mrst_irq_set_state(struct device *dev, int enabled) return 0; } -#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE) - /* Currently, the vRTC doesn't support UIE ON/OFF */ -static int -mrst_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +static int mrst_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct mrst_rtc *mrst = dev_get_drvdata(dev); unsigned long flags; - switch (cmd) { - case RTC_AIE_OFF: - case RTC_AIE_ON: - if (!mrst->irq) - return -EINVAL; - break; - default: - /* PIE ON/OFF is handled by mrst_irq_set_state() */ - return -ENOIOCTLCMD; - } - spin_lock_irqsave(&rtc_lock, flags); - switch (cmd) { - case RTC_AIE_OFF: /* alarm off */ - mrst_irq_disable(mrst, RTC_AIE); - break; - case RTC_AIE_ON: /* alarm on */ + if (enabled) mrst_irq_enable(mrst, RTC_AIE); - break; - } + else + mrst_irq_disable(mrst, RTC_AIE); spin_unlock_irqrestore(&rtc_lock, flags); return 0; } -#else -#define mrst_rtc_ioctl NULL -#endif #if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE) @@ -317,13 +296,13 @@ static int mrst_procfs(struct device *dev, struct seq_file *seq) #endif static const struct rtc_class_ops mrst_rtc_ops = { - .ioctl = mrst_rtc_ioctl, .read_time = mrst_read_time, .set_time = mrst_set_time, .read_alarm = mrst_read_alarm, .set_alarm = mrst_set_alarm, .proc = mrst_procfs, .irq_set_state = mrst_irq_set_state, + .alarm_irq_enable = mrst_rtc_alarm_irq_enable, }; static struct mrst_rtc mrst_rtc; diff --git a/drivers/rtc/rtc-msm6242.c b/drivers/rtc/rtc-msm6242.c index b2fff0ca49f8..67820626e18f 100644 --- a/drivers/rtc/rtc-msm6242.c +++ b/drivers/rtc/rtc-msm6242.c @@ -82,7 +82,7 @@ static inline unsigned int msm6242_read(struct msm6242_priv *priv, static inline void msm6242_write(struct msm6242_priv *priv, unsigned int val, unsigned int reg) { - return __raw_writel(val, &priv->regs[reg]); + __raw_writel(val, &priv->regs[reg]); } static inline void msm6242_set(struct msm6242_priv *priv, unsigned int val, diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c index bcca47298554..60627a764514 100644 --- a/drivers/rtc/rtc-mv.c +++ b/drivers/rtc/rtc-mv.c @@ -169,25 +169,19 @@ static int mv_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) return 0; } -static int mv_rtc_ioctl(struct device *dev, unsigned int cmd, - unsigned long arg) +static int mv_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); void __iomem *ioaddr = pdata->ioaddr; if (pdata->irq < 0) - return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ - switch (cmd) { - case RTC_AIE_OFF: - writel(0, ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); - break; - case RTC_AIE_ON: + return -EINVAL; /* fall back into rtc-dev's emulation */ + + if (enabled) writel(1, ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); - break; - default: - return -ENOIOCTLCMD; - } + else + writel(0, ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); return 0; } @@ -216,7 +210,7 @@ static const struct rtc_class_ops mv_rtc_alarm_ops = { .set_time = mv_rtc_set_time, .read_alarm = mv_rtc_read_alarm, .set_alarm = mv_rtc_set_alarm, - .ioctl = mv_rtc_ioctl, + .alarm_irq_enable = mv_rtc_alarm_irq_enable, }; static int __devinit mv_rtc_probe(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index e72b523c79a5..b4dbf3a319b3 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -143,8 +143,6 @@ omap_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) u8 reg; switch (cmd) { - case RTC_AIE_OFF: - case RTC_AIE_ON: case RTC_UIE_OFF: case RTC_UIE_ON: break; @@ -156,13 +154,6 @@ omap_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) rtc_wait_not_busy(); reg = rtc_read(OMAP_RTC_INTERRUPTS_REG); switch (cmd) { - /* AIE = Alarm Interrupt Enable */ - case RTC_AIE_OFF: - reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM; - break; - case RTC_AIE_ON: - reg |= OMAP_RTC_INTERRUPTS_IT_ALARM; - break; /* UIE = Update Interrupt Enable (1/second) */ case RTC_UIE_OFF: reg &= ~OMAP_RTC_INTERRUPTS_IT_TIMER; @@ -182,6 +173,24 @@ omap_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) #define omap_rtc_ioctl NULL #endif +static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + u8 reg; + + local_irq_disable(); + rtc_wait_not_busy(); + reg = rtc_read(OMAP_RTC_INTERRUPTS_REG); + if (enabled) + reg |= OMAP_RTC_INTERRUPTS_IT_ALARM; + else + reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM; + rtc_wait_not_busy(); + rtc_write(reg, OMAP_RTC_INTERRUPTS_REG); + local_irq_enable(); + + return 0; +} + /* this hardware doesn't support "don't care" alarm fields */ static int tm2bcd(struct rtc_time *tm) { @@ -309,6 +318,7 @@ static struct rtc_class_ops omap_rtc_ops = { .set_time = omap_rtc_set_time, .read_alarm = omap_rtc_read_alarm, .set_alarm = omap_rtc_set_alarm, + .alarm_irq_enable = omap_rtc_alarm_irq_enable, }; static int omap_rtc_alarm; diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c index c086fc30a84c..242bbf86c74a 100644 --- a/drivers/rtc/rtc-proc.c +++ b/drivers/rtc/rtc-proc.c @@ -81,12 +81,16 @@ static int rtc_proc_show(struct seq_file *seq, void *offset) static int rtc_proc_open(struct inode *inode, struct file *file) { + int ret; struct rtc_device *rtc = PDE(inode)->data; if (!try_module_get(THIS_MODULE)) return -ENODEV; - return single_open(file, rtc_proc_show, rtc); + ret = single_open(file, rtc_proc_show, rtc); + if (ret) + module_put(THIS_MODULE); + return ret; } static int rtc_proc_release(struct inode *inode, struct file *file) diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c index 36eb66184461..694da39b6dd2 100644 --- a/drivers/rtc/rtc-rp5c01.c +++ b/drivers/rtc/rtc-rp5c01.c @@ -76,7 +76,7 @@ static inline unsigned int rp5c01_read(struct rp5c01_priv *priv, static inline void rp5c01_write(struct rp5c01_priv *priv, unsigned int val, unsigned int reg) { - return __raw_writel(val, &priv->regs[reg]); + __raw_writel(val, &priv->regs[reg]); } static void rp5c01_lock(struct rp5c01_priv *priv) diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index dd14e202c2c8..6aaa1550e3b1 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -299,14 +299,6 @@ rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) if (rs5c->type == rtc_rs5c372a && (buf & RS5C372A_CTRL1_SL1)) return -ENOIOCTLCMD; - case RTC_AIE_OFF: - case RTC_AIE_ON: - /* these irq management calls only make sense for chips - * which are wired up to an IRQ. - */ - if (!rs5c->has_irq) - return -ENOIOCTLCMD; - break; default: return -ENOIOCTLCMD; } @@ -317,12 +309,6 @@ rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) addr = RS5C_ADDR(RS5C_REG_CTRL1); switch (cmd) { - case RTC_AIE_OFF: /* alarm off */ - buf &= ~RS5C_CTRL1_AALE; - break; - case RTC_AIE_ON: /* alarm on */ - buf |= RS5C_CTRL1_AALE; - break; case RTC_UIE_OFF: /* update off */ buf &= ~RS5C_CTRL1_CT_MASK; break; @@ -347,6 +333,39 @@ rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) #endif +static int rs5c_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rs5c372 *rs5c = i2c_get_clientdata(client); + unsigned char buf; + int status, addr; + + buf = rs5c->regs[RS5C_REG_CTRL1]; + + if (!rs5c->has_irq) + return -EINVAL; + + status = rs5c_get_regs(rs5c); + if (status < 0) + return status; + + addr = RS5C_ADDR(RS5C_REG_CTRL1); + if (enabled) + buf |= RS5C_CTRL1_AALE; + else + buf &= ~RS5C_CTRL1_AALE; + + if (i2c_smbus_write_byte_data(client, addr, buf) < 0) { + printk(KERN_WARNING "%s: can't update alarm\n", + rs5c->rtc->name); + status = -EIO; + } else + rs5c->regs[RS5C_REG_CTRL1] = buf; + + return status; +} + + /* NOTE: Since RTC_WKALM_{RD,SET} were originally defined for EFI, * which only exposes a polled programming interface; and since * these calls map directly to those EFI requests; we don't demand @@ -466,6 +485,7 @@ static const struct rtc_class_ops rs5c372_rtc_ops = { .set_time = rs5c372_rtc_set_time, .read_alarm = rs5c_read_alarm, .set_alarm = rs5c_set_alarm, + .alarm_irq_enable = rs5c_rtc_alarm_irq_enable, }; #if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE) diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 88ea52b8647a..5dfe5ffcb0d3 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -314,16 +314,6 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { switch (cmd) { - case RTC_AIE_OFF: - spin_lock_irq(&sa1100_rtc_lock); - RTSR &= ~RTSR_ALE; - spin_unlock_irq(&sa1100_rtc_lock); - return 0; - case RTC_AIE_ON: - spin_lock_irq(&sa1100_rtc_lock); - RTSR |= RTSR_ALE; - spin_unlock_irq(&sa1100_rtc_lock); - return 0; case RTC_UIE_OFF: spin_lock_irq(&sa1100_rtc_lock); RTSR &= ~RTSR_HZE; @@ -338,6 +328,17 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd, return -ENOIOCTLCMD; } +static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + spin_lock_irq(&sa1100_rtc_lock); + if (enabled) + RTSR |= RTSR_ALE; + else + RTSR &= ~RTSR_ALE; + spin_unlock_irq(&sa1100_rtc_lock); + return 0; +} + static int sa1100_rtc_read_time(struct device *dev, struct rtc_time *tm) { rtc_time_to_tm(RCNR, tm); @@ -410,6 +411,7 @@ static const struct rtc_class_ops sa1100_rtc_ops = { .proc = sa1100_rtc_proc, .irq_set_freq = sa1100_irq_set_freq, .irq_set_state = sa1100_irq_set_state, + .alarm_irq_enable = sa1100_rtc_alarm_irq_enable, }; static int sa1100_rtc_probe(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 06e41ed93230..93314a9e7fa9 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -350,10 +350,6 @@ static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) unsigned int ret = 0; switch (cmd) { - case RTC_AIE_OFF: - case RTC_AIE_ON: - sh_rtc_setaie(dev, cmd == RTC_AIE_ON); - break; case RTC_UIE_OFF: rtc->periodic_freq &= ~PF_OXS; sh_rtc_setcie(dev, 0); @@ -369,6 +365,12 @@ static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) return ret; } +static int sh_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + sh_rtc_setaie(dev, enabled); + return 0; +} + static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct platform_device *pdev = to_platform_device(dev); @@ -604,6 +606,7 @@ static struct rtc_class_ops sh_rtc_ops = { .irq_set_state = sh_rtc_irq_set_state, .irq_set_freq = sh_rtc_irq_set_freq, .proc = sh_rtc_proc, + .alarm_irq_enable = sh_rtc_alarm_irq_enable, }; static int __init sh_rtc_probe(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index 51725f7755b0..a82d6fe97076 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -50,24 +50,9 @@ static int test_rtc_proc(struct device *dev, struct seq_file *seq) return 0; } -static int test_rtc_ioctl(struct device *dev, unsigned int cmd, - unsigned long arg) +static int test_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) { - /* We do support interrupts, they're generated - * using the sysfs interface. - */ - switch (cmd) { - case RTC_PIE_ON: - case RTC_PIE_OFF: - case RTC_UIE_ON: - case RTC_UIE_OFF: - case RTC_AIE_ON: - case RTC_AIE_OFF: - return 0; - - default: - return -ENOIOCTLCMD; - } + return 0; } static const struct rtc_class_ops test_rtc_ops = { @@ -76,7 +61,7 @@ static const struct rtc_class_ops test_rtc_ops = { .read_alarm = test_rtc_read_alarm, .set_alarm = test_rtc_set_alarm, .set_mmss = test_rtc_set_mmss, - .ioctl = test_rtc_ioctl, + .alarm_irq_enable = test_rtc_alarm_irq_enable, }; static ssize_t test_irq_show(struct device *dev, diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index c3244244e8cf..769190ac6d11 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -240,26 +240,6 @@ static int vr41xx_rtc_irq_set_state(struct device *dev, int enabled) static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { switch (cmd) { - case RTC_AIE_ON: - spin_lock_irq(&rtc_lock); - - if (!alarm_enabled) { - enable_irq(aie_irq); - alarm_enabled = 1; - } - - spin_unlock_irq(&rtc_lock); - break; - case RTC_AIE_OFF: - spin_lock_irq(&rtc_lock); - - if (alarm_enabled) { - disable_irq(aie_irq); - alarm_enabled = 0; - } - - spin_unlock_irq(&rtc_lock); - break; case RTC_EPOCH_READ: return put_user(epoch, (unsigned long __user *)arg); case RTC_EPOCH_SET: @@ -275,6 +255,24 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long return 0; } +static int vr41xx_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + spin_lock_irq(&rtc_lock); + if (enabled) { + if (!alarm_enabled) { + enable_irq(aie_irq); + alarm_enabled = 1; + } + } else { + if (alarm_enabled) { + disable_irq(aie_irq); + alarm_enabled = 0; + } + } + spin_unlock_irq(&rtc_lock); + return 0; +} + static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id) { struct platform_device *pdev = (struct platform_device *)dev_id; diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 4155805dcdff..2b771f18d1ad 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c @@ -319,6 +319,9 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) private = (struct dasd_eckd_private *) device->private; lcu = private->lcu; + /* nothing to do if already disconnected */ + if (!lcu) + return; device->discipline->get_uid(device, &uid); spin_lock_irqsave(&lcu->lock, flags); list_del_init(&device->alias_list); @@ -680,6 +683,9 @@ int dasd_alias_remove_device(struct dasd_device *device) private = (struct dasd_eckd_private *) device->private; lcu = private->lcu; + /* nothing to do if already removed */ + if (!lcu) + return 0; spin_lock_irqsave(&lcu->lock, flags); _remove_device_from_lcu(lcu, device); spin_unlock_irqrestore(&lcu->lock, flags); diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index e9fff2b9bce2..5640c89cd9de 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -476,7 +476,7 @@ static inline void inbound_primed(struct qdio_q *q, int count) static int get_inbound_buffer_frontier(struct qdio_q *q) { int count, stop; - unsigned char state; + unsigned char state = 0; /* * Don't check 128 buffers, as otherwise qdio_inbound_q_moved @@ -643,7 +643,7 @@ void qdio_inbound_processing(unsigned long data) static int get_outbound_buffer_frontier(struct qdio_q *q) { int count, stop; - unsigned char state; + unsigned char state = 0; if (need_siga_sync(q)) if (((queue_type(q) != QDIO_IQDIO_QFMT) && diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h index 475c31ae985c..77b26f5b9c33 100644 --- a/drivers/scsi/arcmsr/arcmsr.h +++ b/drivers/scsi/arcmsr/arcmsr.h @@ -2,7 +2,7 @@ ******************************************************************************* ** O.S : Linux ** FILE NAME : arcmsr.h -** BY : Erich Chen +** BY : Nick Cheng ** Description: SCSI RAID Device Driver for ** ARECA RAID Host adapter ******************************************************************************* @@ -46,8 +46,12 @@ struct device_attribute; /*The limit of outstanding scsi command that firmware can handle*/ #define ARCMSR_MAX_OUTSTANDING_CMD 256 -#define ARCMSR_MAX_FREECCB_NUM 320 -#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2010/02/02" +#ifdef CONFIG_XEN + #define ARCMSR_MAX_FREECCB_NUM 160 +#else + #define ARCMSR_MAX_FREECCB_NUM 320 +#endif +#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2010/08/05" #define ARCMSR_SCSI_INITIATOR_ID 255 #define ARCMSR_MAX_XFER_SECTORS 512 #define ARCMSR_MAX_XFER_SECTORS_B 4096 @@ -60,7 +64,6 @@ struct device_attribute; #define ARCMSR_MAX_HBB_POSTQUEUE 264 #define ARCMSR_MAX_XFER_LEN 0x26000 /* 152K */ #define ARCMSR_CDB_SG_PAGE_LENGTH 256 -#define SCSI_CMD_ARECA_SPECIFIC 0xE1 #ifndef PCI_DEVICE_ID_ARECA_1880 #define PCI_DEVICE_ID_ARECA_1880 0x1880 #endif diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c index a4e04c50c436..acdae33de521 100644 --- a/drivers/scsi/arcmsr/arcmsr_attr.c +++ b/drivers/scsi/arcmsr/arcmsr_attr.c @@ -2,7 +2,7 @@ ******************************************************************************* ** O.S : Linux ** FILE NAME : arcmsr_attr.c -** BY : Erich Chen +** BY : Nick Cheng ** Description: attributes exported to sysfs and device host ******************************************************************************* ** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 1cadcd6b7da6..984bd527c6c9 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -2,7 +2,7 @@ ******************************************************************************* ** O.S : Linux ** FILE NAME : arcmsr_hba.c -** BY : Erich Chen +** BY : Nick Cheng ** Description: SCSI RAID Device Driver for ** ARECA RAID Host adapter ******************************************************************************* @@ -76,7 +76,7 @@ MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx/1880) SATA/SAS RAID Host Bus Adapte MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(ARCMSR_DRIVER_VERSION); static int sleeptime = 10; -static int retrycount = 30; +static int retrycount = 12; wait_queue_head_t wait_q; static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd); @@ -187,7 +187,6 @@ int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd) if (isleep > 0) { msleep(isleep*1000); } - printk(KERN_NOTICE "wake-up\n"); return 0; } @@ -921,7 +920,6 @@ static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, } static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct CommandControlBlock *pCCB, bool error) - { int id, lun; if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) { @@ -948,7 +946,7 @@ static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct Comma , pCCB->startdone , atomic_read(&acb->ccboutstandingcount)); return; - } + } arcmsr_report_ccb_state(acb, pCCB, error); } @@ -981,7 +979,7 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; /*clear all outbound posted Q*/ - writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, ®->iop2drv_doorbell); /* clear doorbell interrupt */ + writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); /* clear doorbell interrupt */ for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) { if ((flag_ccb = readl(®->done_qbuffer[i])) != 0) { writel(0, ®->done_qbuffer[i]); @@ -1511,7 +1509,6 @@ static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb) arcmsr_drain_donequeue(acb, pCCB, error); } } - static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb) { uint32_t index; @@ -2106,10 +2103,6 @@ static int arcmsr_queue_command_lck(struct scsi_cmnd *cmd, if (atomic_read(&acb->ccboutstandingcount) >= ARCMSR_MAX_OUTSTANDING_CMD) return SCSI_MLQUEUE_HOST_BUSY; - if ((scsicmd == SCSI_CMD_ARECA_SPECIFIC)) { - printk(KERN_NOTICE "Receiveing SCSI_CMD_ARECA_SPECIFIC command..\n"); - return 0; - } ccb = arcmsr_get_freeccb(acb); if (!ccb) return SCSI_MLQUEUE_HOST_BUSY; @@ -2393,6 +2386,7 @@ static int arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, int index, rtn; bool error; polling_hbb_ccb_retry: + poll_count++; /* clear doorbell interrupt */ writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); @@ -2663,6 +2657,7 @@ static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb) { struct MessageUnit_A __iomem *reg = acb->pmuA; if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){ + mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); return; } else { acb->fw_flag = FW_NORMAL; @@ -2670,8 +2665,10 @@ static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb) atomic_set(&acb->rq_map_token, 16); } atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token)); - if (atomic_dec_and_test(&acb->rq_map_token)) + if (atomic_dec_and_test(&acb->rq_map_token)) { + mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); return; + } writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); } @@ -2682,15 +2679,18 @@ static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb) { struct MessageUnit_B __iomem *reg = acb->pmuB; if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){ + mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); return; } else { acb->fw_flag = FW_NORMAL; if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) { - atomic_set(&acb->rq_map_token,16); + atomic_set(&acb->rq_map_token, 16); } atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token)); - if(atomic_dec_and_test(&acb->rq_map_token)) + if (atomic_dec_and_test(&acb->rq_map_token)) { + mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); return; + } writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell); mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); } @@ -2701,6 +2701,7 @@ static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb) { struct MessageUnit_C __iomem *reg = acb->pmuC; if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) { + mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); return; } else { acb->fw_flag = FW_NORMAL; @@ -2708,8 +2709,10 @@ static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb) atomic_set(&acb->rq_map_token, 16); } atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token)); - if (atomic_dec_and_test(&acb->rq_map_token)) + if (atomic_dec_and_test(&acb->rq_map_token)) { + mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); return; + } writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); @@ -2897,6 +2900,8 @@ static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb) uint32_t intmask_org; uint8_t rtnval = 0x00; int i = 0; + unsigned long flags; + if (atomic_read(&acb->ccboutstandingcount) != 0) { /* disable all outbound interrupt */ intmask_org = arcmsr_disable_outbound_ints(acb); @@ -2907,7 +2912,12 @@ static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb) for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { ccb = acb->pccb_pool[i]; if (ccb->startdone == ARCMSR_CCB_START) { - arcmsr_ccb_complete(ccb); + scsi_dma_unmap(ccb->pcmd); + ccb->startdone = ARCMSR_CCB_DONE; + ccb->ccb_flags = 0; + spin_lock_irqsave(&acb->ccblist_lock, flags); + list_add_tail(&ccb->list, &acb->ccb_free_list); + spin_unlock_irqrestore(&acb->ccblist_lock, flags); } } atomic_set(&acb->ccboutstandingcount, 0); @@ -2920,8 +2930,7 @@ static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb) static int arcmsr_bus_reset(struct scsi_cmnd *cmd) { - struct AdapterControlBlock *acb = - (struct AdapterControlBlock *)cmd->device->host->hostdata; + struct AdapterControlBlock *acb; uint32_t intmask_org, outbound_doorbell; int retry_count = 0; int rtn = FAILED; @@ -2971,31 +2980,16 @@ sleep_again: atomic_set(&acb->rq_map_token, 16); atomic_set(&acb->ante_token_value, 16); acb->fw_flag = FW_NORMAL; - init_timer(&acb->eternal_timer); - acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ); - acb->eternal_timer.data = (unsigned long) acb; - acb->eternal_timer.function = &arcmsr_request_device_map; - add_timer(&acb->eternal_timer); + mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); acb->acb_flags &= ~ACB_F_BUS_RESET; rtn = SUCCESS; printk(KERN_ERR "arcmsr: scsi bus reset eh returns with success\n"); } else { acb->acb_flags &= ~ACB_F_BUS_RESET; - if (atomic_read(&acb->rq_map_token) == 0) { - atomic_set(&acb->rq_map_token, 16); - atomic_set(&acb->ante_token_value, 16); - acb->fw_flag = FW_NORMAL; - init_timer(&acb->eternal_timer); - acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ); - acb->eternal_timer.data = (unsigned long) acb; - acb->eternal_timer.function = &arcmsr_request_device_map; - add_timer(&acb->eternal_timer); - } else { - atomic_set(&acb->rq_map_token, 16); - atomic_set(&acb->ante_token_value, 16); - acb->fw_flag = FW_NORMAL; - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); - } + atomic_set(&acb->rq_map_token, 16); + atomic_set(&acb->ante_token_value, 16); + acb->fw_flag = FW_NORMAL; + mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); rtn = SUCCESS; } break; @@ -3007,21 +3001,10 @@ sleep_again: rtn = FAILED; } else { acb->acb_flags &= ~ACB_F_BUS_RESET; - if (atomic_read(&acb->rq_map_token) == 0) { - atomic_set(&acb->rq_map_token, 16); - atomic_set(&acb->ante_token_value, 16); - acb->fw_flag = FW_NORMAL; - init_timer(&acb->eternal_timer); - acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ); - acb->eternal_timer.data = (unsigned long) acb; - acb->eternal_timer.function = &arcmsr_request_device_map; - add_timer(&acb->eternal_timer); - } else { - atomic_set(&acb->rq_map_token, 16); - atomic_set(&acb->ante_token_value, 16); - acb->fw_flag = FW_NORMAL; - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); - } + atomic_set(&acb->rq_map_token, 16); + atomic_set(&acb->ante_token_value, 16); + acb->fw_flag = FW_NORMAL; + mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); rtn = SUCCESS; } break; @@ -3067,31 +3050,16 @@ sleep: atomic_set(&acb->rq_map_token, 16); atomic_set(&acb->ante_token_value, 16); acb->fw_flag = FW_NORMAL; - init_timer(&acb->eternal_timer); - acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6 * HZ); - acb->eternal_timer.data = (unsigned long) acb; - acb->eternal_timer.function = &arcmsr_request_device_map; - add_timer(&acb->eternal_timer); + mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); acb->acb_flags &= ~ACB_F_BUS_RESET; rtn = SUCCESS; printk(KERN_ERR "arcmsr: scsi bus reset eh returns with success\n"); } else { acb->acb_flags &= ~ACB_F_BUS_RESET; - if (atomic_read(&acb->rq_map_token) == 0) { - atomic_set(&acb->rq_map_token, 16); - atomic_set(&acb->ante_token_value, 16); - acb->fw_flag = FW_NORMAL; - init_timer(&acb->eternal_timer); - acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ); - acb->eternal_timer.data = (unsigned long) acb; - acb->eternal_timer.function = &arcmsr_request_device_map; - add_timer(&acb->eternal_timer); - } else { - atomic_set(&acb->rq_map_token, 16); - atomic_set(&acb->ante_token_value, 16); - acb->fw_flag = FW_NORMAL; - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); - } + atomic_set(&acb->rq_map_token, 16); + atomic_set(&acb->ante_token_value, 16); + acb->fw_flag = FW_NORMAL; + mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); rtn = SUCCESS; } break; diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 5815cbeb27a6..9a7aaf5f1311 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -646,6 +646,7 @@ void sas_scsi_recover_host(struct Scsi_Host *shost) spin_lock_irqsave(shost->host_lock, flags); list_splice_init(&shost->eh_cmd_q, &eh_work_q); + shost->host_eh_scheduled = 0; spin_unlock_irqrestore(shost->host_lock, flags); SAS_DPRINTK("Enter %s\n", __func__); diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index b2a817055b8b..9ead0399808a 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -2176,9 +2176,9 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) /* adjust hba_queue_depth, reply_free_queue_depth, * and queue_size */ - ioc->hba_queue_depth -= queue_diff; - ioc->reply_free_queue_depth -= queue_diff; - queue_size -= queue_diff; + ioc->hba_queue_depth -= (queue_diff / 2); + ioc->reply_free_queue_depth -= (queue_diff / 2); + queue_size = facts->MaxReplyDescriptorPostQueueDepth; } ioc->reply_post_queue_depth = queue_size; @@ -3941,6 +3941,8 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc) static void _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) { + mpt2sas_scsih_reset_handler(ioc, reset_phase); + mpt2sas_ctl_reset_handler(ioc, reset_phase); switch (reset_phase) { case MPT2_IOC_PRE_RESET: dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " @@ -3971,8 +3973,6 @@ _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); break; } - mpt2sas_scsih_reset_handler(ioc, reset_phase); - mpt2sas_ctl_reset_handler(ioc, reset_phase); } /** @@ -4026,6 +4026,7 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, { int r; unsigned long flags; + u8 pe_complete = ioc->wait_for_port_enable_to_complete; dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); @@ -4068,6 +4069,14 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, if (r) goto out; _base_reset_handler(ioc, MPT2_IOC_AFTER_RESET); + + /* If this hard reset is called while port enable is active, then + * there is no reason to call make_ioc_operational + */ + if (pe_complete) { + r = -EFAULT; + goto out; + } r = _base_make_ioc_operational(ioc, sleep_flag); if (!r) _base_reset_handler(ioc, MPT2_IOC_DONE_RESET); diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index eda347c57979..5ded3db6e316 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -819,7 +819,7 @@ _scsih_is_end_device(u32 device_info) } /** - * mptscsih_get_scsi_lookup - returns scmd entry + * _scsih_scsi_lookup_get - returns scmd entry * @ioc: per adapter object * @smid: system request message index * @@ -832,6 +832,28 @@ _scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid) } /** + * _scsih_scsi_lookup_get_clear - returns scmd entry + * @ioc: per adapter object + * @smid: system request message index + * + * Returns the smid stored scmd pointer. + * Then will derefrence the stored scmd pointer. + */ +static inline struct scsi_cmnd * +_scsih_scsi_lookup_get_clear(struct MPT2SAS_ADAPTER *ioc, u16 smid) +{ + unsigned long flags; + struct scsi_cmnd *scmd; + + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + scmd = ioc->scsi_lookup[smid - 1].scmd; + ioc->scsi_lookup[smid - 1].scmd = NULL; + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + + return scmd; +} + +/** * _scsih_scsi_lookup_find_by_scmd - scmd lookup * @ioc: per adapter object * @smid: system request message index @@ -2981,9 +3003,6 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc, u16 handle; for (i = 0 ; i < event_data->NumEntries; i++) { - if (event_data->PHY[i].PhyStatus & - MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) - continue; handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); if (!handle) continue; @@ -3210,7 +3229,7 @@ _scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc) u16 count = 0; for (smid = 1; smid <= ioc->scsiio_depth; smid++) { - scmd = _scsih_scsi_lookup_get(ioc, smid); + scmd = _scsih_scsi_lookup_get_clear(ioc, smid); if (!scmd) continue; count++; @@ -3804,7 +3823,7 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) u32 response_code = 0; mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - scmd = _scsih_scsi_lookup_get(ioc, smid); + scmd = _scsih_scsi_lookup_get_clear(ioc, smid); if (scmd == NULL) return 1; @@ -5005,6 +5024,12 @@ _scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc, event_data); #endif + /* In MPI Revision K (0xC), the internal device reset complete was + * implemented, so avoid setting tm_busy flag for older firmware. + */ + if ((ioc->facts.HeaderVersion >> 8) < 0xC) + return; + if (event_data->ReasonCode != MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET && event_data->ReasonCode != @@ -5099,6 +5124,7 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event) { struct scsi_cmnd *scmd; + struct scsi_device *sdev; u16 smid, handle; u32 lun; struct MPT2SAS_DEVICE *sas_device_priv_data; @@ -5109,12 +5135,17 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data; #endif u16 ioc_status; + unsigned long flags; + int r; + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "broadcast primative: " "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum, event_data->PortWidth)); dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + ioc->broadcast_aen_busy = 0; termination_count = 0; query_count = 0; mpi_reply = ioc->tm_cmds.reply; @@ -5122,7 +5153,8 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, scmd = _scsih_scsi_lookup_get(ioc, smid); if (!scmd) continue; - sas_device_priv_data = scmd->device->hostdata; + sdev = scmd->device; + sas_device_priv_data = sdev->hostdata; if (!sas_device_priv_data || !sas_device_priv_data->sas_target) continue; /* skip hidden raid components */ @@ -5138,6 +5170,7 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, lun = sas_device_priv_data->lun; query_count++; + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun, MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, NULL); ioc->tm_cmds.status = MPT2_CMD_NOT_USED; @@ -5147,14 +5180,20 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, (mpi_reply->ResponseCode == MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED || mpi_reply->ResponseCode == - MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) + MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) { + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); continue; - - mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun, - MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30, NULL); + } + r = mpt2sas_scsih_issue_tm(ioc, handle, sdev->channel, sdev->id, + sdev->lun, MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, + scmd); + if (r == FAILED) + sdev_printk(KERN_WARNING, sdev, "task abort: FAILED " + "scmd(%p)\n", scmd); termination_count += le32_to_cpu(mpi_reply->TerminationCount); + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); } - ioc->broadcast_aen_busy = 0; + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - exit, query_count = %d termination_count = %d\n", @@ -6626,6 +6665,7 @@ _scsih_remove(struct pci_dev *pdev) destroy_workqueue(wq); /* release all the volumes */ + _scsih_ir_shutdown(ioc); list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list, list) { if (raid_device->starget) { diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 44578b56ad0a..d3e58d763b43 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1561,6 +1561,7 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport) { struct Scsi_Host *host = rport_to_shost(rport); fc_port_t *fcport = *(fc_port_t **)rport->dd_data; + unsigned long flags; if (!fcport) return; @@ -1573,10 +1574,10 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport) * Transport has effectively 'deleted' the rport, clear * all local references. */ - spin_lock_irq(host->host_lock); + spin_lock_irqsave(host->host_lock, flags); fcport->rport = fcport->drport = NULL; *((fc_port_t **)rport->dd_data) = NULL; - spin_unlock_irq(host->host_lock); + spin_unlock_irqrestore(host->host_lock, flags); if (test_bit(ABORT_ISP_ACTIVE, &fcport->vha->dpc_flags)) return; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index f948e1a73aec..d9479c3fe5f8 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2505,11 +2505,12 @@ qla2x00_rport_del(void *data) { fc_port_t *fcport = data; struct fc_rport *rport; + unsigned long flags; - spin_lock_irq(fcport->vha->host->host_lock); + spin_lock_irqsave(fcport->vha->host->host_lock, flags); rport = fcport->drport ? fcport->drport: fcport->rport; fcport->drport = NULL; - spin_unlock_irq(fcport->vha->host->host_lock); + spin_unlock_irqrestore(fcport->vha->host->host_lock, flags); if (rport) fc_remote_port_delete(rport); } @@ -2879,6 +2880,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport) struct fc_rport_identifiers rport_ids; struct fc_rport *rport; struct qla_hw_data *ha = vha->hw; + unsigned long flags; qla2x00_rport_del(fcport); @@ -2893,9 +2895,9 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport) "Unable to allocate fc remote port!\n"); return; } - spin_lock_irq(fcport->vha->host->host_lock); + spin_lock_irqsave(fcport->vha->host->host_lock, flags); *((fc_port_t **)rport->dd_data) = fcport; - spin_unlock_irq(fcport->vha->host->host_lock); + spin_unlock_irqrestore(fcport->vha->host->host_lock, flags); rport->supported_classes = fcport->supported_classes; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index c194c23ca1fb..f27724d76cf6 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -562,7 +562,6 @@ qla2xxx_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *) } if (atomic_read(&fcport->state) != FCS_ONLINE) { if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD || - atomic_read(&fcport->state) == FCS_DEVICE_LOST || atomic_read(&base_vha->loop_state) == LOOP_DEAD) { cmd->result = DID_NO_CONNECT << 16; goto qc24_fail_command; @@ -2513,6 +2512,7 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport, { struct fc_rport *rport; scsi_qla_host_t *base_vha; + unsigned long flags; if (!fcport->rport) return; @@ -2520,9 +2520,9 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport, rport = fcport->rport; if (defer) { base_vha = pci_get_drvdata(vha->hw->pdev); - spin_lock_irq(vha->host->host_lock); + spin_lock_irqsave(vha->host->host_lock, flags); fcport->drport = rport; - spin_unlock_irq(vha->host->host_lock); + spin_unlock_irqrestore(vha->host->host_lock, flags); set_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags); qla2xxx_wake_dpc(base_vha); } else @@ -3282,10 +3282,10 @@ qla2x00_do_dpc(void *data) set_user_nice(current, -20); + set_current_state(TASK_INTERRUPTIBLE); while (!kthread_should_stop()) { DEBUG3(printk("qla2x00: DPC handler sleeping\n")); - set_current_state(TASK_INTERRUPTIBLE); schedule(); __set_current_state(TASK_RUNNING); @@ -3454,7 +3454,9 @@ qla2x00_do_dpc(void *data) qla2x00_do_dpc_all_vps(base_vha); ha->dpc_active = 0; + set_current_state(TASK_INTERRUPTIBLE); } /* End of while(1) */ + __set_current_state(TASK_RUNNING); DEBUG(printk("scsi(%ld): DPC handler exiting\n", base_vha->host_no)); diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 7b310934efed..a6b2d72022fc 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1671,7 +1671,7 @@ static int do_device_access(struct scsi_cmnd *scmd, unsigned long long lba, unsigned int num, int write) { int ret; - unsigned int block, rest = 0; + unsigned long long block, rest = 0; int (*func)(struct scsi_cmnd *, unsigned char *, int); func = write ? fetch_to_dev_buffer : fill_from_dev_buffer; diff --git a/drivers/sh/intc/chip.c b/drivers/sh/intc/chip.c index de885a0f917a..f33e2dd97934 100644 --- a/drivers/sh/intc/chip.c +++ b/drivers/sh/intc/chip.c @@ -173,7 +173,8 @@ int intc_set_priority(unsigned int irq, unsigned int prio) return 0; } -#define VALID(x) (x | 0x80) +#define SENSE_VALID_FLAG 0x80 +#define VALID(x) (x | SENSE_VALID_FLAG) static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = { [IRQ_TYPE_EDGE_FALLING] = VALID(0), @@ -201,7 +202,8 @@ static int intc_set_type(struct irq_data *data, unsigned int type) ihp = intc_find_irq(d->sense, d->nr_sense, irq); if (ihp) { addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0); - intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value); + intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, + value & ~SENSE_VALID_FLAG); } return 0; diff --git a/drivers/spi/pxa2xx_spi_pci.c b/drivers/spi/pxa2xx_spi_pci.c index 351d8a375b57..19752b09e155 100644 --- a/drivers/spi/pxa2xx_spi_pci.c +++ b/drivers/spi/pxa2xx_spi_pci.c @@ -7,10 +7,9 @@ #include <linux/of_device.h> #include <linux/spi/pxa2xx_spi.h> -struct awesome_struct { +struct ce4100_info { struct ssp_device ssp; - struct platform_device spi_pdev; - struct pxa2xx_spi_master spi_pdata; + struct platform_device *spi_pdev; }; static DEFINE_MUTEX(ssp_lock); @@ -51,23 +50,15 @@ void pxa_ssp_free(struct ssp_device *ssp) } EXPORT_SYMBOL_GPL(pxa_ssp_free); -static void plat_dev_release(struct device *dev) -{ - struct awesome_struct *as = container_of(dev, - struct awesome_struct, spi_pdev.dev); - - of_device_node_put(&as->spi_pdev.dev); -} - static int __devinit ce4100_spi_probe(struct pci_dev *dev, const struct pci_device_id *ent) { int ret; resource_size_t phys_beg; resource_size_t phys_len; - struct awesome_struct *spi_info; + struct ce4100_info *spi_info; struct platform_device *pdev; - struct pxa2xx_spi_master *spi_pdata; + struct pxa2xx_spi_master spi_pdata; struct ssp_device *ssp; ret = pci_enable_device(dev); @@ -84,33 +75,30 @@ static int __devinit ce4100_spi_probe(struct pci_dev *dev, return ret; } + pdev = platform_device_alloc("pxa2xx-spi", dev->devfn); spi_info = kzalloc(sizeof(*spi_info), GFP_KERNEL); - if (!spi_info) { + if (!pdev || !spi_info ) { ret = -ENOMEM; - goto err_kz; + goto err_nomem; } - ssp = &spi_info->ssp; - pdev = &spi_info->spi_pdev; - spi_pdata = &spi_info->spi_pdata; + memset(&spi_pdata, 0, sizeof(spi_pdata)); + spi_pdata.num_chipselect = dev->devfn; - pdev->name = "pxa2xx-spi"; - pdev->id = dev->devfn; - pdev->dev.parent = &dev->dev; - pdev->dev.platform_data = &spi_info->spi_pdata; + ret = platform_device_add_data(pdev, &spi_pdata, sizeof(spi_pdata)); + if (ret) + goto err_nomem; + pdev->dev.parent = &dev->dev; #ifdef CONFIG_OF pdev->dev.of_node = dev->dev.of_node; #endif - pdev->dev.release = plat_dev_release; - - spi_pdata->num_chipselect = dev->devfn; - + ssp = &spi_info->ssp; ssp->phys_base = pci_resource_start(dev, 0); ssp->mmio_base = ioremap(phys_beg, phys_len); if (!ssp->mmio_base) { dev_err(&pdev->dev, "failed to ioremap() registers\n"); ret = -EIO; - goto err_remap; + goto err_nomem; } ssp->irq = dev->irq; ssp->port_id = pdev->id; @@ -122,7 +110,7 @@ static int __devinit ce4100_spi_probe(struct pci_dev *dev, pci_set_drvdata(dev, spi_info); - ret = platform_device_register(pdev); + ret = platform_device_add(pdev); if (ret) goto err_dev_add; @@ -135,27 +123,21 @@ err_dev_add: mutex_unlock(&ssp_lock); iounmap(ssp->mmio_base); -err_remap: - kfree(spi_info); - -err_kz: +err_nomem: release_mem_region(phys_beg, phys_len); - + platform_device_put(pdev); + kfree(spi_info); return ret; } static void __devexit ce4100_spi_remove(struct pci_dev *dev) { - struct awesome_struct *spi_info; - struct platform_device *pdev; + struct ce4100_info *spi_info; struct ssp_device *ssp; spi_info = pci_get_drvdata(dev); - ssp = &spi_info->ssp; - pdev = &spi_info->spi_pdev; - - platform_device_unregister(pdev); + platform_device_unregister(spi_info->spi_pdev); iounmap(ssp->mmio_base); release_mem_region(pci_resource_start(dev, 0), @@ -171,7 +153,6 @@ static void __devexit ce4100_spi_remove(struct pci_dev *dev) } static struct pci_device_id ce4100_spi_devices[] __devinitdata = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e6a) }, { }, }; diff --git a/drivers/spi/spi_sh_msiof.c b/drivers/spi/spi_sh_msiof.c index 56f60c8ea0ab..2c665fceaac7 100644 --- a/drivers/spi/spi_sh_msiof.c +++ b/drivers/spi/spi_sh_msiof.c @@ -509,9 +509,11 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t) bytes_done = 0; while (bytes_done < t->len) { + void *rx_buf = t->rx_buf ? t->rx_buf + bytes_done : NULL; + const void *tx_buf = t->tx_buf ? t->tx_buf + bytes_done : NULL; n = sh_msiof_spi_txrx_once(p, tx_fifo, rx_fifo, - t->tx_buf + bytes_done, - t->rx_buf + bytes_done, + tx_buf, + rx_buf, words, bits); if (n < 0) break; diff --git a/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c index 0e298dba9fc8..29b8ab44ea47 100644 --- a/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c +++ b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c @@ -360,8 +360,8 @@ int PSSendOps(void *arg) status = 1; goto complete; } - len = (firmware->size > MAX_BDADDR_FORMAT_LENGTH)? MAX_BDADDR_FORMAT_LENGTH: firmware->size; - memcpy(config_bdaddr, firmware->data,len); + len = min(firmware->size, MAX_BDADDR_FORMAT_LENGTH - 1); + memcpy(config_bdaddr, firmware->data, len); config_bdaddr[len] = '\0'; write_bdaddr(hdev,config_bdaddr,BDADDR_TYPE_STRING); A_RELEASE_FIRMWARE(firmware); diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.c b/drivers/staging/brcm80211/sys/wl_mac80211.c index bdd629d72a75..cd8392badff0 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.c +++ b/drivers/staging/brcm80211/sys/wl_mac80211.c @@ -209,11 +209,8 @@ static void wl_ops_stop(struct ieee80211_hw *hw) struct wl_info *wl = hw->priv; ASSERT(wl); WL_LOCK(wl); - wl_down(wl); ieee80211_stop_queues(hw); WL_UNLOCK(wl); - - return; } static int @@ -246,7 +243,14 @@ wl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) static void wl_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - return; + struct wl_info *wl; + + wl = HW_TO_WL(hw); + + /* put driver in down state */ + WL_LOCK(wl); + wl_down(wl); + WL_UNLOCK(wl); } static int @@ -259,9 +263,7 @@ ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan, switch (type) { case NL80211_CHAN_HT20: case NL80211_CHAN_NO_HT: - WL_LOCK(wl); err = wlc_set(wl->wlc, WLC_SET_CHANNEL, chan->hw_value); - WL_UNLOCK(wl); break; case NL80211_CHAN_HT40MINUS: case NL80211_CHAN_HT40PLUS: @@ -281,6 +283,7 @@ static int wl_ops_config(struct ieee80211_hw *hw, u32 changed) int err = 0; int new_int; + WL_LOCK(wl); if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { WL_NONE("%s: Setting listen interval to %d\n", __func__, conf->listen_interval); @@ -337,6 +340,7 @@ static int wl_ops_config(struct ieee80211_hw *hw, u32 changed) } config_out: + WL_UNLOCK(wl); return err; } @@ -455,13 +459,21 @@ wl_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) static void wl_ops_sw_scan_start(struct ieee80211_hw *hw) { + struct wl_info *wl = hw->priv; WL_NONE("Scan Start\n"); + WL_LOCK(wl); + wlc_scan_start(wl->wlc); + WL_UNLOCK(wl); return; } static void wl_ops_sw_scan_complete(struct ieee80211_hw *hw) { + struct wl_info *wl = hw->priv; WL_NONE("Scan Complete\n"); + WL_LOCK(wl); + wlc_scan_stop(wl->wlc); + WL_UNLOCK(wl); return; } @@ -779,7 +791,7 @@ static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs, wl_found++; return wl; - fail: +fail: wl_free(wl); fail1: return NULL; @@ -1090,7 +1102,6 @@ wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return 0; } -#ifdef LINUXSTA_PS static int wl_suspend(struct pci_dev *pdev, pm_message_t state) { struct wl_info *wl; @@ -1105,11 +1116,12 @@ static int wl_suspend(struct pci_dev *pdev, pm_message_t state) return -ENODEV; } + /* only need to flag hw is down for proper resume */ WL_LOCK(wl); - wl_down(wl); wl->pub->hw_up = false; WL_UNLOCK(wl); - pci_save_state(pdev, wl->pci_psstate); + + pci_save_state(pdev); pci_disable_device(pdev); return pci_set_power_state(pdev, PCI_D3hot); } @@ -1133,7 +1145,7 @@ static int wl_resume(struct pci_dev *pdev) if (err) return err; - pci_restore_state(pdev, wl->pci_psstate); + pci_restore_state(pdev); err = pci_enable_device(pdev); if (err) @@ -1145,13 +1157,12 @@ static int wl_resume(struct pci_dev *pdev) if ((val & 0x0000ff00) != 0) pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); - WL_LOCK(wl); - err = wl_up(wl); - WL_UNLOCK(wl); - + /* + * done. driver will be put in up state + * in wl_ops_add_interface() call. + */ return err; } -#endif /* LINUXSTA_PS */ static void wl_remove(struct pci_dev *pdev) { @@ -1184,14 +1195,12 @@ static void wl_remove(struct pci_dev *pdev) } static struct pci_driver wl_pci_driver = { - .name = "brcm80211", - .probe = wl_pci_probe, -#ifdef LINUXSTA_PS - .suspend = wl_suspend, - .resume = wl_resume, -#endif /* LINUXSTA_PS */ - .remove = __devexit_p(wl_remove), - .id_table = wl_id_table, + .name = "brcm80211", + .probe = wl_pci_probe, + .suspend = wl_suspend, + .resume = wl_resume, + .remove = __devexit_p(wl_remove), + .id_table = wl_id_table, }; /** diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index 1d5d01ac0a9b..e37e8058e2b8 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -5126,7 +5126,6 @@ wlc_sendpkt_mac80211(struct wlc_info *wlc, struct sk_buff *sdu, fifo = prio2fifo[prio]; ASSERT((uint) skb_headroom(sdu) >= TXOFF); - ASSERT(!(sdu->cloned)); ASSERT(!(sdu->next)); ASSERT(!(sdu->prev)); ASSERT(fifo < NFIFO); @@ -8462,3 +8461,16 @@ static void wlc_txq_free(struct wlc_info *wlc, struct osl_info *osh, kfree(qi); } + +/* + * Flag 'scan in progress' to withold dynamic phy calibration + */ +void wlc_scan_start(struct wlc_info *wlc) +{ + wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, true); +} + +void wlc_scan_stop(struct wlc_info *wlc) +{ + wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, false); +} diff --git a/drivers/staging/brcm80211/sys/wlc_pub.h b/drivers/staging/brcm80211/sys/wlc_pub.h index 146a6904a39b..aff413001b70 100644 --- a/drivers/staging/brcm80211/sys/wlc_pub.h +++ b/drivers/staging/brcm80211/sys/wlc_pub.h @@ -570,6 +570,8 @@ extern void wlc_enable_mac(struct wlc_info *wlc); extern u16 wlc_rate_shm_offset(struct wlc_info *wlc, u8 rate); extern u32 wlc_get_rspec_history(struct wlc_bsscfg *cfg); extern u32 wlc_get_current_highest_rate(struct wlc_bsscfg *cfg); +extern void wlc_scan_start(struct wlc_info *wlc); +extern void wlc_scan_stop(struct wlc_info *wlc); static inline int wlc_iovar_getuint(struct wlc_info *wlc, const char *name, uint *arg) diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index aad47326d6dc..1502d80f6f78 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -439,6 +439,7 @@ config COMEDI_NI_AT_AO config COMEDI_NI_ATMIO tristate "NI AT-MIO E series ISA-PNP card support" depends on ISAPNP && COMEDI_NI_TIO && COMEDI_NI_COMMON + select COMEDI_8255 default N ---help--- Enable support for National Instruments AT-MIO E series cards @@ -1040,6 +1041,8 @@ config COMEDI_NI_PCIDIO config COMEDI_NI_PCIMIO tristate "NI PCI-MIO-E series and M series support" depends on COMEDI_NI_TIO && COMEDI_NI_COMMON + select COMEDI_8255 + select COMEDI_FC default N ---help--- Enable support for National Instruments PCI-MIO-E series and M series @@ -1164,6 +1167,7 @@ config COMEDI_NI_LABPC_CS config COMEDI_NI_MIO_CS tristate "NI DAQCard E series PCMCIA support" depends on COMEDI_NI_TIO && COMEDI_NI_COMMON + select COMEDI_8255 select COMEDI_FC default N ---help--- @@ -1268,7 +1272,6 @@ config COMEDI_MITE config COMEDI_NI_TIO tristate "NI general purpose counter support" depends on COMEDI_MITE - select COMEDI_8255 default N ---help--- Enable support for National Instruments general purpose counters. diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c index cd25b241cc1f..fd274e9c7b78 100644 --- a/drivers/staging/comedi/drivers/mite.c +++ b/drivers/staging/comedi/drivers/mite.c @@ -61,8 +61,6 @@ #define PCI_DAQ_SIZE 4096 #define PCI_DAQ_SIZE_660X 8192 -MODULE_LICENSE("GPL"); - struct mite_struct *mite_devices; EXPORT_SYMBOL(mite_devices); diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c index 14e716e99a5c..54741c9e1af5 100644 --- a/drivers/staging/comedi/drivers/ni_6527.c +++ b/drivers/staging/comedi/drivers/ni_6527.c @@ -527,3 +527,7 @@ static void __exit driver_ni6527_cleanup_module(void) module_init(driver_ni6527_init_module); module_exit(driver_ni6527_cleanup_module); + +MODULE_AUTHOR("Comedi http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c index 8b8e2aaf77fb..403fc0997d37 100644 --- a/drivers/staging/comedi/drivers/ni_65xx.c +++ b/drivers/staging/comedi/drivers/ni_65xx.c @@ -871,3 +871,7 @@ static void __exit driver_ni_65xx_cleanup_module(void) module_init(driver_ni_65xx_init_module); module_exit(driver_ni_65xx_cleanup_module); + +MODULE_AUTHOR("Comedi http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c index 6612b085c4ef..ca2aeaa9449c 100644 --- a/drivers/staging/comedi/drivers/ni_660x.c +++ b/drivers/staging/comedi/drivers/ni_660x.c @@ -1421,3 +1421,7 @@ static int ni_660x_dio_insn_config(struct comedi_device *dev, }; return 0; } + +MODULE_AUTHOR("Comedi http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c index e9f034efdc6f..d8d91f90060e 100644 --- a/drivers/staging/comedi/drivers/ni_670x.c +++ b/drivers/staging/comedi/drivers/ni_670x.c @@ -384,3 +384,7 @@ static int ni_670x_find_device(struct comedi_device *dev, int bus, int slot) mite_list_devices(); return -EIO; } + +MODULE_AUTHOR("Comedi http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c index 4d1868d04bac..0728c3c0cb0e 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.c +++ b/drivers/staging/comedi/drivers/ni_labpc.c @@ -575,7 +575,8 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase, /* grab our IRQ */ if (irq) { isr_flags = 0; - if (thisboard->bustype == pci_bustype) + if (thisboard->bustype == pci_bustype + || thisboard->bustype == pcmcia_bustype) isr_flags |= IRQF_SHARED; if (request_irq(irq, labpc_interrupt, isr_flags, driver_labpc.driver_name, dev)) { diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c index 84a15c34e484..005d2fe86ee4 100644 --- a/drivers/staging/comedi/drivers/ni_pcidio.c +++ b/drivers/staging/comedi/drivers/ni_pcidio.c @@ -1354,3 +1354,7 @@ static void __exit driver_pcidio_cleanup_module(void) module_init(driver_pcidio_init_module); module_exit(driver_pcidio_cleanup_module); + +MODULE_AUTHOR("Comedi http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c index 23a381247285..9148abdad074 100644 --- a/drivers/staging/comedi/drivers/ni_pcimio.c +++ b/drivers/staging/comedi/drivers/ni_pcimio.c @@ -1853,3 +1853,7 @@ static int pcimio_dio_change(struct comedi_device *dev, return 0; } + +MODULE_AUTHOR("Comedi http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/hv/blkvsc_drv.c b/drivers/staging/hv/blkvsc_drv.c index b3d05fcfe6d2..4fb809485d9e 100644 --- a/drivers/staging/hv/blkvsc_drv.c +++ b/drivers/staging/hv/blkvsc_drv.c @@ -368,6 +368,7 @@ static int blkvsc_probe(struct device *device) blkdev->gd->first_minor = 0; blkdev->gd->fops = &block_ops; blkdev->gd->private_data = blkdev; + blkdev->gd->driverfs_dev = &(blkdev->device_ctx->device); sprintf(blkdev->gd->disk_name, "hd%c", 'a' + devnum); blkvsc_do_inquiry(blkdev); diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c index df9cd131e953..0edbe7483a4c 100644 --- a/drivers/staging/hv/netvsc.c +++ b/drivers/staging/hv/netvsc.c @@ -1279,7 +1279,7 @@ static void netvsc_channel_cb(void *context) /* ASSERT(device); */ packet = kzalloc(NETVSC_PACKET_SIZE * sizeof(unsigned char), - GFP_KERNEL); + GFP_ATOMIC); if (!packet) return; buffer = packet; diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c index 0147b407512c..b41c9640b72d 100644 --- a/drivers/staging/hv/netvsc_drv.c +++ b/drivers/staging/hv/netvsc_drv.c @@ -236,6 +236,7 @@ static void netvsc_linkstatus_callback(struct hv_device *device_obj, if (status == 1) { netif_carrier_on(net); netif_wake_queue(net); + netif_notify_peers(net); } else { netif_carrier_off(net); netif_stop_queue(net); @@ -358,7 +359,6 @@ static int netvsc_probe(struct device *device) /* Set initial state */ netif_carrier_off(net); - netif_stop_queue(net); net_device_ctx = netdev_priv(net); net_device_ctx->device_ctx = device_ctx; diff --git a/drivers/staging/iio/adc/ad7476_core.c b/drivers/staging/iio/adc/ad7476_core.c index deb68c8a6e18..b8b54da67c63 100644 --- a/drivers/staging/iio/adc/ad7476_core.c +++ b/drivers/staging/iio/adc/ad7476_core.c @@ -68,7 +68,7 @@ static ssize_t ad7476_show_scale(struct device *dev, /* Corresponds to Vref / 2^(bits) */ unsigned int scale_uv = (st->int_vref_mv * 1000) >> st->chip_info->bits; - return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000); + return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); } static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad7476_show_scale, NULL, 0); diff --git a/drivers/staging/iio/adc/ad7887_core.c b/drivers/staging/iio/adc/ad7887_core.c index 685908995d49..5d85efab658c 100644 --- a/drivers/staging/iio/adc/ad7887_core.c +++ b/drivers/staging/iio/adc/ad7887_core.c @@ -68,7 +68,7 @@ static ssize_t ad7887_show_scale(struct device *dev, /* Corresponds to Vref / 2^(bits) */ unsigned int scale_uv = (st->int_vref_mv * 1000) >> st->chip_info->bits; - return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000); + return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); } static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad7887_show_scale, NULL, 0); diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c index 6309d521a864..89ccf375a188 100644 --- a/drivers/staging/iio/adc/ad799x_core.c +++ b/drivers/staging/iio/adc/ad799x_core.c @@ -432,7 +432,7 @@ static ssize_t ad799x_show_scale(struct device *dev, /* Corresponds to Vref / 2^(bits) */ unsigned int scale_uv = (st->int_vref_mv * 1000) >> st->chip_info->bits; - return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000); + return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); } static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad799x_show_scale, NULL, 0); diff --git a/drivers/staging/iio/dac/ad5446.c b/drivers/staging/iio/dac/ad5446.c index e3387cd31145..0f87ecac82fc 100644 --- a/drivers/staging/iio/dac/ad5446.c +++ b/drivers/staging/iio/dac/ad5446.c @@ -87,7 +87,7 @@ static ssize_t ad5446_show_scale(struct device *dev, /* Corresponds to Vref / 2^(bits) */ unsigned int scale_uv = (st->vref_mv * 1000) >> st->chip_info->bits; - return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000); + return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); } static IIO_DEVICE_ATTR(out_scale, S_IRUGO, ad5446_show_scale, NULL, 0); diff --git a/drivers/staging/intel_sst/intelmid_v2_control.c b/drivers/staging/intel_sst/intelmid_v2_control.c index e38e89df6e84..e2f6d6a3c850 100644 --- a/drivers/staging/intel_sst/intelmid_v2_control.c +++ b/drivers/staging/intel_sst/intelmid_v2_control.c @@ -874,7 +874,10 @@ static int nc_set_selected_input_dev(u8 value) sc_access[3].reg_addr = 0x109; sc_access[3].mask = MASK6; sc_access[3].value = 0x00; - num_val = 4; + sc_access[4].reg_addr = 0x104; + sc_access[4].value = 0x3C; + sc_access[4].mask = 0xff; + num_val = 5; break; default: return -EINVAL; diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index 3fe5f4160194..0aad0d7a74a3 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -495,7 +495,7 @@ static int send_data_block(struct IR_tx *tx, unsigned char *data_block) /* send boot data to the IR TX device */ static int send_boot_data(struct IR_tx *tx) { - int ret; + int ret, i; unsigned char buf[4]; /* send the boot block */ @@ -503,7 +503,7 @@ static int send_boot_data(struct IR_tx *tx) if (ret != 0) return ret; - /* kick it off? */ + /* Hit the go button to activate the new boot data */ buf[0] = 0x00; buf[1] = 0x20; ret = i2c_master_send(tx->c, buf, 2); @@ -511,7 +511,19 @@ static int send_boot_data(struct IR_tx *tx) zilog_error("i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; } - ret = i2c_master_send(tx->c, buf, 1); + + /* + * Wait for zilog to settle after hitting go post boot block upload. + * Without this delay, the HD-PVR and HVR-1950 both return an -EIO + * upon attempting to get firmware revision, and tx probe thus fails. + */ + for (i = 0; i < 10; i++) { + ret = i2c_master_send(tx->c, buf, 1); + if (ret == 1) + break; + udelay(100); + } + if (ret != 1) { zilog_error("i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; @@ -523,8 +535,8 @@ static int send_boot_data(struct IR_tx *tx) zilog_error("i2c_master_recv failed with %d\n", ret); return 0; } - if (buf[0] != 0x80) { - zilog_error("unexpected IR TX response: %02x\n", buf[0]); + if ((buf[0] != 0x80) && (buf[0] != 0xa0)) { + zilog_error("unexpected IR TX init response: %02x\n", buf[0]); return 0; } zilog_notify("Zilog/Hauppauge IR blaster firmware version " @@ -827,7 +839,15 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) zilog_error("i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; } - ret = i2c_master_send(tx->c, buf, 1); + + /* Give the z8 a moment to process data block */ + for (i = 0; i < 10; i++) { + ret = i2c_master_send(tx->c, buf, 1); + if (ret == 1) + break; + udelay(100); + } + if (ret != 1) { zilog_error("i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; diff --git a/drivers/staging/msm/msm_fb.c b/drivers/staging/msm/msm_fb.c index 23fa049b51f2..a2f29d464051 100644 --- a/drivers/staging/msm/msm_fb.c +++ b/drivers/staging/msm/msm_fb.c @@ -347,7 +347,7 @@ static int msm_fb_suspend(struct platform_device *pdev, pm_message_t state) if ((!mfd) || (mfd->key != MFD_KEY)) return 0; - acquire_console_sem(); + console_lock(); fb_set_suspend(mfd->fbi, 1); ret = msm_fb_suspend_sub(mfd); @@ -358,7 +358,7 @@ static int msm_fb_suspend(struct platform_device *pdev, pm_message_t state) pdev->dev.power.power_state = state; } - release_console_sem(); + console_unlock(); return ret; } #else @@ -431,11 +431,11 @@ static int msm_fb_resume(struct platform_device *pdev) if ((!mfd) || (mfd->key != MFD_KEY)) return 0; - acquire_console_sem(); + console_lock(); ret = msm_fb_resume_sub(mfd); pdev->dev.power.power_state = PMSG_ON; fb_set_suspend(mfd->fbi, 1); - release_console_sem(); + console_unlock(); return ret; } diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c index 9f26dc9408bb..56a283d1a74d 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon.c +++ b/drivers/staging/olpc_dcon/olpc_dcon.c @@ -373,17 +373,17 @@ static void dcon_source_switch(struct work_struct *work) * * For now, we just hope.. */ - acquire_console_sem(); + console_lock(); ignore_fb_events = 1; if (fb_blank(fbinfo, FB_BLANK_UNBLANK)) { ignore_fb_events = 0; - release_console_sem(); + console_unlock(); printk(KERN_ERR "olpc-dcon: Failed to enter CPU mode\n"); dcon_pending = DCON_SOURCE_DCON; return; } ignore_fb_events = 0; - release_console_sem(); + console_unlock(); /* And turn off the DCON */ pdata->set_dconload(1); @@ -435,12 +435,12 @@ static void dcon_source_switch(struct work_struct *work) } } - acquire_console_sem(); + console_lock(); ignore_fb_events = 1; if (fb_blank(fbinfo, FB_BLANK_POWERDOWN)) printk(KERN_ERR "olpc-dcon: couldn't blank fb!\n"); ignore_fb_events = 0; - release_console_sem(); + console_unlock(); printk(KERN_INFO "olpc-dcon: The DCON has control\n"); break; diff --git a/drivers/staging/rt2860/rt_main_dev.c b/drivers/staging/rt2860/rt_main_dev.c index 701561d6b6fd..236dd36d349a 100644 --- a/drivers/staging/rt2860/rt_main_dev.c +++ b/drivers/staging/rt2860/rt_main_dev.c @@ -484,8 +484,6 @@ struct net_device *RtmpPhyNetDevInit(struct rt_rtmp_adapter *pAd, net_dev->ml_priv = (void *)pAd; pAd->net_dev = net_dev; - netif_stop_queue(net_dev); - return net_dev; } diff --git a/drivers/staging/rt2860/usb_main_dev.c b/drivers/staging/rt2860/usb_main_dev.c index ee68d51caa4e..322bf49ee906 100644 --- a/drivers/staging/rt2860/usb_main_dev.c +++ b/drivers/staging/rt2860/usb_main_dev.c @@ -106,6 +106,7 @@ struct usb_device_id rtusb_usb_id[] = { {USB_DEVICE(0x0411, 0x016f)}, /* MelCo.,Inc. WLI-UC-G301N */ {USB_DEVICE(0x1737, 0x0070)}, /* Linksys WUSB100 */ {USB_DEVICE(0x1737, 0x0071)}, /* Linksys WUSB600N */ + {USB_DEVICE(0x1737, 0x0078)}, /* Linksys WUSB100v2 */ {USB_DEVICE(0x0411, 0x00e8)}, /* Buffalo WLI-UC-G300N */ {USB_DEVICE(0x050d, 0x815c)}, /* Belkin F5D8053 */ {USB_DEVICE(0x100D, 0x9031)}, /* Motorola 2770 */ diff --git a/drivers/staging/rtl8712/hal_init.c b/drivers/staging/rtl8712/hal_init.c index 32088a641eba..84be383abec3 100644 --- a/drivers/staging/rtl8712/hal_init.c +++ b/drivers/staging/rtl8712/hal_init.c @@ -128,12 +128,13 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter) u8 *ptmpchar = NULL, *ppayload, *ptr; struct tx_desc *ptx_desc; u32 txdscp_sz = sizeof(struct tx_desc); + u8 ret = _FAIL; ulfilelength = rtl871x_open_fw(padapter, &phfwfile_hdl, &pmappedfw); if (pmappedfw && (ulfilelength > 0)) { update_fwhdr(&fwhdr, pmappedfw); if (chk_fwhdr(&fwhdr, ulfilelength) == _FAIL) - goto exit_fail; + goto firmware_rel; fill_fwpriv(padapter, &fwhdr.fwpriv); /* firmware check ok */ maxlen = (fwhdr.img_IMEM_size > fwhdr.img_SRAM_size) ? @@ -141,7 +142,7 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter) maxlen += txdscp_sz; ptmpchar = _malloc(maxlen + FWBUFF_ALIGN_SZ); if (ptmpchar == NULL) - return _FAIL; + goto firmware_rel; ptx_desc = (struct tx_desc *)(ptmpchar + FWBUFF_ALIGN_SZ - ((addr_t)(ptmpchar) & (FWBUFF_ALIGN_SZ - 1))); @@ -273,11 +274,13 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter) goto exit_fail; } else goto exit_fail; - return _SUCCESS; + ret = _SUCCESS; exit_fail: kfree(ptmpchar); - return _FAIL; +firmware_rel: + release_firmware((struct firmware *)phfwfile_hdl); + return ret; } uint rtl8712_hal_init(struct _adapter *padapter) diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c index a692ee88b9e9..21ce2af447b5 100644 --- a/drivers/staging/rtl8712/usb_intf.c +++ b/drivers/staging/rtl8712/usb_intf.c @@ -47,54 +47,123 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf, static void r871xu_dev_remove(struct usb_interface *pusb_intf); static struct usb_device_id rtl871x_usb_id_tbl[] = { - /*92SU - * Realtek */ - {USB_DEVICE(0x0bda, 0x8171)}, - {USB_DEVICE(0x0bda, 0x8172)}, + +/* RTL8188SU */ + /* Realtek */ + {USB_DEVICE(0x0BDA, 0x8171)}, {USB_DEVICE(0x0bda, 0x8173)}, - {USB_DEVICE(0x0bda, 0x8174)}, {USB_DEVICE(0x0bda, 0x8712)}, {USB_DEVICE(0x0bda, 0x8713)}, {USB_DEVICE(0x0bda, 0xC512)}, - /* Abocom */ + /* Abocom */ {USB_DEVICE(0x07B8, 0x8188)}, + /* ASUS */ + {USB_DEVICE(0x0B05, 0x1786)}, + {USB_DEVICE(0x0B05, 0x1791)}, /* 11n mode disable */ + /* Belkin */ + {USB_DEVICE(0x050D, 0x945A)}, /* Corega */ - {USB_DEVICE(0x07aa, 0x0047)}, - /* Dlink */ - {USB_DEVICE(0x07d1, 0x3303)}, - {USB_DEVICE(0x07d1, 0x3302)}, - {USB_DEVICE(0x07d1, 0x3300)}, - /* Dlink for Skyworth */ - {USB_DEVICE(0x14b2, 0x3300)}, - {USB_DEVICE(0x14b2, 0x3301)}, - {USB_DEVICE(0x14b2, 0x3302)}, + {USB_DEVICE(0x07AA, 0x0047)}, + /* D-Link */ + {USB_DEVICE(0x2001, 0x3306)}, + {USB_DEVICE(0x07D1, 0x3306)}, /* 11n mode disable */ + /* Edimax */ + {USB_DEVICE(0x7392, 0x7611)}, /* EnGenius */ {USB_DEVICE(0x1740, 0x9603)}, - {USB_DEVICE(0x1740, 0x9605)}, + /* Hawking */ + {USB_DEVICE(0x0E66, 0x0016)}, + /* Hercules */ + {USB_DEVICE(0x06F8, 0xE034)}, + {USB_DEVICE(0x06F8, 0xE032)}, + /* Logitec */ + {USB_DEVICE(0x0789, 0x0167)}, + /* PCI */ + {USB_DEVICE(0x2019, 0xAB28)}, + {USB_DEVICE(0x2019, 0xED16)}, + /* Sitecom */ + {USB_DEVICE(0x0DF6, 0x0057)}, + {USB_DEVICE(0x0DF6, 0x0045)}, + {USB_DEVICE(0x0DF6, 0x0059)}, /* 11n mode disable */ + {USB_DEVICE(0x0DF6, 0x004B)}, + {USB_DEVICE(0x0DF6, 0x0063)}, + /* Sweex */ + {USB_DEVICE(0x177F, 0x0154)}, + /* Thinkware */ + {USB_DEVICE(0x0BDA, 0x5077)}, + /* Toshiba */ + {USB_DEVICE(0x1690, 0x0752)}, + /* - */ + {USB_DEVICE(0x20F4, 0x646B)}, + {USB_DEVICE(0x083A, 0xC512)}, + +/* RTL8191SU */ + /* Realtek */ + {USB_DEVICE(0x0BDA, 0x8172)}, + /* Amigo */ + {USB_DEVICE(0x0EB0, 0x9061)}, + /* ASUS/EKB */ + {USB_DEVICE(0x0BDA, 0x8172)}, + {USB_DEVICE(0x13D3, 0x3323)}, + {USB_DEVICE(0x13D3, 0x3311)}, /* 11n mode disable */ + {USB_DEVICE(0x13D3, 0x3342)}, + /* ASUS/EKBLenovo */ + {USB_DEVICE(0x13D3, 0x3333)}, + {USB_DEVICE(0x13D3, 0x3334)}, + {USB_DEVICE(0x13D3, 0x3335)}, /* 11n mode disable */ + {USB_DEVICE(0x13D3, 0x3336)}, /* 11n mode disable */ + /* ASUS/Media BOX */ + {USB_DEVICE(0x13D3, 0x3309)}, /* Belkin */ - {USB_DEVICE(0x050d, 0x815F)}, - {USB_DEVICE(0x050d, 0x945A)}, - {USB_DEVICE(0x050d, 0x845A)}, - /* Guillemot */ - {USB_DEVICE(0x06f8, 0xe031)}, + {USB_DEVICE(0x050D, 0x815F)}, + /* D-Link */ + {USB_DEVICE(0x07D1, 0x3302)}, + {USB_DEVICE(0x07D1, 0x3300)}, + {USB_DEVICE(0x07D1, 0x3303)}, /* Edimax */ - {USB_DEVICE(0x7392, 0x7611)}, {USB_DEVICE(0x7392, 0x7612)}, - {USB_DEVICE(0x7392, 0x7622)}, - /* Sitecom */ - {USB_DEVICE(0x0DF6, 0x0045)}, + /* EnGenius */ + {USB_DEVICE(0x1740, 0x9605)}, + /* Guillemot */ + {USB_DEVICE(0x06F8, 0xE031)}, /* Hawking */ {USB_DEVICE(0x0E66, 0x0015)}, - {USB_DEVICE(0x0E66, 0x0016)}, - {USB_DEVICE(0x0b05, 0x1786)}, - {USB_DEVICE(0x0b05, 0x1791)}, /* 11n mode disable */ - + /* Mediao */ {USB_DEVICE(0x13D3, 0x3306)}, - {USB_DEVICE(0x13D3, 0x3309)}, + /* PCI */ + {USB_DEVICE(0x2019, 0xED18)}, + {USB_DEVICE(0x2019, 0x4901)}, + /* Sitecom */ + {USB_DEVICE(0x0DF6, 0x0058)}, + {USB_DEVICE(0x0DF6, 0x0049)}, + {USB_DEVICE(0x0DF6, 0x004C)}, + {USB_DEVICE(0x0DF6, 0x0064)}, + /* Skyworth */ + {USB_DEVICE(0x14b2, 0x3300)}, + {USB_DEVICE(0x14b2, 0x3301)}, + {USB_DEVICE(0x14B2, 0x3302)}, + /* - */ + {USB_DEVICE(0x04F2, 0xAFF2)}, + {USB_DEVICE(0x04F2, 0xAFF5)}, + {USB_DEVICE(0x04F2, 0xAFF6)}, + {USB_DEVICE(0x13D3, 0x3339)}, + {USB_DEVICE(0x13D3, 0x3340)}, /* 11n mode disable */ + {USB_DEVICE(0x13D3, 0x3341)}, /* 11n mode disable */ {USB_DEVICE(0x13D3, 0x3310)}, - {USB_DEVICE(0x13D3, 0x3311)}, /* 11n mode disable */ {USB_DEVICE(0x13D3, 0x3325)}, - {USB_DEVICE(0x083A, 0xC512)}, + +/* RTL8192SU */ + /* Realtek */ + {USB_DEVICE(0x0BDA, 0x8174)}, + {USB_DEVICE(0x0BDA, 0x8174)}, + /* Belkin */ + {USB_DEVICE(0x050D, 0x845A)}, + /* Corega */ + {USB_DEVICE(0x07AA, 0x0051)}, + /* Edimax */ + {USB_DEVICE(0x7392, 0x7622)}, + /* NEC */ + {USB_DEVICE(0x0409, 0x02B6)}, {} }; @@ -103,8 +172,20 @@ MODULE_DEVICE_TABLE(usb, rtl871x_usb_id_tbl); static struct specific_device_id specific_device_id_tbl[] = { {.idVendor = 0x0b05, .idProduct = 0x1791, .flags = SPEC_DEV_ID_DISABLE_HT}, + {.idVendor = 0x0df6, .idProduct = 0x0059, + .flags = SPEC_DEV_ID_DISABLE_HT}, + {.idVendor = 0x13d3, .idProduct = 0x3306, + .flags = SPEC_DEV_ID_DISABLE_HT}, {.idVendor = 0x13D3, .idProduct = 0x3311, .flags = SPEC_DEV_ID_DISABLE_HT}, + {.idVendor = 0x13d3, .idProduct = 0x3335, + .flags = SPEC_DEV_ID_DISABLE_HT}, + {.idVendor = 0x13d3, .idProduct = 0x3336, + .flags = SPEC_DEV_ID_DISABLE_HT}, + {.idVendor = 0x13d3, .idProduct = 0x3340, + .flags = SPEC_DEV_ID_DISABLE_HT}, + {.idVendor = 0x13d3, .idProduct = 0x3341, + .flags = SPEC_DEV_ID_DISABLE_HT}, {} }; diff --git a/drivers/staging/sm7xx/smtcfb.c b/drivers/staging/sm7xx/smtcfb.c index 0bc113c44d39..d007e4a12c14 100644 --- a/drivers/staging/sm7xx/smtcfb.c +++ b/drivers/staging/sm7xx/smtcfb.c @@ -1044,9 +1044,9 @@ static int __maybe_unused smtcfb_suspend(struct pci_dev *pdev, pm_message_t msg) /* when doing suspend, call fb apis and pci apis */ if (msg.event == PM_EVENT_SUSPEND) { - acquire_console_sem(); + console_lock(); fb_set_suspend(&sfb->fb, 1); - release_console_sem(); + console_unlock(); retv = pci_save_state(pdev); pci_disable_device(pdev); retv = pci_choose_state(pdev, msg); @@ -1105,9 +1105,9 @@ static int __maybe_unused smtcfb_resume(struct pci_dev *pdev) smtcfb_setmode(sfb); - acquire_console_sem(); + console_lock(); fb_set_suspend(&sfb->fb, 0); - release_console_sem(); + console_unlock(); return 0; } diff --git a/drivers/staging/speakup/kobjects.c b/drivers/staging/speakup/kobjects.c index 408bb9b3303e..07a7f5432597 100644 --- a/drivers/staging/speakup/kobjects.c +++ b/drivers/staging/speakup/kobjects.c @@ -332,7 +332,7 @@ static ssize_t silent_store(struct kobject *kobj, struct kobj_attribute *attr, unsigned long flags; len = strlen(buf); - if (len > 0 || len < 3) { + if (len > 0 && len < 3) { ch = buf[0]; if (ch == '\n') ch = '0'; diff --git a/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c index e8f047e86a32..80183a7e6624 100644 --- a/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c +++ b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c @@ -986,12 +986,6 @@ static int __devinit synaptics_rmi4_probe input_set_abs_params(rmi4_data->input_dev, ABS_MT_TOUCH_MAJOR, 0, MAX_TOUCH_MAJOR, 0, 0); - retval = input_register_device(rmi4_data->input_dev); - if (retval) { - dev_err(&client->dev, "%s:input register failed\n", __func__); - goto err_input_register; - } - /* Clear interrupts */ synaptics_rmi4_i2c_block_read(rmi4_data, rmi4_data->fn01_data_base_addr + 1, intr_status, @@ -1003,15 +997,20 @@ static int __devinit synaptics_rmi4_probe if (retval) { dev_err(&client->dev, "%s:Unable to get attn irq %d\n", __func__, platformdata->irq_number); - goto err_request_irq; + goto err_unset_clientdata; + } + + retval = input_register_device(rmi4_data->input_dev); + if (retval) { + dev_err(&client->dev, "%s:input register failed\n", __func__); + goto err_free_irq; } return retval; -err_request_irq: +err_free_irq: free_irq(platformdata->irq_number, rmi4_data); - input_unregister_device(rmi4_data->input_dev); -err_input_register: +err_unset_clientdata: i2c_set_clientdata(client, NULL); err_query_dev: if (platformdata->regulator_en) { diff --git a/drivers/staging/tidspbridge/core/io_sm.c b/drivers/staging/tidspbridge/core/io_sm.c index 571864555ddd..27e0aa81a584 100644 --- a/drivers/staging/tidspbridge/core/io_sm.c +++ b/drivers/staging/tidspbridge/core/io_sm.c @@ -949,7 +949,7 @@ func_end: * Calls the Bridge's CHNL_ISR to determine if this interrupt is ours, then * schedules a DPC to dispatch I/O. */ -void io_mbox_msg(u32 msg) +int io_mbox_msg(struct notifier_block *self, unsigned long len, void *msg) { struct io_mgr *pio_mgr; struct dev_object *dev_obj; @@ -959,9 +959,9 @@ void io_mbox_msg(u32 msg) dev_get_io_mgr(dev_obj, &pio_mgr); if (!pio_mgr) - return; + return NOTIFY_BAD; - pio_mgr->intr_val = (u16)msg; + pio_mgr->intr_val = (u16)((u32)msg); if (pio_mgr->intr_val & MBX_PM_CLASS) io_dispatch_pm(pio_mgr); @@ -973,7 +973,7 @@ void io_mbox_msg(u32 msg) spin_unlock_irqrestore(&pio_mgr->dpc_lock, flags); tasklet_schedule(&pio_mgr->dpc_tasklet); } - return; + return NOTIFY_OK; } /* diff --git a/drivers/staging/tidspbridge/core/tiomap3430.c b/drivers/staging/tidspbridge/core/tiomap3430.c index a3b0a183d570..a3f69f6f505f 100644 --- a/drivers/staging/tidspbridge/core/tiomap3430.c +++ b/drivers/staging/tidspbridge/core/tiomap3430.c @@ -223,6 +223,10 @@ static struct bridge_drv_interface drv_interface_fxns = { bridge_msg_set_queue_id, }; +static struct notifier_block dsp_mbox_notifier = { + .notifier_call = io_mbox_msg, +}; + static inline void flush_all(struct bridge_dev_context *dev_context) { if (dev_context->dw_brd_state == BRD_DSP_HIBERNATION || @@ -553,7 +557,7 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt, * Enable Mailbox events and also drain any pending * stale messages. */ - dev_context->mbox = omap_mbox_get("dsp"); + dev_context->mbox = omap_mbox_get("dsp", &dsp_mbox_notifier); if (IS_ERR(dev_context->mbox)) { dev_context->mbox = NULL; pr_err("%s: Failed to get dsp mailbox handle\n", @@ -563,8 +567,6 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt, } if (!status) { - dev_context->mbox->rxq->callback = (int (*)(void *))io_mbox_msg; - /*PM_IVA2GRPSEL_PER = 0xC0;*/ temp = readl(resources->dw_per_pm_base + 0xA8); temp = (temp & 0xFFFFFF30) | 0xC0; @@ -685,7 +687,7 @@ static int bridge_brd_stop(struct bridge_dev_context *dev_ctxt) /* Disable the mailbox interrupts */ if (dev_context->mbox) { omap_mbox_disable_irq(dev_context->mbox, IRQ_RX); - omap_mbox_put(dev_context->mbox); + omap_mbox_put(dev_context->mbox, &dsp_mbox_notifier); dev_context->mbox = NULL; } /* Reset IVA2 clocks*/ @@ -786,10 +788,7 @@ static int bridge_dev_create(struct bridge_dev_context pt_attrs = kzalloc(sizeof(struct pg_table_attrs), GFP_KERNEL); if (pt_attrs != NULL) { - /* Assuming that we use only DSP's memory map - * until 0x4000:0000 , we would need only 1024 - * L1 enties i.e L1 size = 4K */ - pt_attrs->l1_size = 0x1000; + pt_attrs->l1_size = SZ_16K; /* 4096 entries of 32 bits */ align_size = pt_attrs->l1_size; /* Align sizes are expected to be power of 2 */ /* we like to get aligned on L1 table size */ diff --git a/drivers/staging/tidspbridge/include/dspbridge/io_sm.h b/drivers/staging/tidspbridge/include/dspbridge/io_sm.h index 18aec55d8647..8242c70e09dd 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/io_sm.h +++ b/drivers/staging/tidspbridge/include/dspbridge/io_sm.h @@ -72,22 +72,17 @@ extern void io_dpc(unsigned long ref_data); /* * ======== io_mbox_msg ======== * Purpose: - * Main interrupt handler for the shared memory Bridge channel manager. - * Calls the Bridge's chnlsm_isr to determine if this interrupt is ours, - * then schedules a DPC to dispatch I/O. + * Main message handler for the shared memory Bridge channel manager. + * Determine if this message is ours, then schedules a DPC to + * dispatch I/O. * Parameters: - * ref_data: Pointer to the channel manager object for this board. - * Set in an initial call to ISR_Install(). + * self: Pointer to its own notifier_block struct. + * len: Length of message. + * msg: Message code received. * Returns: - * TRUE if interrupt handled; FALSE otherwise. - * Requires: - * Must be in locked memory if executing in kernel mode. - * Must only call functions which are in locked memory if Kernel mode. - * Must only call asynchronous services. - * Interrupts are disabled and EOI for this interrupt has been sent. - * Ensures: + * NOTIFY_OK if handled; NOTIFY_BAD otherwise. */ -void io_mbox_msg(u32 msg); +int io_mbox_msg(struct notifier_block *self, unsigned long len, void *msg); /* * ======== io_request_chnl ======== diff --git a/drivers/staging/usbip/stub.h b/drivers/staging/usbip/stub.h index 30dbfb6d16f2..d73267961ef4 100644 --- a/drivers/staging/usbip/stub.h +++ b/drivers/staging/usbip/stub.h @@ -32,6 +32,7 @@ struct stub_device { struct usb_interface *interface; + struct usb_device *udev; struct list_head list; struct usbip_device ud; diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c index b186b5fed2b9..a7ce51cc8909 100644 --- a/drivers/staging/usbip/stub_dev.c +++ b/drivers/staging/usbip/stub_dev.c @@ -258,10 +258,11 @@ static void stub_shutdown_connection(struct usbip_device *ud) static void stub_device_reset(struct usbip_device *ud) { struct stub_device *sdev = container_of(ud, struct stub_device, ud); - struct usb_device *udev = interface_to_usbdev(sdev->interface); + struct usb_device *udev = sdev->udev; int ret; usbip_udbg("device reset"); + ret = usb_lock_device_for_reset(udev, sdev->interface); if (ret < 0) { dev_err(&udev->dev, "lock for reset\n"); @@ -309,7 +310,8 @@ static void stub_device_unusable(struct usbip_device *ud) * * Allocates and initializes a new stub_device struct. */ -static struct stub_device *stub_device_alloc(struct usb_interface *interface) +static struct stub_device *stub_device_alloc(struct usb_device *udev, + struct usb_interface *interface) { struct stub_device *sdev; int busnum = interface_to_busnum(interface); @@ -324,7 +326,8 @@ static struct stub_device *stub_device_alloc(struct usb_interface *interface) return NULL; } - sdev->interface = interface; + sdev->interface = usb_get_intf(interface); + sdev->udev = usb_get_dev(udev); /* * devid is defined with devnum when this driver is first allocated. @@ -450,11 +453,12 @@ static int stub_probe(struct usb_interface *interface, return err; } + usb_get_intf(interface); return 0; } /* ok. this is my device. */ - sdev = stub_device_alloc(interface); + sdev = stub_device_alloc(udev, interface); if (!sdev) return -ENOMEM; @@ -476,6 +480,8 @@ static int stub_probe(struct usb_interface *interface, dev_err(&interface->dev, "create sysfs files for %s\n", udev_busid); usb_set_intfdata(interface, NULL); + usb_put_intf(interface); + busid_priv->interf_count = 0; busid_priv->sdev = NULL; @@ -545,6 +551,7 @@ static void stub_disconnect(struct usb_interface *interface) if (busid_priv->interf_count > 1) { busid_priv->interf_count--; shutdown_busid(busid_priv); + usb_put_intf(interface); return; } @@ -554,6 +561,9 @@ static void stub_disconnect(struct usb_interface *interface) /* 1. shutdown the current connection */ shutdown_busid(busid_priv); + usb_put_dev(sdev->udev); + usb_put_intf(interface); + /* 3. free sdev */ busid_priv->sdev = NULL; stub_device_free(sdev); diff --git a/drivers/staging/usbip/stub_rx.c b/drivers/staging/usbip/stub_rx.c index 3de6fd2539dc..ae6ac82754a4 100644 --- a/drivers/staging/usbip/stub_rx.c +++ b/drivers/staging/usbip/stub_rx.c @@ -364,7 +364,7 @@ static struct stub_priv *stub_priv_alloc(struct stub_device *sdev, static int get_pipe(struct stub_device *sdev, int epnum, int dir) { - struct usb_device *udev = interface_to_usbdev(sdev->interface); + struct usb_device *udev = sdev->udev; struct usb_host_endpoint *ep; struct usb_endpoint_descriptor *epd = NULL; @@ -484,7 +484,7 @@ static void stub_recv_cmd_submit(struct stub_device *sdev, int ret; struct stub_priv *priv; struct usbip_device *ud = &sdev->ud; - struct usb_device *udev = interface_to_usbdev(sdev->interface); + struct usb_device *udev = sdev->udev; int pipe = get_pipe(sdev, pdu->base.ep, pdu->base.direction); diff --git a/drivers/staging/usbip/vhci.h b/drivers/staging/usbip/vhci.h index 41a1fe5138f4..afc3b1a71881 100644 --- a/drivers/staging/usbip/vhci.h +++ b/drivers/staging/usbip/vhci.h @@ -100,9 +100,6 @@ struct vhci_hcd { * But, the index of this array begins from 0. */ struct vhci_device vdev[VHCI_NPORTS]; - - /* vhci_device which has not been assiged its address yet */ - int pending_port; }; @@ -119,6 +116,9 @@ void rh_port_disconnect(int rhport); void vhci_rx_loop(struct usbip_task *ut); void vhci_tx_loop(struct usbip_task *ut); +struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, + __u32 seqnum); + #define hardware (&the_controller->pdev.dev) static inline struct vhci_device *port_to_vdev(__u32 port) diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c index 08bd26a245d5..a35fe61268de 100644 --- a/drivers/staging/usbip/vhci_hcd.c +++ b/drivers/staging/usbip/vhci_hcd.c @@ -138,8 +138,6 @@ void rh_port_connect(int rhport, enum usb_device_speed speed) * the_controller->vdev[rhport].ud.status = VDEV_CONNECT; * spin_unlock(&the_controller->vdev[rhport].ud.lock); */ - the_controller->pending_port = rhport; - spin_unlock_irqrestore(&the_controller->lock, flags); usb_hcd_poll_rh_status(vhci_to_hcd(the_controller)); @@ -559,6 +557,7 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, struct device *dev = &urb->dev->dev; int ret = 0; unsigned long flags; + struct vhci_device *vdev; usbip_dbg_vhci_hc("enter, usb_hcd %p urb %p mem_flags %d\n", hcd, urb, mem_flags); @@ -574,6 +573,18 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, return urb->status; } + vdev = port_to_vdev(urb->dev->portnum-1); + + /* refuse enqueue for dead connection */ + spin_lock(&vdev->ud.lock); + if (vdev->ud.status == VDEV_ST_NULL || vdev->ud.status == VDEV_ST_ERROR) { + usbip_uerr("enqueue for inactive port %d\n", vdev->rhport); + spin_unlock(&vdev->ud.lock); + spin_unlock_irqrestore(&the_controller->lock, flags); + return -ENODEV; + } + spin_unlock(&vdev->ud.lock); + ret = usb_hcd_link_urb_to_ep(hcd, urb); if (ret) goto no_need_unlink; @@ -592,8 +603,6 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, __u8 type = usb_pipetype(urb->pipe); struct usb_ctrlrequest *ctrlreq = (struct usb_ctrlrequest *) urb->setup_packet; - struct vhci_device *vdev = - port_to_vdev(the_controller->pending_port); if (type != PIPE_CONTROL || !ctrlreq) { dev_err(dev, "invalid request to devnum 0\n"); @@ -607,7 +616,9 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, dev_info(dev, "SetAddress Request (%d) to port %d\n", ctrlreq->wValue, vdev->rhport); - vdev->udev = urb->dev; + if (vdev->udev) + usb_put_dev(vdev->udev); + vdev->udev = usb_get_dev(urb->dev); spin_lock(&vdev->ud.lock); vdev->ud.status = VDEV_ST_USED; @@ -627,8 +638,9 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, "Get_Descriptor to device 0 " "(get max pipe size)\n"); - /* FIXME: reference count? (usb_get_dev()) */ - vdev->udev = urb->dev; + if (vdev->udev) + usb_put_dev(vdev->udev); + vdev->udev = usb_get_dev(urb->dev); goto out; default: @@ -805,7 +817,6 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) return 0; } - static void vhci_device_unlink_cleanup(struct vhci_device *vdev) { struct vhci_unlink *unlink, *tmp; @@ -813,11 +824,34 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev) spin_lock(&vdev->priv_lock); list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) { + usbip_uinfo("unlink cleanup tx %lu\n", unlink->unlink_seqnum); list_del(&unlink->list); kfree(unlink); } list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) { + struct urb *urb; + + /* give back URB of unanswered unlink request */ + usbip_uinfo("unlink cleanup rx %lu\n", unlink->unlink_seqnum); + + urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum); + if (!urb) { + usbip_uinfo("the urb (seqnum %lu) was already given back\n", + unlink->unlink_seqnum); + list_del(&unlink->list); + kfree(unlink); + continue; + } + + urb->status = -ENODEV; + + spin_lock(&the_controller->lock); + usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb); + spin_unlock(&the_controller->lock); + + usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status); + list_del(&unlink->list); kfree(unlink); } @@ -887,6 +921,10 @@ static void vhci_device_reset(struct usbip_device *ud) vdev->speed = 0; vdev->devid = 0; + if (vdev->udev) + usb_put_dev(vdev->udev); + vdev->udev = NULL; + ud->tcp_socket = NULL; ud->status = VDEV_ST_NULL; diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c index 8147d7202b2d..bf6991470941 100644 --- a/drivers/staging/usbip/vhci_rx.c +++ b/drivers/staging/usbip/vhci_rx.c @@ -23,16 +23,14 @@ #include "vhci.h" -/* get URB from transmitted urb queue */ -static struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, +/* get URB from transmitted urb queue. caller must hold vdev->priv_lock */ +struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum) { struct vhci_priv *priv, *tmp; struct urb *urb = NULL; int status; - spin_lock(&vdev->priv_lock); - list_for_each_entry_safe(priv, tmp, &vdev->priv_rx, list) { if (priv->seqnum == seqnum) { urb = priv->urb; @@ -63,8 +61,6 @@ static struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, } } - spin_unlock(&vdev->priv_lock); - return urb; } @@ -74,9 +70,11 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev, struct usbip_device *ud = &vdev->ud; struct urb *urb; + spin_lock(&vdev->priv_lock); urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum); + spin_unlock(&vdev->priv_lock); if (!urb) { usbip_uerr("cannot find a urb of seqnum %u\n", @@ -161,7 +159,12 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev, return; } + spin_lock(&vdev->priv_lock); + urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum); + + spin_unlock(&vdev->priv_lock); + if (!urb) { /* * I get the result of a unlink request. But, it seems that I @@ -190,6 +193,19 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev, return; } +static int vhci_priv_tx_empty(struct vhci_device *vdev) +{ + int empty = 0; + + spin_lock(&vdev->priv_lock); + + empty = list_empty(&vdev->priv_rx); + + spin_unlock(&vdev->priv_lock); + + return empty; +} + /* recv a pdu */ static void vhci_rx_pdu(struct usbip_device *ud) { @@ -202,11 +218,29 @@ static void vhci_rx_pdu(struct usbip_device *ud) memset(&pdu, 0, sizeof(pdu)); - /* 1. receive a pdu header */ ret = usbip_xmit(0, ud->tcp_socket, (char *) &pdu, sizeof(pdu), 0); + if (ret < 0) { + if (ret == -ECONNRESET) + usbip_uinfo("connection reset by peer\n"); + else if (ret == -EAGAIN) { + /* ignore if connection was idle */ + if (vhci_priv_tx_empty(vdev)) + return; + usbip_uinfo("connection timed out with pending urbs\n"); + } else if (ret != -ERESTARTSYS) + usbip_uinfo("xmit failed %d\n", ret); + + usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); + return; + } + if (ret == 0) { + usbip_uinfo("connection closed"); + usbip_event_add(ud, VDEV_EVENT_DOWN); + return; + } if (ret != sizeof(pdu)) { - usbip_uerr("receiving pdu failed! size is %d, should be %d\n", + usbip_uerr("received pdu size is %d, should be %d\n", ret, (unsigned int)sizeof(pdu)); usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); return; diff --git a/drivers/staging/vme/bridges/Module.symvers b/drivers/staging/vme/bridges/Module.symvers deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/drivers/staging/vme/bridges/Module.symvers +++ /dev/null diff --git a/drivers/staging/xgifb/vb_setmode.c b/drivers/staging/xgifb/vb_setmode.c index 7016fdd2509f..e19b932492e1 100644 --- a/drivers/staging/xgifb/vb_setmode.c +++ b/drivers/staging/xgifb/vb_setmode.c @@ -3954,8 +3954,8 @@ void XGI_GetCRT2ResInfo(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned char XGI_IsLCDDualLink(struct vb_device_info *pVBInfo) { - if ((((pVBInfo->VBInfo & SetCRT2ToLCD) | SetCRT2ToLCDA)) - && (pVBInfo->LCDInfo & SetLCDDualLink)) /* shampoo0129 */ + if ((pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) && + (pVBInfo->LCDInfo & SetLCDDualLink)) /* shampoo0129 */ return 1; return 0; @@ -8773,7 +8773,7 @@ unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo, if (pVBInfo->IF_DEF_LVDS == 0) { CRT2Index = CRT2Index >> 6; /* for LCD */ - if (((pVBInfo->VBInfo & SetCRT2ToLCD) | SetCRT2ToLCDA)) { /*301b*/ + if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { /*301b*/ if (pVBInfo->LCDResInfo != Panel1024x768) VCLKIndex = LCDXlat2VCLK[CRT2Index]; else diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c index 5415712f01f8..4bd8cbdaee76 100644 --- a/drivers/staging/zram/zram_drv.c +++ b/drivers/staging/zram/zram_drv.c @@ -227,6 +227,7 @@ static int zram_read(struct zram *zram, struct bio *bio) if (zram_test_flag(zram, index, ZRAM_ZERO)) { handle_zero_page(page); + index++; continue; } @@ -235,12 +236,14 @@ static int zram_read(struct zram *zram, struct bio *bio) pr_debug("Read before write: sector=%lu, size=%u", (ulong)(bio->bi_sector), bio->bi_size); /* Do nothing */ + index++; continue; } /* Page is stored uncompressed since it's incompressible */ if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) { handle_uncompressed_page(zram, page, index); + index++; continue; } @@ -320,6 +323,7 @@ static int zram_write(struct zram *zram, struct bio *bio) mutex_unlock(&zram->lock); zram_stat_inc(&zram->stats.pages_zero); zram_set_flag(zram, index, ZRAM_ZERO); + index++; continue; } diff --git a/drivers/target/Makefile b/drivers/target/Makefile index 5cfd70819f08..973bb190ef57 100644 --- a/drivers/target/Makefile +++ b/drivers/target/Makefile @@ -13,8 +13,7 @@ target_core_mod-y := target_core_configfs.o \ target_core_transport.o \ target_core_cdb.o \ target_core_ua.o \ - target_core_rd.o \ - target_core_mib.o + target_core_rd.o obj-$(CONFIG_TARGET_CORE) += target_core_mod.o diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 2764510798b0..caf8dc18ee0a 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -37,7 +37,6 @@ #include <linux/parser.h> #include <linux/syscalls.h> #include <linux/configfs.h> -#include <linux/proc_fs.h> #include <target/target_core_base.h> #include <target/target_core_device.h> @@ -1971,13 +1970,35 @@ static void target_core_dev_release(struct config_item *item) { struct se_subsystem_dev *se_dev = container_of(to_config_group(item), struct se_subsystem_dev, se_dev_group); - struct config_group *dev_cg; - - if (!(se_dev)) - return; + struct se_hba *hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item); + struct se_subsystem_api *t = hba->transport; + struct config_group *dev_cg = &se_dev->se_dev_group; - dev_cg = &se_dev->se_dev_group; kfree(dev_cg->default_groups); + /* + * This pointer will set when the storage is enabled with: + *`echo 1 > $CONFIGFS/core/$HBA/$DEV/dev_enable` + */ + if (se_dev->se_dev_ptr) { + printk(KERN_INFO "Target_Core_ConfigFS: Calling se_free_" + "virtual_device() for se_dev_ptr: %p\n", + se_dev->se_dev_ptr); + + se_free_virtual_device(se_dev->se_dev_ptr, hba); + } else { + /* + * Release struct se_subsystem_dev->se_dev_su_ptr.. + */ + printk(KERN_INFO "Target_Core_ConfigFS: Calling t->free_" + "device() for se_dev_su_ptr: %p\n", + se_dev->se_dev_su_ptr); + + t->free_device(se_dev->se_dev_su_ptr); + } + + printk(KERN_INFO "Target_Core_ConfigFS: Deallocating se_subsystem" + "_dev_t: %p\n", se_dev); + kfree(se_dev); } static ssize_t target_core_dev_show(struct config_item *item, @@ -2140,7 +2161,16 @@ static struct configfs_attribute *target_core_alua_lu_gp_attrs[] = { NULL, }; +static void target_core_alua_lu_gp_release(struct config_item *item) +{ + struct t10_alua_lu_gp *lu_gp = container_of(to_config_group(item), + struct t10_alua_lu_gp, lu_gp_group); + + core_alua_free_lu_gp(lu_gp); +} + static struct configfs_item_operations target_core_alua_lu_gp_ops = { + .release = target_core_alua_lu_gp_release, .show_attribute = target_core_alua_lu_gp_attr_show, .store_attribute = target_core_alua_lu_gp_attr_store, }; @@ -2191,9 +2221,11 @@ static void target_core_alua_drop_lu_gp( printk(KERN_INFO "Target_Core_ConfigFS: Releasing ALUA Logical Unit" " Group: core/alua/lu_gps/%s, ID: %hu\n", config_item_name(item), lu_gp->lu_gp_id); - + /* + * core_alua_free_lu_gp() is called from target_core_alua_lu_gp_ops->release() + * -> target_core_alua_lu_gp_release() + */ config_item_put(item); - core_alua_free_lu_gp(lu_gp); } static struct configfs_group_operations target_core_alua_lu_gps_group_ops = { @@ -2549,7 +2581,16 @@ static struct configfs_attribute *target_core_alua_tg_pt_gp_attrs[] = { NULL, }; +static void target_core_alua_tg_pt_gp_release(struct config_item *item) +{ + struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(to_config_group(item), + struct t10_alua_tg_pt_gp, tg_pt_gp_group); + + core_alua_free_tg_pt_gp(tg_pt_gp); +} + static struct configfs_item_operations target_core_alua_tg_pt_gp_ops = { + .release = target_core_alua_tg_pt_gp_release, .show_attribute = target_core_alua_tg_pt_gp_attr_show, .store_attribute = target_core_alua_tg_pt_gp_attr_store, }; @@ -2602,9 +2643,11 @@ static void target_core_alua_drop_tg_pt_gp( printk(KERN_INFO "Target_Core_ConfigFS: Releasing ALUA Target Port" " Group: alua/tg_pt_gps/%s, ID: %hu\n", config_item_name(item), tg_pt_gp->tg_pt_gp_id); - + /* + * core_alua_free_tg_pt_gp() is called from target_core_alua_tg_pt_gp_ops->release() + * -> target_core_alua_tg_pt_gp_release(). + */ config_item_put(item); - core_alua_free_tg_pt_gp(tg_pt_gp); } static struct configfs_group_operations target_core_alua_tg_pt_gps_group_ops = { @@ -2771,13 +2814,11 @@ static void target_core_drop_subdev( struct se_subsystem_api *t; struct config_item *df_item; struct config_group *dev_cg, *tg_pt_gp_cg; - int i, ret; + int i; hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item); - if (mutex_lock_interruptible(&hba->hba_access_mutex)) - goto out; - + mutex_lock(&hba->hba_access_mutex); t = hba->transport; spin_lock(&se_global->g_device_lock); @@ -2791,7 +2832,10 @@ static void target_core_drop_subdev( config_item_put(df_item); } kfree(tg_pt_gp_cg->default_groups); - core_alua_free_tg_pt_gp(T10_ALUA(se_dev)->default_tg_pt_gp); + /* + * core_alua_free_tg_pt_gp() is called from ->default_tg_pt_gp + * directly from target_core_alua_tg_pt_gp_release(). + */ T10_ALUA(se_dev)->default_tg_pt_gp = NULL; dev_cg = &se_dev->se_dev_group; @@ -2800,38 +2844,12 @@ static void target_core_drop_subdev( dev_cg->default_groups[i] = NULL; config_item_put(df_item); } - - config_item_put(item); /* - * This pointer will set when the storage is enabled with: - * `echo 1 > $CONFIGFS/core/$HBA/$DEV/dev_enable` + * The releasing of se_dev and associated se_dev->se_dev_ptr is done + * from target_core_dev_item_ops->release() ->target_core_dev_release(). */ - if (se_dev->se_dev_ptr) { - printk(KERN_INFO "Target_Core_ConfigFS: Calling se_free_" - "virtual_device() for se_dev_ptr: %p\n", - se_dev->se_dev_ptr); - - ret = se_free_virtual_device(se_dev->se_dev_ptr, hba); - if (ret < 0) - goto hba_out; - } else { - /* - * Release struct se_subsystem_dev->se_dev_su_ptr.. - */ - printk(KERN_INFO "Target_Core_ConfigFS: Calling t->free_" - "device() for se_dev_su_ptr: %p\n", - se_dev->se_dev_su_ptr); - - t->free_device(se_dev->se_dev_su_ptr); - } - - printk(KERN_INFO "Target_Core_ConfigFS: Deallocating se_subsystem" - "_dev_t: %p\n", se_dev); - -hba_out: + config_item_put(item); mutex_unlock(&hba->hba_access_mutex); -out: - kfree(se_dev); } static struct configfs_group_operations target_core_hba_group_ops = { @@ -2914,6 +2932,13 @@ SE_HBA_ATTR(hba_mode, S_IRUGO | S_IWUSR); CONFIGFS_EATTR_OPS(target_core_hba, se_hba, hba_group); +static void target_core_hba_release(struct config_item *item) +{ + struct se_hba *hba = container_of(to_config_group(item), + struct se_hba, hba_group); + core_delete_hba(hba); +} + static struct configfs_attribute *target_core_hba_attrs[] = { &target_core_hba_hba_info.attr, &target_core_hba_hba_mode.attr, @@ -2921,6 +2946,7 @@ static struct configfs_attribute *target_core_hba_attrs[] = { }; static struct configfs_item_operations target_core_hba_item_ops = { + .release = target_core_hba_release, .show_attribute = target_core_hba_attr_show, .store_attribute = target_core_hba_attr_store, }; @@ -2997,10 +3023,11 @@ static void target_core_call_delhbafromtarget( struct config_group *group, struct config_item *item) { - struct se_hba *hba = item_to_hba(item); - + /* + * core_delete_hba() is called from target_core_hba_item_ops->release() + * -> target_core_hba_release() + */ config_item_put(item); - core_delete_hba(hba); } static struct configfs_group_operations target_core_group_ops = { @@ -3022,7 +3049,6 @@ static int target_core_init_configfs(void) struct config_group *target_cg, *hba_cg = NULL, *alua_cg = NULL; struct config_group *lu_gp_cg = NULL; struct configfs_subsystem *subsys; - struct proc_dir_entry *scsi_target_proc = NULL; struct t10_alua_lu_gp *lu_gp; int ret; @@ -3128,21 +3154,10 @@ static int target_core_init_configfs(void) if (core_dev_setup_virtual_lun0() < 0) goto out; - scsi_target_proc = proc_mkdir("scsi_target", 0); - if (!(scsi_target_proc)) { - printk(KERN_ERR "proc_mkdir(scsi_target, 0) failed\n"); - goto out; - } - ret = init_scsi_target_mib(); - if (ret < 0) - goto out; - return 0; out: configfs_unregister_subsystem(subsys); - if (scsi_target_proc) - remove_proc_entry("scsi_target", 0); core_dev_release_virtual_lun0(); rd_module_exit(); out_global: @@ -3178,8 +3193,7 @@ static void target_core_exit_configfs(void) config_item_put(item); } kfree(lu_gp_cg->default_groups); - core_alua_free_lu_gp(se_global->default_lu_gp); - se_global->default_lu_gp = NULL; + lu_gp_cg->default_groups = NULL; alua_cg = &se_global->alua_group; for (i = 0; alua_cg->default_groups[i]; i++) { @@ -3188,6 +3202,7 @@ static void target_core_exit_configfs(void) config_item_put(item); } kfree(alua_cg->default_groups); + alua_cg->default_groups = NULL; hba_cg = &se_global->target_core_hbagroup; for (i = 0; hba_cg->default_groups[i]; i++) { @@ -3196,20 +3211,20 @@ static void target_core_exit_configfs(void) config_item_put(item); } kfree(hba_cg->default_groups); - - for (i = 0; subsys->su_group.default_groups[i]; i++) { - item = &subsys->su_group.default_groups[i]->cg_item; - subsys->su_group.default_groups[i] = NULL; - config_item_put(item); - } + hba_cg->default_groups = NULL; + /* + * We expect subsys->su_group.default_groups to be released + * by configfs subsystem provider logic.. + */ + configfs_unregister_subsystem(subsys); kfree(subsys->su_group.default_groups); - configfs_unregister_subsystem(subsys); + core_alua_free_lu_gp(se_global->default_lu_gp); + se_global->default_lu_gp = NULL; + printk(KERN_INFO "TARGET_CORE[0]: Released ConfigFS Fabric" " Infrastructure\n"); - remove_scsi_target_mib(); - remove_proc_entry("scsi_target", 0); core_dev_release_virtual_lun0(); rd_module_exit(); release_se_global(); diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 317ce58d426d..5da051a07fa3 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -373,11 +373,11 @@ int core_update_device_list_for_node( /* * deve->se_lun_acl will be NULL for demo-mode created LUNs * that have not been explictly concerted to MappedLUNs -> - * struct se_lun_acl. + * struct se_lun_acl, but we remove deve->alua_port_list from + * port->sep_alua_list. This also means that active UAs and + * NodeACL context specific PR metadata for demo-mode + * MappedLUN *deve will be released below.. */ - if (!(deve->se_lun_acl)) - return 0; - spin_lock_bh(&port->sep_alua_lock); list_del(&deve->alua_port_list); spin_unlock_bh(&port->sep_alua_lock); @@ -395,12 +395,14 @@ int core_update_device_list_for_node( printk(KERN_ERR "struct se_dev_entry->se_lun_acl" " already set for demo mode -> explict" " LUN ACL transition\n"); + spin_unlock_irq(&nacl->device_list_lock); return -1; } if (deve->se_lun != lun) { printk(KERN_ERR "struct se_dev_entry->se_lun does" " match passed struct se_lun for demo mode" " -> explict LUN ACL transition\n"); + spin_unlock_irq(&nacl->device_list_lock); return -1; } deve->se_lun_acl = lun_acl; @@ -865,9 +867,6 @@ static void se_dev_stop(struct se_device *dev) } } spin_unlock(&hba->device_lock); - - while (atomic_read(&hba->dev_mib_access_count)) - cpu_relax(); } int se_dev_check_online(struct se_device *dev) diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 32b148d7e261..b65d1c8e7740 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -214,12 +214,22 @@ TCM_MAPPEDLUN_ATTR(write_protect, S_IRUGO | S_IWUSR); CONFIGFS_EATTR_OPS(target_fabric_mappedlun, se_lun_acl, se_lun_group); +static void target_fabric_mappedlun_release(struct config_item *item) +{ + struct se_lun_acl *lacl = container_of(to_config_group(item), + struct se_lun_acl, se_lun_group); + struct se_portal_group *se_tpg = lacl->se_lun_nacl->se_tpg; + + core_dev_free_initiator_node_lun_acl(se_tpg, lacl); +} + static struct configfs_attribute *target_fabric_mappedlun_attrs[] = { &target_fabric_mappedlun_write_protect.attr, NULL, }; static struct configfs_item_operations target_fabric_mappedlun_item_ops = { + .release = target_fabric_mappedlun_release, .show_attribute = target_fabric_mappedlun_attr_show, .store_attribute = target_fabric_mappedlun_attr_store, .allow_link = target_fabric_mappedlun_link, @@ -337,15 +347,21 @@ static void target_fabric_drop_mappedlun( struct config_group *group, struct config_item *item) { - struct se_lun_acl *lacl = container_of(to_config_group(item), - struct se_lun_acl, se_lun_group); - struct se_portal_group *se_tpg = lacl->se_lun_nacl->se_tpg; - config_item_put(item); - core_dev_free_initiator_node_lun_acl(se_tpg, lacl); +} + +static void target_fabric_nacl_base_release(struct config_item *item) +{ + struct se_node_acl *se_nacl = container_of(to_config_group(item), + struct se_node_acl, acl_group); + struct se_portal_group *se_tpg = se_nacl->se_tpg; + struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; + + tf->tf_ops.fabric_drop_nodeacl(se_nacl); } static struct configfs_item_operations target_fabric_nacl_base_item_ops = { + .release = target_fabric_nacl_base_release, .show_attribute = target_fabric_nacl_base_attr_show, .store_attribute = target_fabric_nacl_base_attr_store, }; @@ -404,9 +420,6 @@ static void target_fabric_drop_nodeacl( struct config_group *group, struct config_item *item) { - struct se_portal_group *se_tpg = container_of(group, - struct se_portal_group, tpg_acl_group); - struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; struct se_node_acl *se_nacl = container_of(to_config_group(item), struct se_node_acl, acl_group); struct config_item *df_item; @@ -419,9 +432,10 @@ static void target_fabric_drop_nodeacl( nacl_cg->default_groups[i] = NULL; config_item_put(df_item); } - + /* + * struct se_node_acl free is done in target_fabric_nacl_base_release() + */ config_item_put(item); - tf->tf_ops.fabric_drop_nodeacl(se_nacl); } static struct configfs_group_operations target_fabric_nacl_group_ops = { @@ -437,7 +451,18 @@ TF_CIT_SETUP(tpg_nacl, NULL, &target_fabric_nacl_group_ops, NULL); CONFIGFS_EATTR_OPS(target_fabric_np_base, se_tpg_np, tpg_np_group); +static void target_fabric_np_base_release(struct config_item *item) +{ + struct se_tpg_np *se_tpg_np = container_of(to_config_group(item), + struct se_tpg_np, tpg_np_group); + struct se_portal_group *se_tpg = se_tpg_np->tpg_np_parent; + struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; + + tf->tf_ops.fabric_drop_np(se_tpg_np); +} + static struct configfs_item_operations target_fabric_np_base_item_ops = { + .release = target_fabric_np_base_release, .show_attribute = target_fabric_np_base_attr_show, .store_attribute = target_fabric_np_base_attr_store, }; @@ -466,6 +491,7 @@ static struct config_group *target_fabric_make_np( if (!(se_tpg_np) || IS_ERR(se_tpg_np)) return ERR_PTR(-EINVAL); + se_tpg_np->tpg_np_parent = se_tpg; config_group_init_type_name(&se_tpg_np->tpg_np_group, name, &TF_CIT_TMPL(tf)->tfc_tpg_np_base_cit); @@ -476,14 +502,10 @@ static void target_fabric_drop_np( struct config_group *group, struct config_item *item) { - struct se_portal_group *se_tpg = container_of(group, - struct se_portal_group, tpg_np_group); - struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; - struct se_tpg_np *se_tpg_np = container_of(to_config_group(item), - struct se_tpg_np, tpg_np_group); - + /* + * struct se_tpg_np is released via target_fabric_np_base_release() + */ config_item_put(item); - tf->tf_ops.fabric_drop_np(se_tpg_np); } static struct configfs_group_operations target_fabric_np_group_ops = { @@ -814,7 +836,18 @@ TF_CIT_SETUP(tpg_param, &target_fabric_tpg_param_item_ops, NULL, NULL); */ CONFIGFS_EATTR_OPS(target_fabric_tpg, se_portal_group, tpg_group); +static void target_fabric_tpg_release(struct config_item *item) +{ + struct se_portal_group *se_tpg = container_of(to_config_group(item), + struct se_portal_group, tpg_group); + struct se_wwn *wwn = se_tpg->se_tpg_wwn; + struct target_fabric_configfs *tf = wwn->wwn_tf; + + tf->tf_ops.fabric_drop_tpg(se_tpg); +} + static struct configfs_item_operations target_fabric_tpg_base_item_ops = { + .release = target_fabric_tpg_release, .show_attribute = target_fabric_tpg_attr_show, .store_attribute = target_fabric_tpg_attr_store, }; @@ -872,8 +905,6 @@ static void target_fabric_drop_tpg( struct config_group *group, struct config_item *item) { - struct se_wwn *wwn = container_of(group, struct se_wwn, wwn_group); - struct target_fabric_configfs *tf = wwn->wwn_tf; struct se_portal_group *se_tpg = container_of(to_config_group(item), struct se_portal_group, tpg_group); struct config_group *tpg_cg = &se_tpg->tpg_group; @@ -890,15 +921,28 @@ static void target_fabric_drop_tpg( } config_item_put(item); - tf->tf_ops.fabric_drop_tpg(se_tpg); } +static void target_fabric_release_wwn(struct config_item *item) +{ + struct se_wwn *wwn = container_of(to_config_group(item), + struct se_wwn, wwn_group); + struct target_fabric_configfs *tf = wwn->wwn_tf; + + tf->tf_ops.fabric_drop_wwn(wwn); +} + +static struct configfs_item_operations target_fabric_tpg_item_ops = { + .release = target_fabric_release_wwn, +}; + static struct configfs_group_operations target_fabric_tpg_group_ops = { .make_group = target_fabric_make_tpg, .drop_item = target_fabric_drop_tpg, }; -TF_CIT_SETUP(tpg, NULL, &target_fabric_tpg_group_ops, NULL); +TF_CIT_SETUP(tpg, &target_fabric_tpg_item_ops, &target_fabric_tpg_group_ops, + NULL); /* End of tfc_tpg_cit */ @@ -932,13 +976,7 @@ static void target_fabric_drop_wwn( struct config_group *group, struct config_item *item) { - struct target_fabric_configfs *tf = container_of(group, - struct target_fabric_configfs, tf_group); - struct se_wwn *wwn = container_of(to_config_group(item), - struct se_wwn, wwn_group); - config_item_put(item); - tf->tf_ops.fabric_drop_wwn(wwn); } static struct configfs_group_operations target_fabric_wwn_group_ops = { diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index c6e0d757e76e..67f0c09983c8 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -154,7 +154,7 @@ static struct se_device *iblock_create_virtdevice( bd = blkdev_get_by_path(ib_dev->ibd_udev_path, FMODE_WRITE|FMODE_READ|FMODE_EXCL, ib_dev); - if (!(bd)) + if (IS_ERR(bd)) goto failed; /* * Setup the local scope queue_limits from struct request_queue->limits @@ -220,8 +220,10 @@ static void iblock_free_device(void *p) { struct iblock_dev *ib_dev = p; - blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL); - bioset_free(ib_dev->ibd_bio_set); + if (ib_dev->ibd_bd != NULL) + blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL); + if (ib_dev->ibd_bio_set != NULL) + bioset_free(ib_dev->ibd_bio_set); kfree(ib_dev); } diff --git a/drivers/target/target_core_mib.c b/drivers/target/target_core_mib.c deleted file mode 100644 index d5a48aa0d2d1..000000000000 --- a/drivers/target/target_core_mib.c +++ /dev/null @@ -1,1078 +0,0 @@ -/******************************************************************************* - * Filename: target_core_mib.c - * - * Copyright (c) 2006-2007 SBE, Inc. All Rights Reserved. - * Copyright (c) 2007-2010 Rising Tide Systems - * Copyright (c) 2008-2010 Linux-iSCSI.org - * - * Nicholas A. Bellinger <nab@linux-iscsi.org> - * - * 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/kernel.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/string.h> -#include <linux/version.h> -#include <generated/utsrelease.h> -#include <linux/utsname.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/blkdev.h> -#include <scsi/scsi.h> -#include <scsi/scsi_device.h> -#include <scsi/scsi_host.h> - -#include <target/target_core_base.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> -#include <target/target_core_configfs.h> - -#include "target_core_hba.h" -#include "target_core_mib.h" - -/* SCSI mib table index */ -static struct scsi_index_table scsi_index_table; - -#ifndef INITIAL_JIFFIES -#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ)) -#endif - -/* SCSI Instance Table */ -#define SCSI_INST_SW_INDEX 1 -#define SCSI_TRANSPORT_INDEX 1 - -#define NONE "None" -#define ISPRINT(a) ((a >= ' ') && (a <= '~')) - -static inline int list_is_first(const struct list_head *list, - const struct list_head *head) -{ - return list->prev == head; -} - -static void *locate_hba_start( - struct seq_file *seq, - loff_t *pos) -{ - spin_lock(&se_global->g_device_lock); - return seq_list_start(&se_global->g_se_dev_list, *pos); -} - -static void *locate_hba_next( - struct seq_file *seq, - void *v, - loff_t *pos) -{ - return seq_list_next(v, &se_global->g_se_dev_list, pos); -} - -static void locate_hba_stop(struct seq_file *seq, void *v) -{ - spin_unlock(&se_global->g_device_lock); -} - -/**************************************************************************** - * SCSI MIB Tables - ****************************************************************************/ - -/* - * SCSI Instance Table - */ -static void *scsi_inst_seq_start( - struct seq_file *seq, - loff_t *pos) -{ - spin_lock(&se_global->hba_lock); - return seq_list_start(&se_global->g_hba_list, *pos); -} - -static void *scsi_inst_seq_next( - struct seq_file *seq, - void *v, - loff_t *pos) -{ - return seq_list_next(v, &se_global->g_hba_list, pos); -} - -static void scsi_inst_seq_stop(struct seq_file *seq, void *v) -{ - spin_unlock(&se_global->hba_lock); -} - -static int scsi_inst_seq_show(struct seq_file *seq, void *v) -{ - struct se_hba *hba = list_entry(v, struct se_hba, hba_list); - - if (list_is_first(&hba->hba_list, &se_global->g_hba_list)) - seq_puts(seq, "inst sw_indx\n"); - - seq_printf(seq, "%u %u\n", hba->hba_index, SCSI_INST_SW_INDEX); - seq_printf(seq, "plugin: %s version: %s\n", - hba->transport->name, TARGET_CORE_VERSION); - - return 0; -} - -static const struct seq_operations scsi_inst_seq_ops = { - .start = scsi_inst_seq_start, - .next = scsi_inst_seq_next, - .stop = scsi_inst_seq_stop, - .show = scsi_inst_seq_show -}; - -static int scsi_inst_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &scsi_inst_seq_ops); -} - -static const struct file_operations scsi_inst_seq_fops = { - .owner = THIS_MODULE, - .open = scsi_inst_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * SCSI Device Table - */ -static void *scsi_dev_seq_start(struct seq_file *seq, loff_t *pos) -{ - return locate_hba_start(seq, pos); -} - -static void *scsi_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return locate_hba_next(seq, v, pos); -} - -static void scsi_dev_seq_stop(struct seq_file *seq, void *v) -{ - locate_hba_stop(seq, v); -} - -static int scsi_dev_seq_show(struct seq_file *seq, void *v) -{ - struct se_hba *hba; - struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, - g_se_dev_list); - struct se_device *dev = se_dev->se_dev_ptr; - char str[28]; - int k; - - if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) - seq_puts(seq, "inst indx role ports\n"); - - if (!(dev)) - return 0; - - hba = dev->se_hba; - if (!(hba)) { - /* Log error ? */ - return 0; - } - - seq_printf(seq, "%u %u %s %u\n", hba->hba_index, - dev->dev_index, "Target", dev->dev_port_count); - - memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28); - - /* vendor */ - for (k = 0; k < 8; k++) - str[k] = ISPRINT(DEV_T10_WWN(dev)->vendor[k]) ? - DEV_T10_WWN(dev)->vendor[k] : 0x20; - str[k] = 0x20; - - /* model */ - for (k = 0; k < 16; k++) - str[k+9] = ISPRINT(DEV_T10_WWN(dev)->model[k]) ? - DEV_T10_WWN(dev)->model[k] : 0x20; - str[k + 9] = 0; - - seq_printf(seq, "dev_alias: %s\n", str); - - return 0; -} - -static const struct seq_operations scsi_dev_seq_ops = { - .start = scsi_dev_seq_start, - .next = scsi_dev_seq_next, - .stop = scsi_dev_seq_stop, - .show = scsi_dev_seq_show -}; - -static int scsi_dev_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &scsi_dev_seq_ops); -} - -static const struct file_operations scsi_dev_seq_fops = { - .owner = THIS_MODULE, - .open = scsi_dev_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * SCSI Port Table - */ -static void *scsi_port_seq_start(struct seq_file *seq, loff_t *pos) -{ - return locate_hba_start(seq, pos); -} - -static void *scsi_port_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return locate_hba_next(seq, v, pos); -} - -static void scsi_port_seq_stop(struct seq_file *seq, void *v) -{ - locate_hba_stop(seq, v); -} - -static int scsi_port_seq_show(struct seq_file *seq, void *v) -{ - struct se_hba *hba; - struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, - g_se_dev_list); - struct se_device *dev = se_dev->se_dev_ptr; - struct se_port *sep, *sep_tmp; - - if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) - seq_puts(seq, "inst device indx role busy_count\n"); - - if (!(dev)) - return 0; - - hba = dev->se_hba; - if (!(hba)) { - /* Log error ? */ - return 0; - } - - /* FIXME: scsiPortBusyStatuses count */ - spin_lock(&dev->se_port_lock); - list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) { - seq_printf(seq, "%u %u %u %s%u %u\n", hba->hba_index, - dev->dev_index, sep->sep_index, "Device", - dev->dev_index, 0); - } - spin_unlock(&dev->se_port_lock); - - return 0; -} - -static const struct seq_operations scsi_port_seq_ops = { - .start = scsi_port_seq_start, - .next = scsi_port_seq_next, - .stop = scsi_port_seq_stop, - .show = scsi_port_seq_show -}; - -static int scsi_port_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &scsi_port_seq_ops); -} - -static const struct file_operations scsi_port_seq_fops = { - .owner = THIS_MODULE, - .open = scsi_port_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * SCSI Transport Table - */ -static void *scsi_transport_seq_start(struct seq_file *seq, loff_t *pos) -{ - return locate_hba_start(seq, pos); -} - -static void *scsi_transport_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return locate_hba_next(seq, v, pos); -} - -static void scsi_transport_seq_stop(struct seq_file *seq, void *v) -{ - locate_hba_stop(seq, v); -} - -static int scsi_transport_seq_show(struct seq_file *seq, void *v) -{ - struct se_hba *hba; - struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, - g_se_dev_list); - struct se_device *dev = se_dev->se_dev_ptr; - struct se_port *se, *se_tmp; - struct se_portal_group *tpg; - struct t10_wwn *wwn; - char buf[64]; - - if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) - seq_puts(seq, "inst device indx dev_name\n"); - - if (!(dev)) - return 0; - - hba = dev->se_hba; - if (!(hba)) { - /* Log error ? */ - return 0; - } - - wwn = DEV_T10_WWN(dev); - - spin_lock(&dev->se_port_lock); - list_for_each_entry_safe(se, se_tmp, &dev->dev_sep_list, sep_list) { - tpg = se->sep_tpg; - sprintf(buf, "scsiTransport%s", - TPG_TFO(tpg)->get_fabric_name()); - - seq_printf(seq, "%u %s %u %s+%s\n", - hba->hba_index, /* scsiTransportIndex */ - buf, /* scsiTransportType */ - (TPG_TFO(tpg)->tpg_get_inst_index != NULL) ? - TPG_TFO(tpg)->tpg_get_inst_index(tpg) : - 0, - TPG_TFO(tpg)->tpg_get_wwn(tpg), - (strlen(wwn->unit_serial)) ? - /* scsiTransportDevName */ - wwn->unit_serial : wwn->vendor); - } - spin_unlock(&dev->se_port_lock); - - return 0; -} - -static const struct seq_operations scsi_transport_seq_ops = { - .start = scsi_transport_seq_start, - .next = scsi_transport_seq_next, - .stop = scsi_transport_seq_stop, - .show = scsi_transport_seq_show -}; - -static int scsi_transport_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &scsi_transport_seq_ops); -} - -static const struct file_operations scsi_transport_seq_fops = { - .owner = THIS_MODULE, - .open = scsi_transport_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * SCSI Target Device Table - */ -static void *scsi_tgt_dev_seq_start(struct seq_file *seq, loff_t *pos) -{ - return locate_hba_start(seq, pos); -} - -static void *scsi_tgt_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return locate_hba_next(seq, v, pos); -} - -static void scsi_tgt_dev_seq_stop(struct seq_file *seq, void *v) -{ - locate_hba_stop(seq, v); -} - - -#define LU_COUNT 1 /* for now */ -static int scsi_tgt_dev_seq_show(struct seq_file *seq, void *v) -{ - struct se_hba *hba; - struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, - g_se_dev_list); - struct se_device *dev = se_dev->se_dev_ptr; - int non_accessible_lus = 0; - char status[16]; - - if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) - seq_puts(seq, "inst indx num_LUs status non_access_LUs" - " resets\n"); - - if (!(dev)) - return 0; - - hba = dev->se_hba; - if (!(hba)) { - /* Log error ? */ - return 0; - } - - switch (dev->dev_status) { - case TRANSPORT_DEVICE_ACTIVATED: - strcpy(status, "activated"); - break; - case TRANSPORT_DEVICE_DEACTIVATED: - strcpy(status, "deactivated"); - non_accessible_lus = 1; - break; - case TRANSPORT_DEVICE_SHUTDOWN: - strcpy(status, "shutdown"); - non_accessible_lus = 1; - break; - case TRANSPORT_DEVICE_OFFLINE_ACTIVATED: - case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED: - strcpy(status, "offline"); - non_accessible_lus = 1; - break; - default: - sprintf(status, "unknown(%d)", dev->dev_status); - non_accessible_lus = 1; - } - - seq_printf(seq, "%u %u %u %s %u %u\n", - hba->hba_index, dev->dev_index, LU_COUNT, - status, non_accessible_lus, dev->num_resets); - - return 0; -} - -static const struct seq_operations scsi_tgt_dev_seq_ops = { - .start = scsi_tgt_dev_seq_start, - .next = scsi_tgt_dev_seq_next, - .stop = scsi_tgt_dev_seq_stop, - .show = scsi_tgt_dev_seq_show -}; - -static int scsi_tgt_dev_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &scsi_tgt_dev_seq_ops); -} - -static const struct file_operations scsi_tgt_dev_seq_fops = { - .owner = THIS_MODULE, - .open = scsi_tgt_dev_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * SCSI Target Port Table - */ -static void *scsi_tgt_port_seq_start(struct seq_file *seq, loff_t *pos) -{ - return locate_hba_start(seq, pos); -} - -static void *scsi_tgt_port_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return locate_hba_next(seq, v, pos); -} - -static void scsi_tgt_port_seq_stop(struct seq_file *seq, void *v) -{ - locate_hba_stop(seq, v); -} - -static int scsi_tgt_port_seq_show(struct seq_file *seq, void *v) -{ - struct se_hba *hba; - struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, - g_se_dev_list); - struct se_device *dev = se_dev->se_dev_ptr; - struct se_port *sep, *sep_tmp; - struct se_portal_group *tpg; - u32 rx_mbytes, tx_mbytes; - unsigned long long num_cmds; - char buf[64]; - - if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) - seq_puts(seq, "inst device indx name port_index in_cmds" - " write_mbytes read_mbytes hs_in_cmds\n"); - - if (!(dev)) - return 0; - - hba = dev->se_hba; - if (!(hba)) { - /* Log error ? */ - return 0; - } - - spin_lock(&dev->se_port_lock); - list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) { - tpg = sep->sep_tpg; - sprintf(buf, "%sPort#", - TPG_TFO(tpg)->get_fabric_name()); - - seq_printf(seq, "%u %u %u %s%d %s%s%d ", - hba->hba_index, - dev->dev_index, - sep->sep_index, - buf, sep->sep_index, - TPG_TFO(tpg)->tpg_get_wwn(tpg), "+t+", - TPG_TFO(tpg)->tpg_get_tag(tpg)); - - spin_lock(&sep->sep_lun->lun_sep_lock); - num_cmds = sep->sep_stats.cmd_pdus; - rx_mbytes = (sep->sep_stats.rx_data_octets >> 20); - tx_mbytes = (sep->sep_stats.tx_data_octets >> 20); - spin_unlock(&sep->sep_lun->lun_sep_lock); - - seq_printf(seq, "%llu %u %u %u\n", num_cmds, - rx_mbytes, tx_mbytes, 0); - } - spin_unlock(&dev->se_port_lock); - - return 0; -} - -static const struct seq_operations scsi_tgt_port_seq_ops = { - .start = scsi_tgt_port_seq_start, - .next = scsi_tgt_port_seq_next, - .stop = scsi_tgt_port_seq_stop, - .show = scsi_tgt_port_seq_show -}; - -static int scsi_tgt_port_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &scsi_tgt_port_seq_ops); -} - -static const struct file_operations scsi_tgt_port_seq_fops = { - .owner = THIS_MODULE, - .open = scsi_tgt_port_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * SCSI Authorized Initiator Table: - * It contains the SCSI Initiators authorized to be attached to one of the - * local Target ports. - * Iterates through all active TPGs and extracts the info from the ACLs - */ -static void *scsi_auth_intr_seq_start(struct seq_file *seq, loff_t *pos) -{ - spin_lock_bh(&se_global->se_tpg_lock); - return seq_list_start(&se_global->g_se_tpg_list, *pos); -} - -static void *scsi_auth_intr_seq_next(struct seq_file *seq, void *v, - loff_t *pos) -{ - return seq_list_next(v, &se_global->g_se_tpg_list, pos); -} - -static void scsi_auth_intr_seq_stop(struct seq_file *seq, void *v) -{ - spin_unlock_bh(&se_global->se_tpg_lock); -} - -static int scsi_auth_intr_seq_show(struct seq_file *seq, void *v) -{ - struct se_portal_group *se_tpg = list_entry(v, struct se_portal_group, - se_tpg_list); - struct se_dev_entry *deve; - struct se_lun *lun; - struct se_node_acl *se_nacl; - int j; - - if (list_is_first(&se_tpg->se_tpg_list, - &se_global->g_se_tpg_list)) - seq_puts(seq, "inst dev port indx dev_or_port intr_name " - "map_indx att_count num_cmds read_mbytes " - "write_mbytes hs_num_cmds creation_time row_status\n"); - - if (!(se_tpg)) - return 0; - - spin_lock(&se_tpg->acl_node_lock); - list_for_each_entry(se_nacl, &se_tpg->acl_node_list, acl_list) { - - atomic_inc(&se_nacl->mib_ref_count); - smp_mb__after_atomic_inc(); - spin_unlock(&se_tpg->acl_node_lock); - - spin_lock_irq(&se_nacl->device_list_lock); - for (j = 0; j < TRANSPORT_MAX_LUNS_PER_TPG; j++) { - deve = &se_nacl->device_list[j]; - if (!(deve->lun_flags & - TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) || - (!deve->se_lun)) - continue; - lun = deve->se_lun; - if (!lun->lun_se_dev) - continue; - - seq_printf(seq, "%u %u %u %u %u %s %u %u %u %u %u %u" - " %u %s\n", - /* scsiInstIndex */ - (TPG_TFO(se_tpg)->tpg_get_inst_index != NULL) ? - TPG_TFO(se_tpg)->tpg_get_inst_index(se_tpg) : - 0, - /* scsiDeviceIndex */ - lun->lun_se_dev->dev_index, - /* scsiAuthIntrTgtPortIndex */ - TPG_TFO(se_tpg)->tpg_get_tag(se_tpg), - /* scsiAuthIntrIndex */ - se_nacl->acl_index, - /* scsiAuthIntrDevOrPort */ - 1, - /* scsiAuthIntrName */ - se_nacl->initiatorname[0] ? - se_nacl->initiatorname : NONE, - /* FIXME: scsiAuthIntrLunMapIndex */ - 0, - /* scsiAuthIntrAttachedTimes */ - deve->attach_count, - /* scsiAuthIntrOutCommands */ - deve->total_cmds, - /* scsiAuthIntrReadMegaBytes */ - (u32)(deve->read_bytes >> 20), - /* scsiAuthIntrWrittenMegaBytes */ - (u32)(deve->write_bytes >> 20), - /* FIXME: scsiAuthIntrHSOutCommands */ - 0, - /* scsiAuthIntrLastCreation */ - (u32)(((u32)deve->creation_time - - INITIAL_JIFFIES) * 100 / HZ), - /* FIXME: scsiAuthIntrRowStatus */ - "Ready"); - } - spin_unlock_irq(&se_nacl->device_list_lock); - - spin_lock(&se_tpg->acl_node_lock); - atomic_dec(&se_nacl->mib_ref_count); - smp_mb__after_atomic_dec(); - } - spin_unlock(&se_tpg->acl_node_lock); - - return 0; -} - -static const struct seq_operations scsi_auth_intr_seq_ops = { - .start = scsi_auth_intr_seq_start, - .next = scsi_auth_intr_seq_next, - .stop = scsi_auth_intr_seq_stop, - .show = scsi_auth_intr_seq_show -}; - -static int scsi_auth_intr_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &scsi_auth_intr_seq_ops); -} - -static const struct file_operations scsi_auth_intr_seq_fops = { - .owner = THIS_MODULE, - .open = scsi_auth_intr_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * SCSI Attached Initiator Port Table: - * It lists the SCSI Initiators attached to one of the local Target ports. - * Iterates through all active TPGs and use active sessions from each TPG - * to list the info fo this table. - */ -static void *scsi_att_intr_port_seq_start(struct seq_file *seq, loff_t *pos) -{ - spin_lock_bh(&se_global->se_tpg_lock); - return seq_list_start(&se_global->g_se_tpg_list, *pos); -} - -static void *scsi_att_intr_port_seq_next(struct seq_file *seq, void *v, - loff_t *pos) -{ - return seq_list_next(v, &se_global->g_se_tpg_list, pos); -} - -static void scsi_att_intr_port_seq_stop(struct seq_file *seq, void *v) -{ - spin_unlock_bh(&se_global->se_tpg_lock); -} - -static int scsi_att_intr_port_seq_show(struct seq_file *seq, void *v) -{ - struct se_portal_group *se_tpg = list_entry(v, struct se_portal_group, - se_tpg_list); - struct se_dev_entry *deve; - struct se_lun *lun; - struct se_node_acl *se_nacl; - struct se_session *se_sess; - unsigned char buf[64]; - int j; - - if (list_is_first(&se_tpg->se_tpg_list, - &se_global->g_se_tpg_list)) - seq_puts(seq, "inst dev port indx port_auth_indx port_name" - " port_ident\n"); - - if (!(se_tpg)) - return 0; - - spin_lock(&se_tpg->session_lock); - list_for_each_entry(se_sess, &se_tpg->tpg_sess_list, sess_list) { - if ((TPG_TFO(se_tpg)->sess_logged_in(se_sess)) || - (!se_sess->se_node_acl) || - (!se_sess->se_node_acl->device_list)) - continue; - - atomic_inc(&se_sess->mib_ref_count); - smp_mb__after_atomic_inc(); - se_nacl = se_sess->se_node_acl; - atomic_inc(&se_nacl->mib_ref_count); - smp_mb__after_atomic_inc(); - spin_unlock(&se_tpg->session_lock); - - spin_lock_irq(&se_nacl->device_list_lock); - for (j = 0; j < TRANSPORT_MAX_LUNS_PER_TPG; j++) { - deve = &se_nacl->device_list[j]; - if (!(deve->lun_flags & - TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) || - (!deve->se_lun)) - continue; - - lun = deve->se_lun; - if (!lun->lun_se_dev) - continue; - - memset(buf, 0, 64); - if (TPG_TFO(se_tpg)->sess_get_initiator_sid != NULL) - TPG_TFO(se_tpg)->sess_get_initiator_sid( - se_sess, (unsigned char *)&buf[0], 64); - - seq_printf(seq, "%u %u %u %u %u %s+i+%s\n", - /* scsiInstIndex */ - (TPG_TFO(se_tpg)->tpg_get_inst_index != NULL) ? - TPG_TFO(se_tpg)->tpg_get_inst_index(se_tpg) : - 0, - /* scsiDeviceIndex */ - lun->lun_se_dev->dev_index, - /* scsiPortIndex */ - TPG_TFO(se_tpg)->tpg_get_tag(se_tpg), - /* scsiAttIntrPortIndex */ - (TPG_TFO(se_tpg)->sess_get_index != NULL) ? - TPG_TFO(se_tpg)->sess_get_index(se_sess) : - 0, - /* scsiAttIntrPortAuthIntrIdx */ - se_nacl->acl_index, - /* scsiAttIntrPortName */ - se_nacl->initiatorname[0] ? - se_nacl->initiatorname : NONE, - /* scsiAttIntrPortIdentifier */ - buf); - } - spin_unlock_irq(&se_nacl->device_list_lock); - - spin_lock(&se_tpg->session_lock); - atomic_dec(&se_nacl->mib_ref_count); - smp_mb__after_atomic_dec(); - atomic_dec(&se_sess->mib_ref_count); - smp_mb__after_atomic_dec(); - } - spin_unlock(&se_tpg->session_lock); - - return 0; -} - -static const struct seq_operations scsi_att_intr_port_seq_ops = { - .start = scsi_att_intr_port_seq_start, - .next = scsi_att_intr_port_seq_next, - .stop = scsi_att_intr_port_seq_stop, - .show = scsi_att_intr_port_seq_show -}; - -static int scsi_att_intr_port_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &scsi_att_intr_port_seq_ops); -} - -static const struct file_operations scsi_att_intr_port_seq_fops = { - .owner = THIS_MODULE, - .open = scsi_att_intr_port_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * SCSI Logical Unit Table - */ -static void *scsi_lu_seq_start(struct seq_file *seq, loff_t *pos) -{ - return locate_hba_start(seq, pos); -} - -static void *scsi_lu_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return locate_hba_next(seq, v, pos); -} - -static void scsi_lu_seq_stop(struct seq_file *seq, void *v) -{ - locate_hba_stop(seq, v); -} - -#define SCSI_LU_INDEX 1 -static int scsi_lu_seq_show(struct seq_file *seq, void *v) -{ - struct se_hba *hba; - struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, - g_se_dev_list); - struct se_device *dev = se_dev->se_dev_ptr; - int j; - char str[28]; - - if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) - seq_puts(seq, "inst dev indx LUN lu_name vend prod rev" - " dev_type status state-bit num_cmds read_mbytes" - " write_mbytes resets full_stat hs_num_cmds creation_time\n"); - - if (!(dev)) - return 0; - - hba = dev->se_hba; - if (!(hba)) { - /* Log error ? */ - return 0; - } - - /* Fix LU state, if we can read it from the device */ - seq_printf(seq, "%u %u %u %llu %s", hba->hba_index, - dev->dev_index, SCSI_LU_INDEX, - (unsigned long long)0, /* FIXME: scsiLuDefaultLun */ - (strlen(DEV_T10_WWN(dev)->unit_serial)) ? - /* scsiLuWwnName */ - (char *)&DEV_T10_WWN(dev)->unit_serial[0] : - "None"); - - memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28); - /* scsiLuVendorId */ - for (j = 0; j < 8; j++) - str[j] = ISPRINT(DEV_T10_WWN(dev)->vendor[j]) ? - DEV_T10_WWN(dev)->vendor[j] : 0x20; - str[8] = 0; - seq_printf(seq, " %s", str); - - /* scsiLuProductId */ - for (j = 0; j < 16; j++) - str[j] = ISPRINT(DEV_T10_WWN(dev)->model[j]) ? - DEV_T10_WWN(dev)->model[j] : 0x20; - str[16] = 0; - seq_printf(seq, " %s", str); - - /* scsiLuRevisionId */ - for (j = 0; j < 4; j++) - str[j] = ISPRINT(DEV_T10_WWN(dev)->revision[j]) ? - DEV_T10_WWN(dev)->revision[j] : 0x20; - str[4] = 0; - seq_printf(seq, " %s", str); - - seq_printf(seq, " %u %s %s %llu %u %u %u %u %u %u\n", - /* scsiLuPeripheralType */ - TRANSPORT(dev)->get_device_type(dev), - (dev->dev_status == TRANSPORT_DEVICE_ACTIVATED) ? - "available" : "notavailable", /* scsiLuStatus */ - "exposed", /* scsiLuState */ - (unsigned long long)dev->num_cmds, - /* scsiLuReadMegaBytes */ - (u32)(dev->read_bytes >> 20), - /* scsiLuWrittenMegaBytes */ - (u32)(dev->write_bytes >> 20), - dev->num_resets, /* scsiLuInResets */ - 0, /* scsiLuOutTaskSetFullStatus */ - 0, /* scsiLuHSInCommands */ - (u32)(((u32)dev->creation_time - INITIAL_JIFFIES) * - 100 / HZ)); - - return 0; -} - -static const struct seq_operations scsi_lu_seq_ops = { - .start = scsi_lu_seq_start, - .next = scsi_lu_seq_next, - .stop = scsi_lu_seq_stop, - .show = scsi_lu_seq_show -}; - -static int scsi_lu_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &scsi_lu_seq_ops); -} - -static const struct file_operations scsi_lu_seq_fops = { - .owner = THIS_MODULE, - .open = scsi_lu_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/****************************************************************************/ - -/* - * Remove proc fs entries - */ -void remove_scsi_target_mib(void) -{ - remove_proc_entry("scsi_target/mib/scsi_inst", NULL); - remove_proc_entry("scsi_target/mib/scsi_dev", NULL); - remove_proc_entry("scsi_target/mib/scsi_port", NULL); - remove_proc_entry("scsi_target/mib/scsi_transport", NULL); - remove_proc_entry("scsi_target/mib/scsi_tgt_dev", NULL); - remove_proc_entry("scsi_target/mib/scsi_tgt_port", NULL); - remove_proc_entry("scsi_target/mib/scsi_auth_intr", NULL); - remove_proc_entry("scsi_target/mib/scsi_att_intr_port", NULL); - remove_proc_entry("scsi_target/mib/scsi_lu", NULL); - remove_proc_entry("scsi_target/mib", NULL); -} - -/* - * Create proc fs entries for the mib tables - */ -int init_scsi_target_mib(void) -{ - struct proc_dir_entry *dir_entry; - struct proc_dir_entry *scsi_inst_entry; - struct proc_dir_entry *scsi_dev_entry; - struct proc_dir_entry *scsi_port_entry; - struct proc_dir_entry *scsi_transport_entry; - struct proc_dir_entry *scsi_tgt_dev_entry; - struct proc_dir_entry *scsi_tgt_port_entry; - struct proc_dir_entry *scsi_auth_intr_entry; - struct proc_dir_entry *scsi_att_intr_port_entry; - struct proc_dir_entry *scsi_lu_entry; - - dir_entry = proc_mkdir("scsi_target/mib", NULL); - if (!(dir_entry)) { - printk(KERN_ERR "proc_mkdir() failed.\n"); - return -1; - } - - scsi_inst_entry = - create_proc_entry("scsi_target/mib/scsi_inst", 0, NULL); - if (scsi_inst_entry) - scsi_inst_entry->proc_fops = &scsi_inst_seq_fops; - else - goto error; - - scsi_dev_entry = - create_proc_entry("scsi_target/mib/scsi_dev", 0, NULL); - if (scsi_dev_entry) - scsi_dev_entry->proc_fops = &scsi_dev_seq_fops; - else - goto error; - - scsi_port_entry = - create_proc_entry("scsi_target/mib/scsi_port", 0, NULL); - if (scsi_port_entry) - scsi_port_entry->proc_fops = &scsi_port_seq_fops; - else - goto error; - - scsi_transport_entry = - create_proc_entry("scsi_target/mib/scsi_transport", 0, NULL); - if (scsi_transport_entry) - scsi_transport_entry->proc_fops = &scsi_transport_seq_fops; - else - goto error; - - scsi_tgt_dev_entry = - create_proc_entry("scsi_target/mib/scsi_tgt_dev", 0, NULL); - if (scsi_tgt_dev_entry) - scsi_tgt_dev_entry->proc_fops = &scsi_tgt_dev_seq_fops; - else - goto error; - - scsi_tgt_port_entry = - create_proc_entry("scsi_target/mib/scsi_tgt_port", 0, NULL); - if (scsi_tgt_port_entry) - scsi_tgt_port_entry->proc_fops = &scsi_tgt_port_seq_fops; - else - goto error; - - scsi_auth_intr_entry = - create_proc_entry("scsi_target/mib/scsi_auth_intr", 0, NULL); - if (scsi_auth_intr_entry) - scsi_auth_intr_entry->proc_fops = &scsi_auth_intr_seq_fops; - else - goto error; - - scsi_att_intr_port_entry = - create_proc_entry("scsi_target/mib/scsi_att_intr_port", 0, NULL); - if (scsi_att_intr_port_entry) - scsi_att_intr_port_entry->proc_fops = - &scsi_att_intr_port_seq_fops; - else - goto error; - - scsi_lu_entry = create_proc_entry("scsi_target/mib/scsi_lu", 0, NULL); - if (scsi_lu_entry) - scsi_lu_entry->proc_fops = &scsi_lu_seq_fops; - else - goto error; - - return 0; - -error: - printk(KERN_ERR "create_proc_entry() failed.\n"); - remove_scsi_target_mib(); - return -1; -} - -/* - * Initialize the index table for allocating unique row indexes to various mib - * tables - */ -void init_scsi_index_table(void) -{ - memset(&scsi_index_table, 0, sizeof(struct scsi_index_table)); - spin_lock_init(&scsi_index_table.lock); -} - -/* - * Allocate a new row index for the entry type specified - */ -u32 scsi_get_new_index(scsi_index_t type) -{ - u32 new_index; - - if ((type < 0) || (type >= SCSI_INDEX_TYPE_MAX)) { - printk(KERN_ERR "Invalid index type %d\n", type); - return -1; - } - - spin_lock(&scsi_index_table.lock); - new_index = ++scsi_index_table.scsi_mib_index[type]; - if (new_index == 0) - new_index = ++scsi_index_table.scsi_mib_index[type]; - spin_unlock(&scsi_index_table.lock); - - return new_index; -} -EXPORT_SYMBOL(scsi_get_new_index); diff --git a/drivers/target/target_core_mib.h b/drivers/target/target_core_mib.h deleted file mode 100644 index 277204633850..000000000000 --- a/drivers/target/target_core_mib.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef TARGET_CORE_MIB_H -#define TARGET_CORE_MIB_H - -typedef enum { - SCSI_INST_INDEX, - SCSI_DEVICE_INDEX, - SCSI_AUTH_INTR_INDEX, - SCSI_INDEX_TYPE_MAX -} scsi_index_t; - -struct scsi_index_table { - spinlock_t lock; - u32 scsi_mib_index[SCSI_INDEX_TYPE_MAX]; -} ____cacheline_aligned; - -/* SCSI Port stats */ -struct scsi_port_stats { - u64 cmd_pdus; - u64 tx_data_octets; - u64 rx_data_octets; -} ____cacheline_aligned; - -extern int init_scsi_target_mib(void); -extern void remove_scsi_target_mib(void); -extern void init_scsi_index_table(void); -extern u32 scsi_get_new_index(scsi_index_t); - -#endif /*** TARGET_CORE_MIB_H ***/ diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 742d24609a9b..f2a08477a68c 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -462,8 +462,8 @@ static struct se_device *pscsi_create_type_disk( */ bd = blkdev_get_by_path(se_dev->se_dev_udev_path, FMODE_WRITE|FMODE_READ|FMODE_EXCL, pdv); - if (!(bd)) { - printk("pSCSI: blkdev_get_by_path() failed\n"); + if (IS_ERR(bd)) { + printk(KERN_ERR "pSCSI: blkdev_get_by_path() failed\n"); scsi_device_put(sd); return NULL; } diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index abfa81a57115..c26f67467623 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -275,7 +275,6 @@ struct se_node_acl *core_tpg_check_initiator_node_acl( spin_lock_init(&acl->device_list_lock); spin_lock_init(&acl->nacl_sess_lock); atomic_set(&acl->acl_pr_ref_count, 0); - atomic_set(&acl->mib_ref_count, 0); acl->queue_depth = TPG_TFO(tpg)->tpg_get_default_depth(tpg); snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname); acl->se_tpg = tpg; @@ -318,12 +317,6 @@ void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *nacl) cpu_relax(); } -void core_tpg_wait_for_mib_ref(struct se_node_acl *nacl) -{ - while (atomic_read(&nacl->mib_ref_count) != 0) - cpu_relax(); -} - void core_tpg_clear_object_luns(struct se_portal_group *tpg) { int i, ret; @@ -480,7 +473,6 @@ int core_tpg_del_initiator_node_acl( spin_unlock_bh(&tpg->session_lock); core_tpg_wait_for_nacl_pr_ref(acl); - core_tpg_wait_for_mib_ref(acl); core_clear_initiator_node_from_tpg(acl, tpg); core_free_device_list_for_node(acl, tpg); @@ -701,6 +693,8 @@ EXPORT_SYMBOL(core_tpg_register); int core_tpg_deregister(struct se_portal_group *se_tpg) { + struct se_node_acl *nacl, *nacl_tmp; + printk(KERN_INFO "TARGET_CORE[%s]: Deallocating %s struct se_portal_group" " for endpoint: %s Portal Tag %u\n", (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) ? @@ -714,6 +708,25 @@ int core_tpg_deregister(struct se_portal_group *se_tpg) while (atomic_read(&se_tpg->tpg_pr_ref_count) != 0) cpu_relax(); + /* + * Release any remaining demo-mode generated se_node_acl that have + * not been released because of TFO->tpg_check_demo_mode_cache() == 1 + * in transport_deregister_session(). + */ + spin_lock_bh(&se_tpg->acl_node_lock); + list_for_each_entry_safe(nacl, nacl_tmp, &se_tpg->acl_node_list, + acl_list) { + list_del(&nacl->acl_list); + se_tpg->num_node_acls--; + spin_unlock_bh(&se_tpg->acl_node_lock); + + core_tpg_wait_for_nacl_pr_ref(nacl); + core_free_device_list_for_node(nacl, se_tpg); + TPG_TFO(se_tpg)->tpg_release_fabric_acl(se_tpg, nacl); + + spin_lock_bh(&se_tpg->acl_node_lock); + } + spin_unlock_bh(&se_tpg->acl_node_lock); if (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) core_tpg_release_virtual_lun0(se_tpg); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 28b6292ff298..236e22d8cfae 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -379,6 +379,40 @@ void release_se_global(void) se_global = NULL; } +/* SCSI statistics table index */ +static struct scsi_index_table scsi_index_table; + +/* + * Initialize the index table for allocating unique row indexes to various mib + * tables. + */ +void init_scsi_index_table(void) +{ + memset(&scsi_index_table, 0, sizeof(struct scsi_index_table)); + spin_lock_init(&scsi_index_table.lock); +} + +/* + * Allocate a new row index for the entry type specified + */ +u32 scsi_get_new_index(scsi_index_t type) +{ + u32 new_index; + + if ((type < 0) || (type >= SCSI_INDEX_TYPE_MAX)) { + printk(KERN_ERR "Invalid index type %d\n", type); + return -EINVAL; + } + + spin_lock(&scsi_index_table.lock); + new_index = ++scsi_index_table.scsi_mib_index[type]; + if (new_index == 0) + new_index = ++scsi_index_table.scsi_mib_index[type]; + spin_unlock(&scsi_index_table.lock); + + return new_index; +} + void transport_init_queue_obj(struct se_queue_obj *qobj) { atomic_set(&qobj->queue_cnt, 0); @@ -437,7 +471,6 @@ struct se_session *transport_init_session(void) } INIT_LIST_HEAD(&se_sess->sess_list); INIT_LIST_HEAD(&se_sess->sess_acl_list); - atomic_set(&se_sess->mib_ref_count, 0); return se_sess; } @@ -546,12 +579,6 @@ void transport_deregister_session(struct se_session *se_sess) transport_free_session(se_sess); return; } - /* - * Wait for possible reference in drivers/target/target_core_mib.c: - * scsi_att_intr_port_seq_show() - */ - while (atomic_read(&se_sess->mib_ref_count) != 0) - cpu_relax(); spin_lock_bh(&se_tpg->session_lock); list_del(&se_sess->sess_list); @@ -574,7 +601,6 @@ void transport_deregister_session(struct se_session *se_sess) spin_unlock_bh(&se_tpg->acl_node_lock); core_tpg_wait_for_nacl_pr_ref(se_nacl); - core_tpg_wait_for_mib_ref(se_nacl); core_free_device_list_for_node(se_nacl, se_tpg); TPG_TFO(se_tpg)->tpg_release_fabric_acl(se_tpg, se_nacl); @@ -4827,6 +4853,8 @@ static int transport_do_se_mem_map( return ret; } + + BUG_ON(list_empty(se_mem_list)); /* * This is the normal path for all normal non BIDI and BIDI-COMMAND * WRITE payloads.. If we need to do BIDI READ passthrough for @@ -5008,7 +5036,9 @@ transport_map_control_cmd_to_task(struct se_cmd *cmd) struct se_mem *se_mem = NULL, *se_mem_lout = NULL; u32 se_mem_cnt = 0, task_offset = 0; - BUG_ON(list_empty(cmd->t_task->t_mem_list)); + if (!list_empty(T_TASK(cmd)->t_mem_list)) + se_mem = list_entry(T_TASK(cmd)->t_mem_list->next, + struct se_mem, se_list); ret = transport_do_se_mem_map(dev, task, cmd->t_task->t_mem_list, NULL, se_mem, diff --git a/drivers/tty/hvc/Makefile b/drivers/tty/hvc/Makefile index e6bed5f177ff..d79e7e9bf9d2 100644 --- a/drivers/tty/hvc/Makefile +++ b/drivers/tty/hvc/Makefile @@ -10,4 +10,3 @@ obj-$(CONFIG_HVC_XEN) += hvc_xen.o obj-$(CONFIG_HVC_IUCV) += hvc_iucv.o obj-$(CONFIG_HVC_UDBG) += hvc_udbg.o obj-$(CONFIG_HVCS) += hvcs.o -obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 44b8412a04e8..aa2e5d3eb01a 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2414,6 +2414,7 @@ static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm, gsm->initiator = c->initiator; gsm->mru = c->mru; + gsm->mtu = c->mtu; gsm->encoding = c->encapsulation; gsm->adaption = c->adaption; gsm->n2 = c->n2; diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 47d32281032c..52fc0c9a6364 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -581,8 +581,9 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, __u8 __user *buf, size_t nr) { struct n_hdlc *n_hdlc = tty2n_hdlc(tty); - int ret; + int ret = 0; struct n_hdlc_buf *rbuf; + DECLARE_WAITQUEUE(wait, current); if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__); @@ -598,57 +599,55 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, return -EFAULT; } - tty_lock(); + add_wait_queue(&tty->read_wait, &wait); for (;;) { if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { - tty_unlock(); - return -EIO; + ret = -EIO; + break; } + if (tty_hung_up_p(file)) + break; - n_hdlc = tty2n_hdlc (tty); - if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || - tty != n_hdlc->tty) { - tty_unlock(); - return 0; - } + set_current_state(TASK_INTERRUPTIBLE); rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list); - if (rbuf) + if (rbuf) { + if (rbuf->count > nr) { + /* too large for caller's buffer */ + ret = -EOVERFLOW; + } else { + if (copy_to_user(buf, rbuf->buf, rbuf->count)) + ret = -EFAULT; + else + ret = rbuf->count; + } + + if (n_hdlc->rx_free_buf_list.count > + DEFAULT_RX_BUF_COUNT) + kfree(rbuf); + else + n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, rbuf); break; + } /* no data */ if (file->f_flags & O_NONBLOCK) { - tty_unlock(); - return -EAGAIN; + ret = -EAGAIN; + break; } - - interruptible_sleep_on (&tty->read_wait); + + schedule(); + if (signal_pending(current)) { - tty_unlock(); - return -EINTR; + ret = -EINTR; + break; } } - - if (rbuf->count > nr) - /* frame too large for caller's buffer (discard frame) */ - ret = -EOVERFLOW; - else { - /* Copy the data to the caller's buffer */ - if (copy_to_user(buf, rbuf->buf, rbuf->count)) - ret = -EFAULT; - else - ret = rbuf->count; - } - - /* return HDLC buffer to free list unless the free list */ - /* count has exceeded the default value, in which case the */ - /* buffer is freed back to the OS to conserve memory */ - if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT) - kfree(rbuf); - else - n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf); - tty_unlock(); + + remove_wait_queue(&tty->read_wait, &wait); + __set_current_state(TASK_RUNNING); + return ret; } /* end of n_hdlc_tty_read() */ @@ -691,14 +690,15 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, count = maxframe; } - tty_lock(); - add_wait_queue(&tty->write_wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); + + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); - /* Allocate transmit buffer */ - /* sleep until transmit buffer available */ - while (!(tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list))) { + tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list); + if (tbuf) + break; + if (file->f_flags & O_NONBLOCK) { error = -EAGAIN; break; @@ -719,7 +719,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, } } - set_current_state(TASK_RUNNING); + __set_current_state(TASK_RUNNING); remove_wait_queue(&tty->write_wait, &wait); if (!error) { @@ -731,7 +731,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf); n_hdlc_send_frames(n_hdlc,tty); } - tty_unlock(); + return error; } /* end of n_hdlc_tty_write() */ diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index be0ebce36e54..de0160e3f8c4 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -262,7 +262,7 @@ static void status_handle(struct m68k_serial *info, unsigned short status) static void receive_chars(struct m68k_serial *info, unsigned short rx) { - struct tty_struct *tty = info->port.tty; + struct tty_struct *tty = info->tty; m68328_uart *uart = &uart_addr[info->line]; unsigned char ch, flag; @@ -329,7 +329,7 @@ static void transmit_chars(struct m68k_serial *info) goto clear_and_return; } - if((info->xmit_cnt <= 0) || info->port.tty->stopped) { + if((info->xmit_cnt <= 0) || info->tty->stopped) { /* That's peculiar... TX ints off */ uart->ustcnt &= ~USTCNT_TX_INTR_MASK; goto clear_and_return; @@ -383,7 +383,7 @@ static void do_softint(struct work_struct *work) struct m68k_serial *info = container_of(work, struct m68k_serial, tqueue); struct tty_struct *tty; - tty = info->port.tty; + tty = info->tty; if (!tty) return; #if 0 @@ -407,7 +407,7 @@ static void do_serial_hangup(struct work_struct *work) struct m68k_serial *info = container_of(work, struct m68k_serial, tqueue_hangup); struct tty_struct *tty; - tty = info->port.tty; + tty = info->tty; if (!tty) return; @@ -451,8 +451,8 @@ static int startup(struct m68k_serial * info) uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK; #endif - if (info->port.tty) - clear_bit(TTY_IO_ERROR, &info->port.tty->flags); + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; /* @@ -486,8 +486,8 @@ static void shutdown(struct m68k_serial * info) info->xmit_buf = 0; } - if (info->port.tty) - set_bit(TTY_IO_ERROR, &info->port.tty->flags); + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); info->flags &= ~S_INITIALIZED; local_irq_restore(flags); @@ -553,9 +553,9 @@ static void change_speed(struct m68k_serial *info) unsigned cflag; int i; - if (!info->port.tty || !info->port.tty->termios) + if (!info->tty || !info->tty->termios) return; - cflag = info->port.tty->termios->c_cflag; + cflag = info->tty->termios->c_cflag; if (!(port = info->port)) return; @@ -970,7 +970,6 @@ static void send_break(struct m68k_serial * info, unsigned int duration) static int rs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { - int error; struct m68k_serial * info = (struct m68k_serial *)tty->driver_data; int retval; @@ -1104,7 +1103,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; - info->port.tty = NULL; + info->tty = NULL; #warning "This is not and has never been valid so fix it" #if 0 if (tty->ldisc.num != ldiscs[N_TTY].num) { @@ -1142,7 +1141,7 @@ void rs_hangup(struct tty_struct *tty) info->event = 0; info->count = 0; info->flags &= ~S_NORMAL_ACTIVE; - info->port.tty = NULL; + info->tty = NULL; wake_up_interruptible(&info->open_wait); } @@ -1261,7 +1260,7 @@ int rs_open(struct tty_struct *tty, struct file * filp) info->count++; tty->driver_data = info; - info->port.tty = tty; + info->tty = tty; /* * Start up serial port @@ -1338,7 +1337,7 @@ rs68328_init(void) info = &m68k_soft[i]; info->magic = SERIAL_MAGIC; info->port = (int) &uart_addr[i]; - info->port.tty = NULL; + info->tty = NULL; info->irq = uart_irqs[i]; info->custom_divisor = 16; info->close_delay = 50; diff --git a/drivers/tty/serial/68360serial.c b/drivers/tty/serial/68360serial.c index 88b13356ec10..bc21eeae8fde 100644 --- a/drivers/tty/serial/68360serial.c +++ b/drivers/tty/serial/68360serial.c @@ -2428,6 +2428,7 @@ static const struct tty_operations rs_360_ops = { /* .read_proc = rs_360_read_proc, */ .tiocmget = rs_360_tiocmget, .tiocmset = rs_360_tiocmset, + .get_icount = rs_360_get_icount, }; static int __init rs_360_init(void) diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c index b25e6e490530..3975df6f7fdb 100644 --- a/drivers/tty/serial/8250.c +++ b/drivers/tty/serial/8250.c @@ -236,7 +236,8 @@ static const struct serial8250_config uart_config[] = { .fifo_size = 128, .tx_loadsz = 128, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, + /* UART_CAP_EFR breaks billionon CF bluetooth card. */ + .flags = UART_CAP_FIFO | UART_CAP_SLEEP, }, [PORT_16654] = { .name = "ST16654", diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index b1682d7f1d8a..2b8334601c8b 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1518,6 +1518,7 @@ config SERIAL_BCM63XX_CONSOLE config SERIAL_GRLIB_GAISLER_APBUART tristate "GRLIB APBUART serial support" depends on OF + select SERIAL_CORE ---help--- Add support for the GRLIB APBUART serial port. diff --git a/drivers/tty/serial/bfin_5xx.c b/drivers/tty/serial/bfin_5xx.c index e381b895b04d..9b1ff2b6bb37 100644 --- a/drivers/tty/serial/bfin_5xx.c +++ b/drivers/tty/serial/bfin_5xx.c @@ -370,10 +370,8 @@ static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id) { struct bfin_serial_port *uart = dev_id; - spin_lock(&uart->port.lock); while (UART_GET_LSR(uart) & DR) bfin_serial_rx_chars(uart); - spin_unlock(&uart->port.lock); return IRQ_HANDLED; } @@ -490,9 +488,8 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) { int x_pos, pos; - dma_disable_irq(uart->tx_dma_channel); - dma_disable_irq(uart->rx_dma_channel); - spin_lock_bh(&uart->port.lock); + dma_disable_irq_nosync(uart->rx_dma_channel); + spin_lock_bh(&uart->rx_lock); /* 2D DMA RX buffer ring is used. Because curr_y_count and * curr_x_count can't be read as an atomic operation, @@ -523,8 +520,7 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) uart->rx_dma_buf.tail = uart->rx_dma_buf.head; } - spin_unlock_bh(&uart->port.lock); - dma_enable_irq(uart->tx_dma_channel); + spin_unlock_bh(&uart->rx_lock); dma_enable_irq(uart->rx_dma_channel); mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES); @@ -571,7 +567,7 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id) unsigned short irqstat; int x_pos, pos; - spin_lock(&uart->port.lock); + spin_lock(&uart->rx_lock); irqstat = get_dma_curr_irqstat(uart->rx_dma_channel); clear_dma_irqstat(uart->rx_dma_channel); @@ -589,7 +585,7 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id) uart->rx_dma_buf.tail = uart->rx_dma_buf.head; } - spin_unlock(&uart->port.lock); + spin_unlock(&uart->rx_lock); return IRQ_HANDLED; } @@ -1332,6 +1328,7 @@ static int bfin_serial_probe(struct platform_device *pdev) } #ifdef CONFIG_SERIAL_BFIN_DMA + spin_lock_init(&uart->rx_lock); uart->tx_done = 1; uart->tx_count = 0; diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index beb1afa27d8d..7b951adac54b 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -601,7 +601,7 @@ static int max3100_startup(struct uart_port *port) s->rts = 0; sprintf(b, "max3100-%d", s->minor); - s->workqueue = create_freezeable_workqueue(b); + s->workqueue = create_freezable_workqueue(b); if (!s->workqueue) { dev_warn(&s->spi->dev, "cannot create workqueue\n"); return -EBUSY; diff --git a/drivers/tty/serial/max3107.c b/drivers/tty/serial/max3107.c index 910870edf708..750b4f627315 100644 --- a/drivers/tty/serial/max3107.c +++ b/drivers/tty/serial/max3107.c @@ -833,7 +833,7 @@ static int max3107_startup(struct uart_port *port) struct max3107_port *s = container_of(port, struct max3107_port, port); /* Initialize work queue */ - s->workqueue = create_freezeable_workqueue("max3107"); + s->workqueue = create_freezable_workqueue("max3107"); if (!s->workqueue) { dev_err(&s->spi->dev, "Workqueue creation failed\n"); return -EBUSY; diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c index a2f2b3254499..602d9845c52f 100644 --- a/drivers/tty/serial/sb1250-duart.c +++ b/drivers/tty/serial/sb1250-duart.c @@ -829,7 +829,7 @@ static void __init sbd_probe_duarts(void) #ifdef CONFIG_SERIAL_SB1250_DUART_CONSOLE /* * Serial console stuff. Very basic, polling driver for doing serial - * console output. The console_sem is held by the caller, so we + * console output. The console_lock is held by the caller, so we * shouldn't be interrupted for more console activity. */ static void sbd_console_putchar(struct uart_port *uport, int ch) diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index c556ed9db13d..81f13958e751 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -46,7 +46,7 @@ #include <asm/irq_regs.h> /* Whether we react on sysrq keys or just ignore them */ -static int __read_mostly sysrq_enabled = 1; +static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE; static bool __read_mostly sysrq_always_enabled; static bool sysrq_on(void) @@ -571,6 +571,7 @@ struct sysrq_state { unsigned int alt_use; bool active; bool need_reinject; + bool reinjecting; }; static void sysrq_reinject_alt_sysrq(struct work_struct *work) @@ -581,6 +582,10 @@ static void sysrq_reinject_alt_sysrq(struct work_struct *work) unsigned int alt_code = sysrq->alt_use; if (sysrq->need_reinject) { + /* we do not want the assignment to be reordered */ + sysrq->reinjecting = true; + mb(); + /* Simulate press and release of Alt + SysRq */ input_inject_event(handle, EV_KEY, alt_code, 1); input_inject_event(handle, EV_KEY, KEY_SYSRQ, 1); @@ -589,6 +594,9 @@ static void sysrq_reinject_alt_sysrq(struct work_struct *work) input_inject_event(handle, EV_KEY, KEY_SYSRQ, 0); input_inject_event(handle, EV_KEY, alt_code, 0); input_inject_event(handle, EV_SYN, SYN_REPORT, 1); + + mb(); + sysrq->reinjecting = false; } } @@ -599,6 +607,13 @@ static bool sysrq_filter(struct input_handle *handle, bool was_active = sysrq->active; bool suppress; + /* + * Do not filter anything if we are in the process of re-injecting + * Alt+SysRq combination. + */ + if (sysrq->reinjecting) + return false; + switch (type) { case EV_SYN: @@ -629,7 +644,7 @@ static bool sysrq_filter(struct input_handle *handle, sysrq->alt_use = sysrq->alt; /* * If nothing else will be pressed we'll need - * to * re-inject Alt-SysRq keysroke. + * to re-inject Alt-SysRq keysroke. */ sysrq->need_reinject = true; } diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 464d09d97873..0065da4b11c1 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -3256,8 +3256,8 @@ static ssize_t show_cons_active(struct device *dev, struct console *c; ssize_t count = 0; - acquire_console_sem(); - for (c = console_drivers; c; c = c->next) { + console_lock(); + for_each_console(c) { if (!c->device) continue; if (!c->write) @@ -3271,7 +3271,7 @@ static ssize_t show_cons_active(struct device *dev, while (i--) count += sprintf(buf + count, "%s%d%c", cs[i]->name, cs[i]->index, i ? ' ':'\n'); - release_console_sem(); + console_unlock(); return count; } @@ -3306,7 +3306,7 @@ int __init tty_init(void) if (IS_ERR(consdev)) consdev = NULL; else - device_create_file(consdev, &dev_attr_active); + WARN_ON(device_create_file(consdev, &dev_attr_active) < 0); #ifdef CONFIG_VT vty_init(&console_fops); diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index ebae344ce910..c956ed6c83a3 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -316,9 +316,9 @@ int paste_selection(struct tty_struct *tty) /* always called with BTM from vt_ioctl */ WARN_ON(!tty_locked()); - acquire_console_sem(); + console_lock(); poke_blanked_console(); - release_console_sem(); + console_unlock(); ld = tty_ldisc_ref(tty); if (!ld) { diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index eab3a1ff99e4..a672ed192d33 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c @@ -202,7 +202,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) /* Select the proper current console and verify * sanity of the situation under the console lock. */ - acquire_console_sem(); + console_lock(); attr = (currcons & 128); currcons = (currcons & 127); @@ -336,9 +336,9 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) * the pagefault handling code may want to call printk(). */ - release_console_sem(); + console_unlock(); ret = copy_to_user(buf, con_buf_start, orig_count); - acquire_console_sem(); + console_lock(); if (ret) { read += (orig_count - ret); @@ -354,7 +354,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) if (read) ret = read; unlock_out: - release_console_sem(); + console_unlock(); mutex_unlock(&con_buf_mtx); return ret; } @@ -379,7 +379,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) /* Select the proper current console and verify * sanity of the situation under the console lock. */ - acquire_console_sem(); + console_lock(); attr = (currcons & 128); currcons = (currcons & 127); @@ -414,9 +414,9 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) /* Temporarily drop the console lock so that we can read * in the write data from userspace safely. */ - release_console_sem(); + console_unlock(); ret = copy_from_user(con_buf, buf, this_round); - acquire_console_sem(); + console_lock(); if (ret) { this_round -= ret; @@ -542,7 +542,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) vcs_scr_updated(vc); unlock_out: - release_console_sem(); + console_unlock(); mutex_unlock(&con_buf_mtx); diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 76407eca9ab0..147ede3423df 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1003,9 +1003,9 @@ static int vt_resize(struct tty_struct *tty, struct winsize *ws) struct vc_data *vc = tty->driver_data; int ret; - acquire_console_sem(); + console_lock(); ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row); - release_console_sem(); + console_unlock(); return ret; } @@ -1271,7 +1271,7 @@ static void default_attr(struct vc_data *vc) vc->vc_color = vc->vc_def_color; } -/* console_sem is held */ +/* console_lock is held */ static void csi_m(struct vc_data *vc) { int i; @@ -1415,7 +1415,7 @@ int mouse_reporting(void) return vc_cons[fg_console].d->vc_report_mouse; } -/* console_sem is held */ +/* console_lock is held */ static void set_mode(struct vc_data *vc, int on_off) { int i; @@ -1485,7 +1485,7 @@ static void set_mode(struct vc_data *vc, int on_off) } } -/* console_sem is held */ +/* console_lock is held */ static void setterm_command(struct vc_data *vc) { switch(vc->vc_par[0]) { @@ -1545,7 +1545,7 @@ static void setterm_command(struct vc_data *vc) } } -/* console_sem is held */ +/* console_lock is held */ static void csi_at(struct vc_data *vc, unsigned int nr) { if (nr > vc->vc_cols - vc->vc_x) @@ -1555,7 +1555,7 @@ static void csi_at(struct vc_data *vc, unsigned int nr) insert_char(vc, nr); } -/* console_sem is held */ +/* console_lock is held */ static void csi_L(struct vc_data *vc, unsigned int nr) { if (nr > vc->vc_rows - vc->vc_y) @@ -1566,7 +1566,7 @@ static void csi_L(struct vc_data *vc, unsigned int nr) vc->vc_need_wrap = 0; } -/* console_sem is held */ +/* console_lock is held */ static void csi_P(struct vc_data *vc, unsigned int nr) { if (nr > vc->vc_cols - vc->vc_x) @@ -1576,7 +1576,7 @@ static void csi_P(struct vc_data *vc, unsigned int nr) delete_char(vc, nr); } -/* console_sem is held */ +/* console_lock is held */ static void csi_M(struct vc_data *vc, unsigned int nr) { if (nr > vc->vc_rows - vc->vc_y) @@ -1587,7 +1587,7 @@ static void csi_M(struct vc_data *vc, unsigned int nr) vc->vc_need_wrap = 0; } -/* console_sem is held (except via vc_init->reset_terminal */ +/* console_lock is held (except via vc_init->reset_terminal */ static void save_cur(struct vc_data *vc) { vc->vc_saved_x = vc->vc_x; @@ -1603,7 +1603,7 @@ static void save_cur(struct vc_data *vc) vc->vc_saved_G1 = vc->vc_G1_charset; } -/* console_sem is held */ +/* console_lock is held */ static void restore_cur(struct vc_data *vc) { gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y); @@ -1625,7 +1625,7 @@ enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, ESpalette }; -/* console_sem is held (except via vc_init()) */ +/* console_lock is held (except via vc_init()) */ static void reset_terminal(struct vc_data *vc, int do_clear) { vc->vc_top = 0; @@ -1685,7 +1685,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear) csi_J(vc, 2); } -/* console_sem is held */ +/* console_lock is held */ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) { /* @@ -2119,7 +2119,7 @@ static int is_double_width(uint32_t ucs) return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1); } -/* acquires console_sem */ +/* acquires console_lock */ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count) { #ifdef VT_BUF_VRAM_ONLY @@ -2147,11 +2147,11 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co might_sleep(); - acquire_console_sem(); + console_lock(); vc = tty->driver_data; if (vc == NULL) { printk(KERN_ERR "vt: argh, driver_data is NULL !\n"); - release_console_sem(); + console_unlock(); return 0; } @@ -2159,7 +2159,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co if (!vc_cons_allocated(currcons)) { /* could this happen? */ printk_once("con_write: tty %d not allocated\n", currcons+1); - release_console_sem(); + console_unlock(); return 0; } @@ -2375,7 +2375,7 @@ rescan_last_byte: } FLUSH console_conditional_schedule(); - release_console_sem(); + console_unlock(); notify_update(vc); return n; #undef FLUSH @@ -2388,11 +2388,11 @@ rescan_last_byte: * us to do the switches asynchronously (needed when we want * to switch due to a keyboard interrupt). Synchronization * with other console code and prevention of re-entrancy is - * ensured with console_sem. + * ensured with console_lock. */ static void console_callback(struct work_struct *ignored) { - acquire_console_sem(); + console_lock(); if (want_console >= 0) { if (want_console != fg_console && @@ -2422,7 +2422,7 @@ static void console_callback(struct work_struct *ignored) } notify_update(vc_cons[fg_console].d); - release_console_sem(); + console_unlock(); } int set_console(int nr) @@ -2603,7 +2603,7 @@ static struct console vt_console_driver = { */ /* - * Generally a bit racy with respect to console_sem(). + * Generally a bit racy with respect to console_lock();. * * There are some functions which don't need it. * @@ -2629,17 +2629,17 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) switch (type) { case TIOCL_SETSEL: - acquire_console_sem(); + console_lock(); ret = set_selection((struct tiocl_selection __user *)(p+1), tty); - release_console_sem(); + console_unlock(); break; case TIOCL_PASTESEL: ret = paste_selection(tty); break; case TIOCL_UNBLANKSCREEN: - acquire_console_sem(); + console_lock(); unblank_screen(); - release_console_sem(); + console_unlock(); break; case TIOCL_SELLOADLUT: ret = sel_loadlut(p); @@ -2688,10 +2688,10 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) } break; case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */ - acquire_console_sem(); + console_lock(); ignore_poke = 1; do_blank_screen(0); - release_console_sem(); + console_unlock(); break; case TIOCL_BLANKEDSCREEN: ret = console_blanked; @@ -2790,11 +2790,11 @@ static void con_flush_chars(struct tty_struct *tty) return; /* if we race with con_close(), vt may be null */ - acquire_console_sem(); + console_lock(); vc = tty->driver_data; if (vc) set_cursor(vc); - release_console_sem(); + console_unlock(); } /* @@ -2805,7 +2805,7 @@ static int con_open(struct tty_struct *tty, struct file *filp) unsigned int currcons = tty->index; int ret = 0; - acquire_console_sem(); + console_lock(); if (tty->driver_data == NULL) { ret = vc_allocate(currcons); if (ret == 0) { @@ -2813,7 +2813,7 @@ static int con_open(struct tty_struct *tty, struct file *filp) /* Still being freed */ if (vc->port.tty) { - release_console_sem(); + console_unlock(); return -ERESTARTSYS; } tty->driver_data = vc; @@ -2827,11 +2827,11 @@ static int con_open(struct tty_struct *tty, struct file *filp) tty->termios->c_iflag |= IUTF8; else tty->termios->c_iflag &= ~IUTF8; - release_console_sem(); + console_unlock(); return ret; } } - release_console_sem(); + console_unlock(); return ret; } @@ -2844,9 +2844,9 @@ static void con_shutdown(struct tty_struct *tty) { struct vc_data *vc = tty->driver_data; BUG_ON(vc == NULL); - acquire_console_sem(); + console_lock(); vc->port.tty = NULL; - release_console_sem(); + console_unlock(); tty_shutdown(tty); } @@ -2893,13 +2893,13 @@ static int __init con_init(void) struct vc_data *vc; unsigned int currcons = 0, i; - acquire_console_sem(); + console_lock(); if (conswitchp) display_desc = conswitchp->con_startup(); if (!display_desc) { fg_console = 0; - release_console_sem(); + console_unlock(); return 0; } @@ -2946,7 +2946,7 @@ static int __init con_init(void) printable = 1; printk("\n"); - release_console_sem(); + console_unlock(); #ifdef CONFIG_VT_CONSOLE register_console(&vt_console_driver); @@ -2994,7 +2994,7 @@ int __init vty_init(const struct file_operations *console_fops) if (IS_ERR(tty0dev)) tty0dev = NULL; else - device_create_file(tty0dev, &dev_attr_active); + WARN_ON(device_create_file(tty0dev, &dev_attr_active) < 0); vcs_init(); @@ -3037,7 +3037,7 @@ static int bind_con_driver(const struct consw *csw, int first, int last, if (!try_module_get(owner)) return -ENODEV; - acquire_console_sem(); + console_lock(); /* check if driver is registered */ for (i = 0; i < MAX_NR_CON_DRIVER; i++) { @@ -3122,7 +3122,7 @@ static int bind_con_driver(const struct consw *csw, int first, int last, retval = 0; err: - release_console_sem(); + console_unlock(); module_put(owner); return retval; }; @@ -3171,7 +3171,7 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt) if (!try_module_get(owner)) return -ENODEV; - acquire_console_sem(); + console_lock(); /* check if driver is registered and if it is unbindable */ for (i = 0; i < MAX_NR_CON_DRIVER; i++) { @@ -3185,7 +3185,7 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt) } if (retval) { - release_console_sem(); + console_unlock(); goto err; } @@ -3204,12 +3204,12 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt) } if (retval) { - release_console_sem(); + console_unlock(); goto err; } if (!con_is_bound(csw)) { - release_console_sem(); + console_unlock(); goto err; } @@ -3238,7 +3238,7 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt) if (!con_is_bound(csw)) con_driver->flag &= ~CON_DRIVER_FLAG_INIT; - release_console_sem(); + console_unlock(); /* ignore return value, binding should not fail */ bind_con_driver(defcsw, first, last, deflt); err: @@ -3538,14 +3538,14 @@ int register_con_driver(const struct consw *csw, int first, int last) if (!try_module_get(owner)) return -ENODEV; - acquire_console_sem(); + console_lock(); for (i = 0; i < MAX_NR_CON_DRIVER; i++) { con_driver = ®istered_con_driver[i]; /* already registered */ if (con_driver->con == csw) - retval = -EINVAL; + retval = -EBUSY; } if (retval) @@ -3592,7 +3592,7 @@ int register_con_driver(const struct consw *csw, int first, int last) } err: - release_console_sem(); + console_unlock(); module_put(owner); return retval; } @@ -3613,7 +3613,7 @@ int unregister_con_driver(const struct consw *csw) { int i, retval = -ENODEV; - acquire_console_sem(); + console_lock(); /* cannot unregister a bound driver */ if (con_is_bound(csw)) @@ -3639,7 +3639,7 @@ int unregister_con_driver(const struct consw *csw) } } err: - release_console_sem(); + console_unlock(); return retval; } EXPORT_SYMBOL(unregister_con_driver); @@ -3656,7 +3656,12 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt) int err; err = register_con_driver(csw, first, last); - + /* if we get an busy error we still want to bind the console driver + * and return success, as we may have unbound the console driver + Â * but not unregistered it. + */ + if (err == -EBUSY) + err = 0; if (!err) bind_con_driver(csw, first, last, deflt); @@ -3934,9 +3939,9 @@ int con_set_cmap(unsigned char __user *arg) { int rc; - acquire_console_sem(); + console_lock(); rc = set_get_cmap (arg,1); - release_console_sem(); + console_unlock(); return rc; } @@ -3945,9 +3950,9 @@ int con_get_cmap(unsigned char __user *arg) { int rc; - acquire_console_sem(); + console_lock(); rc = set_get_cmap (arg,0); - release_console_sem(); + console_unlock(); return rc; } @@ -3994,12 +3999,12 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op) } else font.data = NULL; - acquire_console_sem(); + console_lock(); if (vc->vc_sw->con_font_get) rc = vc->vc_sw->con_font_get(vc, &font); else rc = -ENOSYS; - release_console_sem(); + console_unlock(); if (rc) goto out; @@ -4076,12 +4081,12 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op) font.data = memdup_user(op->data, size); if (IS_ERR(font.data)) return PTR_ERR(font.data); - acquire_console_sem(); + console_lock(); if (vc->vc_sw->con_font_set) rc = vc->vc_sw->con_font_set(vc, &font, op->flags); else rc = -ENOSYS; - release_console_sem(); + console_unlock(); kfree(font.data); return rc; } @@ -4103,12 +4108,12 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op) else name[MAX_FONT_NAME - 1] = 0; - acquire_console_sem(); + console_lock(); if (vc->vc_sw->con_font_default) rc = vc->vc_sw->con_font_default(vc, &font, s); else rc = -ENOSYS; - release_console_sem(); + console_unlock(); if (!rc) { op->width = font.width; op->height = font.height; @@ -4124,7 +4129,7 @@ static int con_font_copy(struct vc_data *vc, struct console_font_op *op) if (vc->vc_mode != KD_TEXT) return -EINVAL; - acquire_console_sem(); + console_lock(); if (!vc->vc_sw->con_font_copy) rc = -ENOSYS; else if (con < 0 || !vc_cons_allocated(con)) @@ -4133,7 +4138,7 @@ static int con_font_copy(struct vc_data *vc, struct console_font_op *op) rc = 0; else rc = vc->vc_sw->con_font_copy(vc, con); - release_console_sem(); + console_unlock(); return rc; } diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 6b68a0fb4611..1235ebda6e1c 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -649,12 +649,12 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, /* * explicitly blank/unblank the screen if switching modes */ - acquire_console_sem(); + console_lock(); if (arg == KD_TEXT) do_unblank_screen(1); else do_blank_screen(1); - release_console_sem(); + console_unlock(); break; case KDGETMODE: @@ -893,7 +893,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ret = -EINVAL; goto out; } - acquire_console_sem(); + console_lock(); vc->vt_mode = tmp; /* the frsig is ignored, so we set it to 0 */ vc->vt_mode.frsig = 0; @@ -901,7 +901,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, vc->vt_pid = get_pid(task_pid(current)); /* no switch is required -- saw@shade.msu.ru */ vc->vt_newvt = -1; - release_console_sem(); + console_unlock(); break; } @@ -910,9 +910,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, struct vt_mode tmp; int rc; - acquire_console_sem(); + console_lock(); memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode)); - release_console_sem(); + console_unlock(); rc = copy_to_user(up, &tmp, sizeof(struct vt_mode)); if (rc) @@ -965,9 +965,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ret = -ENXIO; else { arg--; - acquire_console_sem(); + console_lock(); ret = vc_allocate(arg); - release_console_sem(); + console_unlock(); if (ret) break; set_console(arg); @@ -990,7 +990,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ret = -ENXIO; else { vsa.console--; - acquire_console_sem(); + console_lock(); ret = vc_allocate(vsa.console); if (ret == 0) { struct vc_data *nvc; @@ -1003,7 +1003,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, put_pid(nvc->vt_pid); nvc->vt_pid = get_pid(task_pid(current)); } - release_console_sem(); + console_unlock(); if (ret) break; /* Commence switch and lock */ @@ -1044,7 +1044,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, /* * Switching-from response */ - acquire_console_sem(); + console_lock(); if (vc->vt_newvt >= 0) { if (arg == 0) /* @@ -1063,7 +1063,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, vc->vt_newvt = -1; ret = vc_allocate(newvt); if (ret) { - release_console_sem(); + console_unlock(); break; } /* @@ -1083,7 +1083,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, if (arg != VT_ACKACQ) ret = -EINVAL; } - release_console_sem(); + console_unlock(); break; /* @@ -1096,20 +1096,20 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, } if (arg == 0) { /* deallocate all unused consoles, but leave 0 */ - acquire_console_sem(); + console_lock(); for (i=1; i<MAX_NR_CONSOLES; i++) if (! VT_BUSY(i)) vc_deallocate(i); - release_console_sem(); + console_unlock(); } else { /* deallocate a single console, if possible */ arg--; if (VT_BUSY(arg)) ret = -EBUSY; else if (arg) { /* leave 0 */ - acquire_console_sem(); + console_lock(); vc_deallocate(arg); - release_console_sem(); + console_unlock(); } } break; @@ -1126,7 +1126,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, get_user(cc, &vtsizes->v_cols)) ret = -EFAULT; else { - acquire_console_sem(); + console_lock(); for (i = 0; i < MAX_NR_CONSOLES; i++) { vc = vc_cons[i].d; @@ -1135,7 +1135,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, vc_resize(vc_cons[i].d, cc, ll); } } - release_console_sem(); + console_unlock(); } break; } @@ -1187,14 +1187,14 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, for (i = 0; i < MAX_NR_CONSOLES; i++) { if (!vc_cons[i].d) continue; - acquire_console_sem(); + console_lock(); if (vlin) vc_cons[i].d->vc_scan_lines = vlin; if (clin) vc_cons[i].d->vc_font.height = clin; vc_cons[i].d->vc_resize_user = 1; vc_resize(vc_cons[i].d, cc, ll); - release_console_sem(); + console_unlock(); } break; } @@ -1367,7 +1367,7 @@ void vc_SAK(struct work_struct *work) struct vc_data *vc; struct tty_struct *tty; - acquire_console_sem(); + console_lock(); vc = vc_con->d; if (vc) { tty = vc->port.tty; @@ -1379,7 +1379,7 @@ void vc_SAK(struct work_struct *work) __do_SAK(tty); reset_vc(vc); } - release_console_sem(); + console_unlock(); } #ifdef CONFIG_COMPAT @@ -1737,10 +1737,10 @@ int vt_move_to_console(unsigned int vt, int alloc) { int prev; - acquire_console_sem(); + console_lock(); /* Graphics mode - up to X */ if (disable_vt_switch) { - release_console_sem(); + console_unlock(); return 0; } prev = fg_console; @@ -1748,7 +1748,7 @@ int vt_move_to_console(unsigned int vt, int alloc) if (alloc && vc_allocate(vt)) { /* we can't have a free VC for now. Too bad, * we don't want to mess the screen for now. */ - release_console_sem(); + console_unlock(); return -ENOSPC; } @@ -1758,10 +1758,10 @@ int vt_move_to_console(unsigned int vt, int alloc) * Let the calling function know so it can decide * what to do. */ - release_console_sem(); + console_unlock(); return -EIO; } - release_console_sem(); + console_unlock(); tty_lock(); if (vt_waitactive(vt + 1)) { pr_debug("Suspend: Can't switch VCs."); @@ -1781,8 +1781,8 @@ int vt_move_to_console(unsigned int vt, int alloc) */ void pm_set_vt_switch(int do_switch) { - acquire_console_sem(); + console_lock(); disable_vt_switch = !do_switch; - release_console_sem(); + console_unlock(); } EXPORT_SYMBOL(pm_set_vt_switch); diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index d6ede989ff22..4ab49d4eebf4 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1607,6 +1607,7 @@ static const struct usb_device_id acm_ids[] = { { NOKIA_PCSUITE_ACM_INFO(0x0154), }, /* Nokia 5800 XpressMusic */ { NOKIA_PCSUITE_ACM_INFO(0x04ce), }, /* Nokia E90 */ { NOKIA_PCSUITE_ACM_INFO(0x01d4), }, /* Nokia E55 */ + { NOKIA_PCSUITE_ACM_INFO(0x0302), }, /* Nokia N8 */ { SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */ /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */ diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 6ee4451bfe2d..47085e5879ab 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -342,7 +342,7 @@ static ssize_t wdm_write goto outnp; } - if (!file->f_flags && O_NONBLOCK) + if (!(file->f_flags & O_NONBLOCK)) r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE, &desc->flags)); else diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index 9da250563027..df502a98d0df 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -192,12 +192,12 @@ int usb_create_ep_devs(struct device *parent, ep_dev->dev.parent = parent; ep_dev->dev.release = ep_device_release; dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress); - device_enable_async_suspend(&ep_dev->dev); retval = device_register(&ep_dev->dev); if (retval) goto error_register; + device_enable_async_suspend(&ep_dev->dev); endpoint->ep_dev = ep_dev; return retval; diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index b55d46070a25..f71e8e307e0f 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -405,7 +405,12 @@ static int suspend_common(struct device *dev, bool do_wakeup) return retval; } - synchronize_irq(pci_dev->irq); + /* If MSI-X is enabled, the driver will have synchronized all vectors + * in pci_suspend(). If MSI or legacy PCI is enabled, that will be + * synchronized here. + */ + if (!hcd->msix_enabled) + synchronize_irq(pci_dev->irq); /* Downstream ports from this root hub should already be quiesced, so * there will be no DMA activity. Now we can shut down the upstream diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 6a95017fa62b..e935f71d7a34 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1955,7 +1955,6 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) dev_dbg(&rhdev->dev, "usb %s%s\n", (msg.event & PM_EVENT_AUTO ? "auto-" : ""), "resume"); - clear_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags); if (!hcd->driver->bus_resume) return -ENOENT; if (hcd->state == HC_STATE_RUNNING) @@ -1963,6 +1962,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) hcd->state = HC_STATE_RESUMING; status = hcd->driver->bus_resume(hcd); + clear_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags); if (status == 0) { /* TRSMRCY = 10 msec */ msleep(10); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b98efae6a1cf..d041c6826e43 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -676,6 +676,8 @@ static void hub_init_func3(struct work_struct *ws); static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) { struct usb_device *hdev = hub->hdev; + struct usb_hcd *hcd; + int ret; int port1; int status; bool need_debounce_delay = false; @@ -714,6 +716,25 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) usb_autopm_get_interface_no_resume( to_usb_interface(hub->intfdev)); return; /* Continues at init2: below */ + } else if (type == HUB_RESET_RESUME) { + /* The internal host controller state for the hub device + * may be gone after a host power loss on system resume. + * Update the device's info so the HW knows it's a hub. + */ + hcd = bus_to_hcd(hdev->bus); + if (hcd->driver->update_hub_device) { + ret = hcd->driver->update_hub_device(hcd, hdev, + &hub->tt, GFP_NOIO); + if (ret < 0) { + dev_err(hub->intfdev, "Host not " + "accepting hub info " + "update.\n"); + dev_err(hub->intfdev, "LS/FS devices " + "and hubs may not work " + "under this hub\n."); + } + } + hub_power_on(hub, true); } else { hub_power_on(hub, true); } @@ -2732,6 +2753,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, udev->ttport = hdev->ttport; } else if (udev->speed != USB_SPEED_HIGH && hdev->speed == USB_SPEED_HIGH) { + if (!hub->tt.hub) { + dev_err(&udev->dev, "parent hub has no TT\n"); + retval = -EINVAL; + goto fail; + } udev->tt = &hub->tt; udev->ttport = port1; } diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 1dc9739277b4..d50099675f28 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -509,7 +509,7 @@ config USB_LANGWELL select USB_GADGET_SELECTED config USB_GADGET_EG20T - boolean "Intel EG20T(Topcliff) USB Device controller" + boolean "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH UDC" depends on PCI select USB_GADGET_DUALSPEED help @@ -525,6 +525,11 @@ config USB_GADGET_EG20T This driver dose not support interrupt transfer or isochronous transfer modes. + This driver also can be used for OKI SEMICONDUCTOR's ML7213 which is + for IVI(In-Vehicle Infotainment) use. + ML7213 is companion chip for Intel Atom E6xx series. + ML7213 is completely compatible for Intel EG20T PCH. + config USB_EG20T tristate depends on USB_GADGET_EG20T @@ -541,6 +546,8 @@ config USB_GADGET_CI13XXX_MSM ci13xxx_udc core. This driver depends on OTG driver for PHY initialization, clock management, powering up VBUS, and power management. + This driver is not supported on boards like trout which + has an external PHY. Say "y" to link the driver statically, or "m" to build a dynamically linked module called "ci13xxx_msm" and force all diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index 31656a2b4ab4..a1c67ae1572a 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -76,10 +76,21 @@ static DEFINE_SPINLOCK(udc_lock); /* control endpoint description */ static const struct usb_endpoint_descriptor -ctrl_endpt_desc = { +ctrl_endpt_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, + .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX), +}; + +static const struct usb_endpoint_descriptor +ctrl_endpt_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_CONTROL, .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX), }; @@ -265,10 +276,10 @@ static int hw_device_init(void __iomem *base) hw_bank.size /= sizeof(u32); reg = hw_aread(ABS_DCCPARAMS, DCCPARAMS_DEN) >> ffs_nr(DCCPARAMS_DEN); - if (reg == 0 || reg > ENDPT_MAX) - return -ENODEV; + hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */ - hw_ep_max = reg; /* cache hw ENDPT_MAX */ + if (hw_ep_max == 0 || hw_ep_max > ENDPT_MAX) + return -ENODEV; /* setup lock mode ? */ @@ -1197,16 +1208,17 @@ static ssize_t show_qheads(struct device *dev, struct device_attribute *attr, } spin_lock_irqsave(udc->lock, flags); - for (i = 0; i < hw_ep_max; i++) { - struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; + for (i = 0; i < hw_ep_max/2; i++) { + struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i]; + struct ci13xxx_ep *mEpTx = &udc->ci13xxx_ep[i + hw_ep_max/2]; n += scnprintf(buf + n, PAGE_SIZE - n, "EP=%02i: RX=%08X TX=%08X\n", - i, (u32)mEp->qh[RX].dma, (u32)mEp->qh[TX].dma); + i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma); for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) { n += scnprintf(buf + n, PAGE_SIZE - n, " %04X: %08X %08X\n", j, - *((u32 *)mEp->qh[RX].ptr + j), - *((u32 *)mEp->qh[TX].ptr + j)); + *((u32 *)mEpRx->qh.ptr + j), + *((u32 *)mEpTx->qh.ptr + j)); } } spin_unlock_irqrestore(udc->lock, flags); @@ -1293,7 +1305,7 @@ static ssize_t show_requests(struct device *dev, struct device_attribute *attr, unsigned long flags; struct list_head *ptr = NULL; struct ci13xxx_req *req = NULL; - unsigned i, j, k, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32); + unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32); dbg_trace("[%s] %p\n", __func__, buf); if (attr == NULL || buf == NULL) { @@ -1303,22 +1315,20 @@ static ssize_t show_requests(struct device *dev, struct device_attribute *attr, spin_lock_irqsave(udc->lock, flags); for (i = 0; i < hw_ep_max; i++) - for (k = RX; k <= TX; k++) - list_for_each(ptr, &udc->ci13xxx_ep[i].qh[k].queue) - { - req = list_entry(ptr, - struct ci13xxx_req, queue); + list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue) + { + req = list_entry(ptr, struct ci13xxx_req, queue); + + n += scnprintf(buf + n, PAGE_SIZE - n, + "EP=%02i: TD=%08X %s\n", + i % hw_ep_max/2, (u32)req->dma, + ((i < hw_ep_max/2) ? "RX" : "TX")); + for (j = 0; j < qSize; j++) n += scnprintf(buf + n, PAGE_SIZE - n, - "EP=%02i: TD=%08X %s\n", - i, (u32)req->dma, - ((k == RX) ? "RX" : "TX")); - - for (j = 0; j < qSize; j++) - n += scnprintf(buf + n, PAGE_SIZE - n, - " %04X: %08X\n", j, - *((u32 *)req->ptr + j)); - } + " %04X: %08X\n", j, + *((u32 *)req->ptr + j)); + } spin_unlock_irqrestore(udc->lock, flags); return n; @@ -1467,12 +1477,12 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) * At this point it's guaranteed exclusive access to qhead * (endpt is not primed) so it's no need to use tripwire */ - mEp->qh[mEp->dir].ptr->td.next = mReq->dma; /* TERMINATE = 0 */ - mEp->qh[mEp->dir].ptr->td.token &= ~TD_STATUS; /* clear status */ + mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */ + mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */ if (mReq->req.zero == 0) - mEp->qh[mEp->dir].ptr->cap |= QH_ZLT; + mEp->qh.ptr->cap |= QH_ZLT; else - mEp->qh[mEp->dir].ptr->cap &= ~QH_ZLT; + mEp->qh.ptr->cap &= ~QH_ZLT; wmb(); /* synchronize before ep prime */ @@ -1542,11 +1552,11 @@ __acquires(mEp->lock) hw_ep_flush(mEp->num, mEp->dir); - while (!list_empty(&mEp->qh[mEp->dir].queue)) { + while (!list_empty(&mEp->qh.queue)) { /* pop oldest request */ struct ci13xxx_req *mReq = \ - list_entry(mEp->qh[mEp->dir].queue.next, + list_entry(mEp->qh.queue.next, struct ci13xxx_req, queue); list_del_init(&mReq->queue); mReq->req.status = -ESHUTDOWN; @@ -1571,8 +1581,6 @@ static int _gadget_stop_activity(struct usb_gadget *gadget) { struct usb_ep *ep; struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget); - struct ci13xxx_ep *mEp = container_of(gadget->ep0, - struct ci13xxx_ep, ep); trace("%p", gadget); @@ -1583,7 +1591,8 @@ static int _gadget_stop_activity(struct usb_gadget *gadget) gadget_for_each_ep(ep, gadget) { usb_ep_fifo_flush(ep); } - usb_ep_fifo_flush(gadget->ep0); + usb_ep_fifo_flush(&udc->ep0out.ep); + usb_ep_fifo_flush(&udc->ep0in.ep); udc->driver->disconnect(gadget); @@ -1591,11 +1600,12 @@ static int _gadget_stop_activity(struct usb_gadget *gadget) gadget_for_each_ep(ep, gadget) { usb_ep_disable(ep); } - usb_ep_disable(gadget->ep0); + usb_ep_disable(&udc->ep0out.ep); + usb_ep_disable(&udc->ep0in.ep); - if (mEp->status != NULL) { - usb_ep_free_request(gadget->ep0, mEp->status); - mEp->status = NULL; + if (udc->status != NULL) { + usb_ep_free_request(&udc->ep0in.ep, udc->status); + udc->status = NULL; } return 0; @@ -1614,7 +1624,6 @@ static void isr_reset_handler(struct ci13xxx *udc) __releases(udc->lock) __acquires(udc->lock) { - struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[0]; int retval; trace("%p", udc); @@ -1635,11 +1644,15 @@ __acquires(udc->lock) if (retval) goto done; - retval = usb_ep_enable(&mEp->ep, &ctrl_endpt_desc); + retval = usb_ep_enable(&udc->ep0out.ep, &ctrl_endpt_out_desc); + if (retval) + goto done; + + retval = usb_ep_enable(&udc->ep0in.ep, &ctrl_endpt_in_desc); if (!retval) { - mEp->status = usb_ep_alloc_request(&mEp->ep, GFP_ATOMIC); - if (mEp->status == NULL) { - usb_ep_disable(&mEp->ep); + udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_ATOMIC); + if (udc->status == NULL) { + usb_ep_disable(&udc->ep0out.ep); retval = -ENOMEM; } } @@ -1672,16 +1685,17 @@ static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req) /** * isr_get_status_response: get_status request response - * @ep: endpoint + * @udc: udc struct * @setup: setup request packet * * This function returns an error code */ -static int isr_get_status_response(struct ci13xxx_ep *mEp, +static int isr_get_status_response(struct ci13xxx *udc, struct usb_ctrlrequest *setup) __releases(mEp->lock) __acquires(mEp->lock) { + struct ci13xxx_ep *mEp = &udc->ep0in; struct usb_request *req = NULL; gfp_t gfp_flags = GFP_ATOMIC; int dir, num, retval; @@ -1736,27 +1750,23 @@ __acquires(mEp->lock) /** * isr_setup_status_phase: queues the status phase of a setup transation - * @mEp: endpoint + * @udc: udc struct * * This function returns an error code */ -static int isr_setup_status_phase(struct ci13xxx_ep *mEp) +static int isr_setup_status_phase(struct ci13xxx *udc) __releases(mEp->lock) __acquires(mEp->lock) { int retval; + struct ci13xxx_ep *mEp; - trace("%p", mEp); - - /* mEp is always valid & configured */ - - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) - mEp->dir = (mEp->dir == TX) ? RX : TX; + trace("%p", udc); - mEp->status->no_interrupt = 1; + mEp = (udc->ep0_dir == TX) ? &udc->ep0out : &udc->ep0in; spin_unlock(mEp->lock); - retval = usb_ep_queue(&mEp->ep, mEp->status, GFP_ATOMIC); + retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC); spin_lock(mEp->lock); return retval; @@ -1778,11 +1788,11 @@ __acquires(mEp->lock) trace("%p", mEp); - if (list_empty(&mEp->qh[mEp->dir].queue)) + if (list_empty(&mEp->qh.queue)) return -EINVAL; /* pop oldest request */ - mReq = list_entry(mEp->qh[mEp->dir].queue.next, + mReq = list_entry(mEp->qh.queue.next, struct ci13xxx_req, queue); list_del_init(&mReq->queue); @@ -1794,10 +1804,10 @@ __acquires(mEp->lock) dbg_done(_usb_addr(mEp), mReq->ptr->token, retval); - if (!list_empty(&mEp->qh[mEp->dir].queue)) { + if (!list_empty(&mEp->qh.queue)) { struct ci13xxx_req* mReqEnq; - mReqEnq = list_entry(mEp->qh[mEp->dir].queue.next, + mReqEnq = list_entry(mEp->qh.queue.next, struct ci13xxx_req, queue); _hardware_enqueue(mEp, mReqEnq); } @@ -1836,16 +1846,14 @@ __acquires(udc->lock) int type, num, err = -EINVAL; struct usb_ctrlrequest req; - if (mEp->desc == NULL) continue; /* not configured */ - if ((mEp->dir == RX && hw_test_and_clear_complete(i)) || - (mEp->dir == TX && hw_test_and_clear_complete(i + 16))) { + if (hw_test_and_clear_complete(i)) { err = isr_tr_complete_low(mEp); if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { if (err > 0) /* needs status phase */ - err = isr_setup_status_phase(mEp); + err = isr_setup_status_phase(udc); if (err < 0) { dbg_event(_usb_addr(mEp), "ERROR", err); @@ -1866,15 +1874,22 @@ __acquires(udc->lock) continue; } + /* + * Flush data and handshake transactions of previous + * setup packet. + */ + _ep_nuke(&udc->ep0out); + _ep_nuke(&udc->ep0in); + /* read_setup_packet */ do { hw_test_and_set_setup_guard(); - memcpy(&req, &mEp->qh[RX].ptr->setup, sizeof(req)); + memcpy(&req, &mEp->qh.ptr->setup, sizeof(req)); } while (!hw_test_and_clear_setup_guard()); type = req.bRequestType; - mEp->dir = (type & USB_DIR_IN) ? TX : RX; + udc->ep0_dir = (type & USB_DIR_IN) ? TX : RX; dbg_setup(_usb_addr(mEp), &req); @@ -1895,7 +1910,7 @@ __acquires(udc->lock) if (err) break; } - err = isr_setup_status_phase(mEp); + err = isr_setup_status_phase(udc); break; case USB_REQ_GET_STATUS: if (type != (USB_DIR_IN|USB_RECIP_DEVICE) && @@ -1905,7 +1920,7 @@ __acquires(udc->lock) if (le16_to_cpu(req.wLength) != 2 || le16_to_cpu(req.wValue) != 0) break; - err = isr_get_status_response(mEp, &req); + err = isr_get_status_response(udc, &req); break; case USB_REQ_SET_ADDRESS: if (type != (USB_DIR_OUT|USB_RECIP_DEVICE)) @@ -1916,7 +1931,7 @@ __acquires(udc->lock) err = hw_usb_set_address((u8)le16_to_cpu(req.wValue)); if (err) break; - err = isr_setup_status_phase(mEp); + err = isr_setup_status_phase(udc); break; case USB_REQ_SET_FEATURE: if (type != (USB_DIR_OUT|USB_RECIP_ENDPOINT) && @@ -1932,12 +1947,12 @@ __acquires(udc->lock) spin_lock(udc->lock); if (err) break; - err = isr_setup_status_phase(mEp); + err = isr_setup_status_phase(udc); break; default: delegate: if (req.wLength == 0) /* no data phase */ - mEp->dir = TX; + udc->ep0_dir = TX; spin_unlock(udc->lock); err = udc->driver->setup(&udc->gadget, &req); @@ -1968,7 +1983,7 @@ static int ep_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) { struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - int direction, retval = 0; + int retval = 0; unsigned long flags; trace("%p, %p", ep, desc); @@ -1982,7 +1997,7 @@ static int ep_enable(struct usb_ep *ep, mEp->desc = desc; - if (!list_empty(&mEp->qh[mEp->dir].queue)) + if (!list_empty(&mEp->qh.queue)) warn("enabling a non-empty endpoint!"); mEp->dir = usb_endpoint_dir_in(desc) ? TX : RX; @@ -1991,29 +2006,22 @@ static int ep_enable(struct usb_ep *ep, mEp->ep.maxpacket = __constant_le16_to_cpu(desc->wMaxPacketSize); - direction = mEp->dir; - do { - dbg_event(_usb_addr(mEp), "ENABLE", 0); + dbg_event(_usb_addr(mEp), "ENABLE", 0); - mEp->qh[mEp->dir].ptr->cap = 0; + mEp->qh.ptr->cap = 0; - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) - mEp->qh[mEp->dir].ptr->cap |= QH_IOS; - else if (mEp->type == USB_ENDPOINT_XFER_ISOC) - mEp->qh[mEp->dir].ptr->cap &= ~QH_MULT; - else - mEp->qh[mEp->dir].ptr->cap &= ~QH_ZLT; - - mEp->qh[mEp->dir].ptr->cap |= - (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT; - mEp->qh[mEp->dir].ptr->td.next |= TD_TERMINATE; /* needed? */ - - retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type); + if (mEp->type == USB_ENDPOINT_XFER_CONTROL) + mEp->qh.ptr->cap |= QH_IOS; + else if (mEp->type == USB_ENDPOINT_XFER_ISOC) + mEp->qh.ptr->cap &= ~QH_MULT; + else + mEp->qh.ptr->cap &= ~QH_ZLT; - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) - mEp->dir = (mEp->dir == TX) ? RX : TX; + mEp->qh.ptr->cap |= + (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT; + mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */ - } while (mEp->dir != direction); + retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type); spin_unlock_irqrestore(mEp->lock, flags); return retval; @@ -2146,7 +2154,7 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req, spin_lock_irqsave(mEp->lock, flags); if (mEp->type == USB_ENDPOINT_XFER_CONTROL && - !list_empty(&mEp->qh[mEp->dir].queue)) { + !list_empty(&mEp->qh.queue)) { _ep_nuke(mEp); retval = -EOVERFLOW; warn("endpoint ctrl %X nuked", _usb_addr(mEp)); @@ -2170,9 +2178,9 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req, /* push request */ mReq->req.status = -EINPROGRESS; mReq->req.actual = 0; - list_add_tail(&mReq->queue, &mEp->qh[mEp->dir].queue); + list_add_tail(&mReq->queue, &mEp->qh.queue); - if (list_is_singular(&mEp->qh[mEp->dir].queue)) + if (list_is_singular(&mEp->qh.queue)) retval = _hardware_enqueue(mEp, mReq); if (retval == -EALREADY) { @@ -2199,7 +2207,7 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req) trace("%p, %p", ep, req); if (ep == NULL || req == NULL || mEp->desc == NULL || - list_empty(&mReq->queue) || list_empty(&mEp->qh[mEp->dir].queue)) + list_empty(&mReq->queue) || list_empty(&mEp->qh.queue)) return -EINVAL; spin_lock_irqsave(mEp->lock, flags); @@ -2244,7 +2252,7 @@ static int ep_set_halt(struct usb_ep *ep, int value) #ifndef STALL_IN /* g_file_storage MS compliant but g_zero fails chapter 9 compliance */ if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX && - !list_empty(&mEp->qh[mEp->dir].queue)) { + !list_empty(&mEp->qh.queue)) { spin_unlock_irqrestore(mEp->lock, flags); return -EAGAIN; } @@ -2355,7 +2363,7 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active) if (is_active) { pm_runtime_get_sync(&_gadget->dev); hw_device_reset(udc); - hw_device_state(udc->ci13xxx_ep[0].qh[RX].dma); + hw_device_state(udc->ep0out.qh.dma); } else { hw_device_state(0); if (udc->udc_driver->notify_event) @@ -2390,7 +2398,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { struct ci13xxx *udc = _udc; - unsigned long i, k, flags; + unsigned long flags; + int i, j; int retval = -ENOMEM; trace("%p", driver); @@ -2427,45 +2436,46 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, info("hw_ep_max = %d", hw_ep_max); - udc->driver = driver; udc->gadget.dev.driver = NULL; retval = 0; - for (i = 0; i < hw_ep_max; i++) { - struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; + for (i = 0; i < hw_ep_max/2; i++) { + for (j = RX; j <= TX; j++) { + int k = i + j * hw_ep_max/2; + struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k]; - scnprintf(mEp->name, sizeof(mEp->name), "ep%i", (int)i); + scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i, + (j == TX) ? "in" : "out"); - mEp->lock = udc->lock; - mEp->device = &udc->gadget.dev; - mEp->td_pool = udc->td_pool; + mEp->lock = udc->lock; + mEp->device = &udc->gadget.dev; + mEp->td_pool = udc->td_pool; - mEp->ep.name = mEp->name; - mEp->ep.ops = &usb_ep_ops; - mEp->ep.maxpacket = CTRL_PAYLOAD_MAX; + mEp->ep.name = mEp->name; + mEp->ep.ops = &usb_ep_ops; + mEp->ep.maxpacket = CTRL_PAYLOAD_MAX; - /* this allocation cannot be random */ - for (k = RX; k <= TX; k++) { - INIT_LIST_HEAD(&mEp->qh[k].queue); + INIT_LIST_HEAD(&mEp->qh.queue); spin_unlock_irqrestore(udc->lock, flags); - mEp->qh[k].ptr = dma_pool_alloc(udc->qh_pool, - GFP_KERNEL, - &mEp->qh[k].dma); + mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL, + &mEp->qh.dma); spin_lock_irqsave(udc->lock, flags); - if (mEp->qh[k].ptr == NULL) + if (mEp->qh.ptr == NULL) retval = -ENOMEM; else - memset(mEp->qh[k].ptr, 0, - sizeof(*mEp->qh[k].ptr)); - } - if (i == 0) - udc->gadget.ep0 = &mEp->ep; - else + memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr)); + + /* skip ep0 out and in endpoints */ + if (i == 0) + continue; + list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list); + } } if (retval) goto done; + udc->gadget.ep0 = &udc->ep0in.ep; /* bind gadget */ driver->driver.bus = NULL; udc->gadget.dev.driver = &driver->driver; @@ -2479,6 +2489,7 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, goto done; } + udc->driver = driver; pm_runtime_get_sync(&udc->gadget.dev); if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) { if (udc->vbus_active) { @@ -2490,14 +2501,12 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, } } - retval = hw_device_state(udc->ci13xxx_ep[0].qh[RX].dma); + retval = hw_device_state(udc->ep0out.qh.dma); if (retval) pm_runtime_put_sync(&udc->gadget.dev); done: spin_unlock_irqrestore(udc->lock, flags); - if (retval) - usb_gadget_unregister_driver(driver); return retval; } EXPORT_SYMBOL(usb_gadget_probe_driver); @@ -2510,7 +2519,7 @@ EXPORT_SYMBOL(usb_gadget_probe_driver); int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) { struct ci13xxx *udc = _udc; - unsigned long i, k, flags; + unsigned long i, flags; trace("%p", driver); @@ -2546,17 +2555,14 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) for (i = 0; i < hw_ep_max; i++) { struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; - if (i == 0) - udc->gadget.ep0 = NULL; - else if (!list_empty(&mEp->ep.ep_list)) + if (!list_empty(&mEp->ep.ep_list)) list_del_init(&mEp->ep.ep_list); - for (k = RX; k <= TX; k++) - if (mEp->qh[k].ptr != NULL) - dma_pool_free(udc->qh_pool, - mEp->qh[k].ptr, mEp->qh[k].dma); + if (mEp->qh.ptr != NULL) + dma_pool_free(udc->qh_pool, mEp->qh.ptr, mEp->qh.dma); } + udc->gadget.ep0 = NULL; udc->driver = NULL; spin_unlock_irqrestore(udc->lock, flags); diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h index f61fed07f76b..a2492b65f98c 100644 --- a/drivers/usb/gadget/ci13xxx_udc.h +++ b/drivers/usb/gadget/ci13xxx_udc.h @@ -20,7 +20,7 @@ * DEFINE *****************************************************************************/ #define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */ -#define ENDPT_MAX (16) +#define ENDPT_MAX (32) #define CTRL_PAYLOAD_MAX (64) #define RX (0) /* similar to USB_DIR_OUT but can be used as an index */ #define TX (1) /* similar to USB_DIR_IN but can be used as an index */ @@ -88,8 +88,7 @@ struct ci13xxx_ep { struct list_head queue; struct ci13xxx_qh *ptr; dma_addr_t dma; - } qh[2]; - struct usb_request *status; + } qh; int wedge; /* global resources */ @@ -119,9 +118,13 @@ struct ci13xxx { struct dma_pool *qh_pool; /* DMA pool for queue heads */ struct dma_pool *td_pool; /* DMA pool for transfer descs */ + struct usb_request *status; /* ep0 status request */ struct usb_gadget gadget; /* USB slave device */ struct ci13xxx_ep ci13xxx_ep[ENDPT_MAX]; /* extended endpts */ + u32 ep0_dir; /* ep0 direction */ +#define ep0out ci13xxx_ep[0] +#define ep0in ci13xxx_ep[16] struct usb_gadget_driver *driver; /* 3rd party gadget driver */ struct ci13xxx_udc_driver *udc_driver; /* device controller driver */ diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index f6ff8456d52d..1ba4befe336b 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -928,8 +928,9 @@ unknown: */ switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_INTERFACE: - if (cdev->config) - f = cdev->config->interface[intf]; + if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES) + break; + f = cdev->config->interface[intf]; break; case USB_RECIP_ENDPOINT: diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index b5dbb2308f56..6d8e533949eb 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -293,6 +293,7 @@ #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> +#include <linux/usb/composite.h> #include "gadget_chips.h" @@ -2763,7 +2764,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, return ERR_PTR(-ENOMEM); common->free_storage_on_release = 1; } else { - memset(common, 0, sizeof common); + memset(common, 0, sizeof *common); common->free_storage_on_release = 0; } diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index 0c8dd81dddca..b120dbb64d0f 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -198,10 +198,10 @@ #define PCH_UDC_BRLEN 0x0F /* Burst length */ #define PCH_UDC_THLEN 0x1F /* Threshold length */ /* Value of EP Buffer Size */ -#define UDC_EP0IN_BUFF_SIZE 64 -#define UDC_EPIN_BUFF_SIZE 512 -#define UDC_EP0OUT_BUFF_SIZE 64 -#define UDC_EPOUT_BUFF_SIZE 512 +#define UDC_EP0IN_BUFF_SIZE 16 +#define UDC_EPIN_BUFF_SIZE 256 +#define UDC_EP0OUT_BUFF_SIZE 16 +#define UDC_EPOUT_BUFF_SIZE 256 /* Value of EP maximum packet size */ #define UDC_EP0IN_MAX_PKT_SIZE 64 #define UDC_EP0OUT_MAX_PKT_SIZE 64 @@ -351,7 +351,7 @@ struct pch_udc_dev { struct pci_pool *data_requests; struct pci_pool *stp_requests; dma_addr_t dma_addr; - unsigned long ep0out_buf[64]; + void *ep0out_buf; struct usb_ctrlrequest setup_data; unsigned long phys_addr; void __iomem *base_addr; @@ -361,6 +361,8 @@ struct pch_udc_dev { #define PCH_UDC_PCI_BAR 1 #define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808 +#define PCI_VENDOR_ID_ROHM 0x10DB +#define PCI_DEVICE_ID_ML7213_IOH_UDC 0x801D static const char ep0_string[] = "ep0in"; static DEFINE_SPINLOCK(udc_stall_spinlock); /* stall spin lock */ @@ -1219,11 +1221,11 @@ static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req, dev = ep->dev; if (req->dma_mapped) { if (ep->in) - pci_unmap_single(dev->pdev, req->req.dma, - req->req.length, PCI_DMA_TODEVICE); + dma_unmap_single(&dev->pdev->dev, req->req.dma, + req->req.length, DMA_TO_DEVICE); else - pci_unmap_single(dev->pdev, req->req.dma, - req->req.length, PCI_DMA_FROMDEVICE); + dma_unmap_single(&dev->pdev->dev, req->req.dma, + req->req.length, DMA_FROM_DEVICE); req->dma_mapped = 0; req->req.dma = DMA_ADDR_INVALID; } @@ -1414,7 +1416,6 @@ static void pch_udc_start_rxrequest(struct pch_udc_ep *ep, pch_udc_clear_dma(ep->dev, DMA_DIR_RX); td_data = req->td_data; - ep->td_data = req->td_data; /* Set the status bits for all descriptors */ while (1) { td_data->status = (td_data->status & ~PCH_UDC_BUFF_STS) | @@ -1613,15 +1614,19 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq, if (usbreq->length && ((usbreq->dma == DMA_ADDR_INVALID) || !usbreq->dma)) { if (ep->in) - usbreq->dma = pci_map_single(dev->pdev, usbreq->buf, - usbreq->length, PCI_DMA_TODEVICE); + usbreq->dma = dma_map_single(&dev->pdev->dev, + usbreq->buf, + usbreq->length, + DMA_TO_DEVICE); else - usbreq->dma = pci_map_single(dev->pdev, usbreq->buf, - usbreq->length, PCI_DMA_FROMDEVICE); + usbreq->dma = dma_map_single(&dev->pdev->dev, + usbreq->buf, + usbreq->length, + DMA_FROM_DEVICE); req->dma_mapped = 1; } if (usbreq->length > 0) { - retval = prepare_dma(ep, req, gfp); + retval = prepare_dma(ep, req, GFP_ATOMIC); if (retval) goto probe_end; } @@ -1646,7 +1651,6 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq, pch_udc_wait_ep_stall(ep); pch_udc_ep_clear_nak(ep); pch_udc_enable_ep_interrupts(ep->dev, (1 << ep->num)); - pch_udc_set_dma(dev, DMA_DIR_TX); } } /* Now add this request to the ep's pending requests */ @@ -1926,6 +1930,7 @@ static void pch_udc_complete_receiver(struct pch_udc_ep *ep) PCH_UDC_BS_DMA_DONE) return; pch_udc_clear_dma(ep->dev, DMA_DIR_RX); + pch_udc_ep_set_ddptr(ep, 0); if ((req->td_data_last->status & PCH_UDC_RXTX_STS) != PCH_UDC_RTS_SUCC) { dev_err(&dev->pdev->dev, "Invalid RXTX status (0x%08x) " @@ -1963,7 +1968,7 @@ static void pch_udc_svc_data_in(struct pch_udc_dev *dev, int ep_num) u32 epsts; struct pch_udc_ep *ep; - ep = &dev->ep[2*ep_num]; + ep = &dev->ep[UDC_EPIN_IDX(ep_num)]; epsts = ep->epsts; ep->epsts = 0; @@ -2008,7 +2013,7 @@ static void pch_udc_svc_data_out(struct pch_udc_dev *dev, int ep_num) struct pch_udc_ep *ep; struct pch_udc_request *req = NULL; - ep = &dev->ep[2*ep_num + 1]; + ep = &dev->ep[UDC_EPOUT_IDX(ep_num)]; epsts = ep->epsts; ep->epsts = 0; @@ -2025,10 +2030,11 @@ static void pch_udc_svc_data_out(struct pch_udc_dev *dev, int ep_num) } if (epsts & UDC_EPSTS_HE) return; - if (epsts & UDC_EPSTS_RSS) + if (epsts & UDC_EPSTS_RSS) { pch_udc_ep_set_stall(ep); pch_udc_enable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num)); + } if (epsts & UDC_EPSTS_RCS) { if (!dev->prot_stall) { pch_udc_ep_clear_stall(ep); @@ -2060,8 +2066,10 @@ static void pch_udc_svc_control_in(struct pch_udc_dev *dev) { u32 epsts; struct pch_udc_ep *ep; + struct pch_udc_ep *ep_out; ep = &dev->ep[UDC_EP0IN_IDX]; + ep_out = &dev->ep[UDC_EP0OUT_IDX]; epsts = ep->epsts; ep->epsts = 0; @@ -2073,8 +2081,16 @@ static void pch_udc_svc_control_in(struct pch_udc_dev *dev) return; if (epsts & UDC_EPSTS_HE) return; - if ((epsts & UDC_EPSTS_TDC) && (!dev->stall)) + if ((epsts & UDC_EPSTS_TDC) && (!dev->stall)) { pch_udc_complete_transfer(ep); + pch_udc_clear_dma(dev, DMA_DIR_RX); + ep_out->td_data->status = (ep_out->td_data->status & + ~PCH_UDC_BUFF_STS) | + PCH_UDC_BS_HST_RDY; + pch_udc_ep_clear_nak(ep_out); + pch_udc_set_dma(dev, DMA_DIR_RX); + pch_udc_ep_set_rrdy(ep_out); + } /* On IN interrupt, provide data if we have any */ if ((epsts & UDC_EPSTS_IN) && !(epsts & UDC_EPSTS_TDC) && !(epsts & UDC_EPSTS_TXEMPTY)) @@ -2102,11 +2118,9 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev) dev->stall = 0; dev->ep[UDC_EP0IN_IDX].halted = 0; dev->ep[UDC_EP0OUT_IDX].halted = 0; - /* In data not ready */ - pch_udc_ep_set_nak(&(dev->ep[UDC_EP0IN_IDX])); dev->setup_data = ep->td_stp->request; pch_udc_init_setup_buff(ep->td_stp); - pch_udc_clear_dma(dev, DMA_DIR_TX); + pch_udc_clear_dma(dev, DMA_DIR_RX); pch_udc_ep_fifo_flush(&(dev->ep[UDC_EP0IN_IDX]), dev->ep[UDC_EP0IN_IDX].in); if ((dev->setup_data.bRequestType & USB_DIR_IN)) @@ -2122,14 +2136,23 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev) setup_supported = dev->driver->setup(&dev->gadget, &dev->setup_data); spin_lock(&dev->lock); + + if (dev->setup_data.bRequestType & USB_DIR_IN) { + ep->td_data->status = (ep->td_data->status & + ~PCH_UDC_BUFF_STS) | + PCH_UDC_BS_HST_RDY; + pch_udc_ep_set_ddptr(ep, ep->td_data_phys); + } /* ep0 in returns data on IN phase */ if (setup_supported >= 0 && setup_supported < UDC_EP0IN_MAX_PKT_SIZE) { pch_udc_ep_clear_nak(&(dev->ep[UDC_EP0IN_IDX])); /* Gadget would have queued a request when * we called the setup */ - pch_udc_set_dma(dev, DMA_DIR_RX); - pch_udc_ep_clear_nak(ep); + if (!(dev->setup_data.bRequestType & USB_DIR_IN)) { + pch_udc_set_dma(dev, DMA_DIR_RX); + pch_udc_ep_clear_nak(ep); + } } else if (setup_supported < 0) { /* if unsupported request, then stall */ pch_udc_ep_set_stall(&(dev->ep[UDC_EP0IN_IDX])); @@ -2142,22 +2165,13 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev) } } else if ((((stat & UDC_EPSTS_OUT_MASK) >> UDC_EPSTS_OUT_SHIFT) == UDC_EPSTS_OUT_DATA) && !dev->stall) { - if (list_empty(&ep->queue)) { - dev_err(&dev->pdev->dev, "%s: No request\n", __func__); - ep->td_data->status = (ep->td_data->status & - ~PCH_UDC_BUFF_STS) | - PCH_UDC_BS_HST_RDY; - pch_udc_set_dma(dev, DMA_DIR_RX); - } else { - /* control write */ - /* next function will pickuo an clear the status */ + pch_udc_clear_dma(dev, DMA_DIR_RX); + pch_udc_ep_set_ddptr(ep, 0); + if (!list_empty(&ep->queue)) { ep->epsts = stat; - - pch_udc_svc_data_out(dev, 0); - /* re-program desc. pointer for possible ZLPs */ - pch_udc_ep_set_ddptr(ep, ep->td_data_phys); - pch_udc_set_dma(dev, DMA_DIR_RX); + pch_udc_svc_data_out(dev, PCH_UDC_EP0); } + pch_udc_set_dma(dev, DMA_DIR_RX); } pch_udc_ep_set_rrdy(ep); } @@ -2174,7 +2188,7 @@ static void pch_udc_postsvc_epinters(struct pch_udc_dev *dev, int ep_num) struct pch_udc_ep *ep; struct pch_udc_request *req; - ep = &dev->ep[2*ep_num]; + ep = &dev->ep[UDC_EPIN_IDX(ep_num)]; if (!list_empty(&ep->queue)) { req = list_entry(ep->queue.next, struct pch_udc_request, queue); pch_udc_enable_ep_interrupts(ep->dev, @@ -2196,13 +2210,13 @@ static void pch_udc_read_all_epstatus(struct pch_udc_dev *dev, u32 ep_intr) for (i = 0; i < PCH_UDC_USED_EP_NUM; i++) { /* IN */ if (ep_intr & (0x1 << i)) { - ep = &dev->ep[2*i]; + ep = &dev->ep[UDC_EPIN_IDX(i)]; ep->epsts = pch_udc_read_ep_status(ep); pch_udc_clear_ep_status(ep, ep->epsts); } /* OUT */ if (ep_intr & (0x10000 << i)) { - ep = &dev->ep[2*i+1]; + ep = &dev->ep[UDC_EPOUT_IDX(i)]; ep->epsts = pch_udc_read_ep_status(ep); pch_udc_clear_ep_status(ep, ep->epsts); } @@ -2563,9 +2577,6 @@ static void pch_udc_pcd_reinit(struct pch_udc_dev *dev) dev->ep[UDC_EP0IN_IDX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE; dev->ep[UDC_EP0OUT_IDX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE; - dev->dma_addr = pci_map_single(dev->pdev, dev->ep0out_buf, 256, - PCI_DMA_FROMDEVICE); - /* remove ep0 in and out from the list. They have own pointer */ list_del_init(&dev->ep[UDC_EP0IN_IDX].ep.ep_list); list_del_init(&dev->ep[UDC_EP0OUT_IDX].ep.ep_list); @@ -2637,6 +2648,13 @@ static int init_dma_pools(struct pch_udc_dev *dev) dev->ep[UDC_EP0IN_IDX].td_stp_phys = 0; dev->ep[UDC_EP0IN_IDX].td_data = NULL; dev->ep[UDC_EP0IN_IDX].td_data_phys = 0; + + dev->ep0out_buf = kzalloc(UDC_EP0OUT_BUFF_SIZE * 4, GFP_KERNEL); + if (!dev->ep0out_buf) + return -ENOMEM; + dev->dma_addr = dma_map_single(&dev->pdev->dev, dev->ep0out_buf, + UDC_EP0OUT_BUFF_SIZE * 4, + DMA_FROM_DEVICE); return 0; } @@ -2700,7 +2718,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK); - /* Assues that there are no pending requets with this driver */ + /* Assures that there are no pending requests with this driver */ + driver->disconnect(&dev->gadget); driver->unbind(&dev->gadget); dev->gadget.dev.driver = NULL; dev->driver = NULL; @@ -2750,6 +2769,11 @@ static void pch_udc_remove(struct pci_dev *pdev) pci_pool_destroy(dev->stp_requests); } + if (dev->dma_addr) + dma_unmap_single(&dev->pdev->dev, dev->dma_addr, + UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE); + kfree(dev->ep0out_buf); + pch_udc_exit(dev); if (dev->irq_registered) @@ -2792,11 +2816,7 @@ static int pch_udc_resume(struct pci_dev *pdev) int ret; pci_set_power_state(pdev, PCI_D0); - ret = pci_restore_state(pdev); - if (ret) { - dev_err(&pdev->dev, "%s: pci_restore_state failed\n", __func__); - return ret; - } + pci_restore_state(pdev); ret = pci_enable_device(pdev); if (ret) { dev_err(&pdev->dev, "%s: pci_enable_device failed\n", __func__); @@ -2914,6 +2934,11 @@ static DEFINE_PCI_DEVICE_TABLE(pch_udc_pcidev_id) = { .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe, .class_mask = 0xffffffff, }, + { + PCI_DEVICE(PCI_VENDOR_ID_ROHM, PCI_DEVICE_ID_ML7213_IOH_UDC), + .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe, + .class_mask = 0xffffffff, + }, { 0 }, }; diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index 2fc8636316c5..12ff6cffedc9 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -131,31 +131,31 @@ static struct printer_dev usb_printer_gadget; * parameters are in UTF-8 (superset of ASCII's 7 bit characters). */ -static ushort __initdata idVendor; +static ushort idVendor; module_param(idVendor, ushort, S_IRUGO); MODULE_PARM_DESC(idVendor, "USB Vendor ID"); -static ushort __initdata idProduct; +static ushort idProduct; module_param(idProduct, ushort, S_IRUGO); MODULE_PARM_DESC(idProduct, "USB Product ID"); -static ushort __initdata bcdDevice; +static ushort bcdDevice; module_param(bcdDevice, ushort, S_IRUGO); MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)"); -static char *__initdata iManufacturer; +static char *iManufacturer; module_param(iManufacturer, charp, S_IRUGO); MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string"); -static char *__initdata iProduct; +static char *iProduct; module_param(iProduct, charp, S_IRUGO); MODULE_PARM_DESC(iProduct, "USB Product string"); -static char *__initdata iSerialNum; +static char *iSerialNum; module_param(iSerialNum, charp, S_IRUGO); MODULE_PARM_DESC(iSerialNum, "1"); -static char *__initdata iPNPstring; +static char *iPNPstring; module_param(iPNPstring, charp, S_IRUGO); MODULE_PARM_DESC(iPNPstring, "MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;"); @@ -1596,13 +1596,12 @@ cleanup(void) int status; mutex_lock(&usb_printer_gadget.lock_printer_io); - class_destroy(usb_gadget_class); - unregister_chrdev_region(g_printer_devno, 2); - status = usb_gadget_unregister_driver(&printer_driver); if (status) ERROR(dev, "usb_gadget_unregister_driver %x\n", status); + unregister_chrdev_region(g_printer_devno, 2); + class_destroy(usb_gadget_class); mutex_unlock(&usb_printer_gadget.lock_printer_io); } module_exit(cleanup); diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 20d43da319ae..015118535f77 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -258,7 +258,7 @@ static int pipe_buffer_setting(struct r8a66597 *r8a66597, break; case R8A66597_BULK: /* isochronous pipes may be used as bulk pipes */ - if (info->pipe > R8A66597_BASE_PIPENUM_BULK) + if (info->pipe >= R8A66597_BASE_PIPENUM_BULK) bufnum = info->pipe - R8A66597_BASE_PIPENUM_BULK; else bufnum = info->pipe - R8A66597_BASE_PIPENUM_ISOC; diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 24046c0f5878..0e6afa260ed8 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -151,6 +151,8 @@ config USB_EHCI_MSM Qualcomm chipsets. Root Hub has inbuilt TT. This driver depends on OTG driver for PHY initialization, clock management, powering up VBUS, and power management. + This driver is not supported on boards like trout which + has an external PHY. config USB_EHCI_HCD_PPC_OF bool "EHCI support for PPC USB controller on OF platform bus" diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c index 2baf8a849086..a869e3c103d3 100644 --- a/drivers/usb/host/ehci-au1xxx.c +++ b/drivers/usb/host/ehci-au1xxx.c @@ -227,8 +227,8 @@ static int ehci_hcd_au1xxx_drv_suspend(struct device *dev) * mark HW unaccessible. The PM and USB cores make sure that * the root hub is either suspended or stopped. */ - spin_lock_irqsave(&ehci->lock, flags); ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev)); + spin_lock_irqsave(&ehci->lock, flags); ehci_writel(ehci, 0, &ehci->regs->intr_enable); (void)ehci_readl(ehci, &ehci->regs->intr_enable); diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 86e42892016d..5c761df7fa83 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -52,7 +52,6 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, struct resource *res; int irq; int retval; - unsigned int temp; pr_debug("initializing FSL-SOC USB Controller\n"); @@ -126,18 +125,6 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, goto err3; } - /* - * Check if it is MPC5121 SoC, otherwise set pdata->have_sysif_regs - * flag for 83xx or 8536 system interface registers. - */ - if (pdata->big_endian_mmio) - temp = in_be32(hcd->regs + FSL_SOC_USB_ID); - else - temp = in_le32(hcd->regs + FSL_SOC_USB_ID); - - if ((temp & ID_MSK) != (~((temp & NID_MSK) >> 8) & ID_MSK)) - pdata->have_sysif_regs = 1; - /* Enable USB controller, 83xx or 8536 */ if (pdata->have_sysif_regs) setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4); diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h index 2c8353795226..3fabed33d940 100644 --- a/drivers/usb/host/ehci-fsl.h +++ b/drivers/usb/host/ehci-fsl.h @@ -19,9 +19,6 @@ #define _EHCI_FSL_H /* offsets for the non-ehci registers in the FSL SOC USB controller */ -#define FSL_SOC_USB_ID 0x0 -#define ID_MSK 0x3f -#define NID_MSK 0x3f00 #define FSL_SOC_USB_ULPIVP 0x170 #define FSL_SOC_USB_PORTSC1 0x184 #define PORT_PTS_MSK (3<<30) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 6fee3cd58efe..74dcf49bd015 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -572,6 +572,8 @@ static int ehci_init(struct usb_hcd *hcd) ehci->iaa_watchdog.function = ehci_iaa_watchdog; ehci->iaa_watchdog.data = (unsigned long) ehci; + hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params); + /* * hw default: 1K periodic list heads, one per frame. * periodic_size can shrink by USBCMD update if hcc_params allows. @@ -579,11 +581,20 @@ static int ehci_init(struct usb_hcd *hcd) ehci->periodic_size = DEFAULT_I_TDPS; INIT_LIST_HEAD(&ehci->cached_itd_list); INIT_LIST_HEAD(&ehci->cached_sitd_list); + + if (HCC_PGM_FRAMELISTLEN(hcc_params)) { + /* periodic schedule size can be smaller than default */ + switch (EHCI_TUNE_FLS) { + case 0: ehci->periodic_size = 1024; break; + case 1: ehci->periodic_size = 512; break; + case 2: ehci->periodic_size = 256; break; + default: BUG(); + } + } if ((retval = ehci_mem_init(ehci, GFP_KERNEL)) < 0) return retval; /* controllers may cache some of the periodic schedule ... */ - hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params); if (HCC_ISOC_CACHE(hcc_params)) // full frame cache ehci->i_thresh = 2 + 8; else // N microframes cached @@ -637,12 +648,6 @@ static int ehci_init(struct usb_hcd *hcd) /* periodic schedule size can be smaller than default */ temp &= ~(3 << 2); temp |= (EHCI_TUNE_FLS << 2); - switch (EHCI_TUNE_FLS) { - case 0: ehci->periodic_size = 1024; break; - case 1: ehci->periodic_size = 512; break; - case 2: ehci->periodic_size = 256; break; - default: BUG(); - } } if (HCC_LPM(hcc_params)) { /* support link power management EHCI 1.1 addendum */ diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 796ea0c8900f..8a515f0d5988 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -111,6 +111,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, { int port; u32 temp; + unsigned long flags; /* If remote wakeup is enabled for the root hub but disabled * for the controller, we must adjust all the port wakeup flags @@ -120,6 +121,8 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || do_wakeup) return; + spin_lock_irqsave(&ehci->lock, flags); + /* clear phy low-power mode before changing wakeup flags */ if (ehci->has_hostpc) { port = HCS_N_PORTS(ehci->hcs_params); @@ -131,7 +134,9 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, temp = ehci_readl(ehci, hostpc_reg); ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg); } + spin_unlock_irqrestore(&ehci->lock, flags); msleep(5); + spin_lock_irqsave(&ehci->lock, flags); } port = HCS_N_PORTS(ehci->hcs_params); @@ -170,6 +175,8 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, /* Does the root hub have a port wakeup pending? */ if (!suspending && (ehci_readl(ehci, &ehci->regs->status) & STS_PCD)) usb_hcd_resume_root_hub(ehci_to_hcd(ehci)); + + spin_unlock_irqrestore(&ehci->lock, flags); } static int ehci_bus_suspend (struct usb_hcd *hcd) diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index fa59b26fc5bc..c8e360d7d975 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c @@ -21,10 +21,13 @@ #include <linux/clk.h> #include <linux/delay.h> #include <linux/usb/otg.h> +#include <linux/usb/ulpi.h> #include <linux/slab.h> #include <mach/mxc_ehci.h> +#include <asm/mach-types.h> + #define ULPI_VIEWPORT_OFFSET 0x170 struct ehci_mxc_priv { @@ -114,6 +117,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) struct usb_hcd *hcd; struct resource *res; int irq, ret; + unsigned int flags; struct ehci_mxc_priv *priv; struct device *dev = &pdev->dev; struct ehci_hcd *ehci; @@ -177,8 +181,8 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) clk_enable(priv->ahbclk); } - /* "dr" device has its own clock */ - if (pdev->id == 0) { + /* "dr" device has its own clock on i.MX51 */ + if (cpu_is_mx51() && (pdev->id == 0)) { priv->phy1clk = clk_get(dev, "usb_phy1"); if (IS_ERR(priv->phy1clk)) { ret = PTR_ERR(priv->phy1clk); @@ -240,6 +244,23 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) if (ret) goto err_add; + if (pdata->otg) { + /* + * efikamx and efikasb have some hardware bug which is + * preventing usb to work unless CHRGVBUS is set. + * It's in violation of USB specs + */ + if (machine_is_mx51_efikamx() || machine_is_mx51_efikasb()) { + flags = otg_io_read(pdata->otg, ULPI_OTG_CTRL); + flags |= ULPI_OTG_CTRL_CHRGVBUS; + ret = otg_io_write(pdata->otg, flags, ULPI_OTG_CTRL); + if (ret) { + dev_err(dev, "unable to set CHRVBUS\n"); + goto err_add; + } + } + } + return 0; err_add: diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 680f2ef4e59f..f784ceb862a3 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -796,7 +796,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) hcd = usb_create_hcd(&ehci_omap_hc_driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { - dev_dbg(&pdev->dev, "failed to create hcd with err %d\n", ret); + dev_err(&pdev->dev, "failed to create hcd with err %d\n", ret); ret = -ENOMEM; goto err_create_hcd; } @@ -864,7 +864,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) ret = omap_start_ehc(omap, hcd); if (ret) { - dev_dbg(&pdev->dev, "failed to start ehci\n"); + dev_err(&pdev->dev, "failed to start ehci with err %d\n", ret); goto err_start; } @@ -879,7 +879,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); if (ret) { - dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret); + dev_err(&pdev->dev, "failed to add hcd with err %d\n", ret); goto err_add_hcd; } diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 76179c39c0e3..07bb982e59f6 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -44,28 +44,35 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) return 0; } -static int ehci_quirk_amd_SB800(struct ehci_hcd *ehci) +static int ehci_quirk_amd_hudson(struct ehci_hcd *ehci) { struct pci_dev *amd_smbus_dev; u8 rev = 0; amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL); - if (!amd_smbus_dev) - return 0; - - pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev); - if (rev < 0x40) { - pci_dev_put(amd_smbus_dev); - amd_smbus_dev = NULL; - return 0; + if (amd_smbus_dev) { + pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev); + if (rev < 0x40) { + pci_dev_put(amd_smbus_dev); + amd_smbus_dev = NULL; + return 0; + } + } else { + amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x780b, NULL); + if (!amd_smbus_dev) + return 0; + pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev); + if (rev < 0x11 || rev > 0x18) { + pci_dev_put(amd_smbus_dev); + amd_smbus_dev = NULL; + return 0; + } } if (!amd_nb_dev) amd_nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1510, NULL); - if (!amd_nb_dev) - ehci_err(ehci, "QUIRK: unable to get AMD NB device\n"); - ehci_info(ehci, "QUIRK: Enable AMD SB800 L1 fix\n"); + ehci_info(ehci, "QUIRK: Enable exception for AMD Hudson ASPM\n"); pci_dev_put(amd_smbus_dev); amd_smbus_dev = NULL; @@ -131,7 +138,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd) /* cache this readonly data; minimize chip reads */ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - if (ehci_quirk_amd_SB800(ehci)) + if (ehci_quirk_amd_hudson(ehci)) ehci->amd_l1_fix = 1; retval = ehci_halt(ehci); @@ -360,8 +367,8 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) * mark HW unaccessible. The PM and USB cores make sure that * the root hub is either suspended or stopped. */ - spin_lock_irqsave (&ehci->lock, flags); ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup); + spin_lock_irqsave (&ehci->lock, flags); ehci_writel(ehci, 0, &ehci->regs->intr_enable); (void)ehci_readl(ehci, &ehci->regs->intr_enable); diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 574b99ea0700..79a66d622f9c 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -262,19 +262,24 @@ static void fsl_usb2_mpc5121_exit(struct platform_device *pdev) } } -struct fsl_usb2_platform_data fsl_usb2_mpc5121_pd = { +static struct fsl_usb2_platform_data fsl_usb2_mpc5121_pd = { .big_endian_desc = 1, .big_endian_mmio = 1, .es = 1, + .have_sysif_regs = 0, .le_setup_buf = 1, .init = fsl_usb2_mpc5121_init, .exit = fsl_usb2_mpc5121_exit, }; #endif /* CONFIG_PPC_MPC512x */ +static struct fsl_usb2_platform_data fsl_usb2_mpc8xxx_pd = { + .have_sysif_regs = 1, +}; + static const struct of_device_id fsl_usb2_mph_dr_of_match[] = { - { .compatible = "fsl-usb2-mph", }, - { .compatible = "fsl-usb2-dr", }, + { .compatible = "fsl-usb2-mph", .data = &fsl_usb2_mpc8xxx_pd, }, + { .compatible = "fsl-usb2-dr", .data = &fsl_usb2_mpc8xxx_pd, }, #ifdef CONFIG_PPC_MPC512x { .compatible = "fsl,mpc5121-usb2-dr", .data = &fsl_usb2_mpc5121_pd, }, #endif diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 990f06b89eaa..2e9602a10e9b 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -861,6 +861,7 @@ static int sl811h_urb_enqueue( DBG("dev %d ep%d maxpacket %d\n", udev->devnum, epnum, ep->maxpacket); retval = -EINVAL; + kfree(ep); goto fail; } diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index df558f6f84e3..3e8211c1ce5a 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -308,11 +308,8 @@ static int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring, /* Ring the host controller doorbell after placing a command on the ring */ void xhci_ring_cmd_db(struct xhci_hcd *xhci) { - u32 temp; - xhci_dbg(xhci, "// Ding dong!\n"); - temp = xhci_readl(xhci, &xhci->dba->doorbell[0]) & DB_MASK; - xhci_writel(xhci, temp | DB_TARGET_HOST, &xhci->dba->doorbell[0]); + xhci_writel(xhci, DB_VALUE_HOST, &xhci->dba->doorbell[0]); /* Flush PCI posted writes */ xhci_readl(xhci, &xhci->dba->doorbell[0]); } @@ -322,26 +319,24 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int ep_index, unsigned int stream_id) { - struct xhci_virt_ep *ep; - unsigned int ep_state; - u32 field; __u32 __iomem *db_addr = &xhci->dba->doorbell[slot_id]; + struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index]; + unsigned int ep_state = ep->ep_state; - ep = &xhci->devs[slot_id]->eps[ep_index]; - ep_state = ep->ep_state; /* Don't ring the doorbell for this endpoint if there are pending - * cancellations because the we don't want to interrupt processing. + * cancellations because we don't want to interrupt processing. * We don't want to restart any stream rings if there's a set dequeue * pointer command pending because the device can choose to start any * stream once the endpoint is on the HW schedule. * FIXME - check all the stream rings for pending cancellations. */ - if (!(ep_state & EP_HALT_PENDING) && !(ep_state & SET_DEQ_PENDING) - && !(ep_state & EP_HALTED)) { - field = xhci_readl(xhci, db_addr) & DB_MASK; - field |= EPI_TO_DB(ep_index) | STREAM_ID_TO_DB(stream_id); - xhci_writel(xhci, field, db_addr); - } + if ((ep_state & EP_HALT_PENDING) || (ep_state & SET_DEQ_PENDING) || + (ep_state & EP_HALTED)) + return; + xhci_writel(xhci, DB_VALUE(ep_index, stream_id), db_addr); + /* The CPU has better things to do at this point than wait for a + * write-posting flush. It'll get there soon enough. + */ } /* Ring the doorbell for any rings with pending URBs */ @@ -1188,7 +1183,7 @@ static void handle_port_status(struct xhci_hcd *xhci, addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS * (port_id - 1); temp = xhci_readl(xhci, addr); - if ((temp & PORT_CONNECT) && (hcd->state == HC_STATE_SUSPENDED)) { + if (hcd->state == HC_STATE_SUSPENDED) { xhci_dbg(xhci, "resume root hub\n"); usb_hcd_resume_root_hub(hcd); } @@ -1710,8 +1705,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, /* Others already handled above */ break; } - dev_dbg(&td->urb->dev->dev, - "ep %#x - asked for %d bytes, " + xhci_dbg(xhci, "ep %#x - asked for %d bytes, " "%d bytes untransferred\n", td->urb->ep->desc.bEndpointAddress, td->urb->transfer_buffer_length, @@ -2389,7 +2383,8 @@ static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb) } xhci_dbg(xhci, "\n"); if (!in_interrupt()) - dev_dbg(&urb->dev->dev, "ep %#x - urb len = %d, sglist used, num_trbs = %d\n", + xhci_dbg(xhci, "ep %#x - urb len = %d, sglist used, " + "num_trbs = %d\n", urb->ep->desc.bEndpointAddress, urb->transfer_buffer_length, num_trbs); @@ -2414,14 +2409,17 @@ static void check_trb_math(struct urb *urb, int num_trbs, int running_total) static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id, unsigned int ep_index, unsigned int stream_id, int start_cycle, - struct xhci_generic_trb *start_trb, struct xhci_td *td) + struct xhci_generic_trb *start_trb) { /* * Pass all the TRBs to the hardware at once and make sure this write * isn't reordered. */ wmb(); - start_trb->field[3] |= start_cycle; + if (start_cycle) + start_trb->field[3] |= start_cycle; + else + start_trb->field[3] &= ~0x1; xhci_ring_ep_doorbell(xhci, slot_id, ep_index, stream_id); } @@ -2449,7 +2447,7 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags, * to set the polling interval (once the API is added). */ if (xhci_interval != ep_interval) { - if (!printk_ratelimit()) + if (printk_ratelimit()) dev_dbg(&urb->dev->dev, "Driver uses different interval" " (%d microframe%s) than xHCI " "(%d microframe%s)\n", @@ -2551,9 +2549,11 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, u32 remainder = 0; /* Don't change the cycle bit of the first TRB until later */ - if (first_trb) + if (first_trb) { first_trb = false; - else + if (start_cycle == 0) + field |= 0x1; + } else field |= ep_ring->cycle_state; /* Chain all the TRBs together; clear the chain bit in the last @@ -2625,7 +2625,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, check_trb_math(urb, num_trbs, running_total); giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, - start_cycle, start_trb, td); + start_cycle, start_trb); return 0; } @@ -2671,7 +2671,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, /* FIXME: this doesn't deal with URB_ZERO_PACKET - need one more */ if (!in_interrupt()) - dev_dbg(&urb->dev->dev, "ep %#x - urb len = %#x (%d), addr = %#llx, num_trbs = %d\n", + xhci_dbg(xhci, "ep %#x - urb len = %#x (%d), " + "addr = %#llx, num_trbs = %d\n", urb->ep->desc.bEndpointAddress, urb->transfer_buffer_length, urb->transfer_buffer_length, @@ -2711,9 +2712,11 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, field = 0; /* Don't change the cycle bit of the first TRB until later */ - if (first_trb) + if (first_trb) { first_trb = false; - else + if (start_cycle == 0) + field |= 0x1; + } else field |= ep_ring->cycle_state; /* Chain all the TRBs together; clear the chain bit in the last @@ -2757,7 +2760,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, check_trb_math(urb, num_trbs, running_total); giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, - start_cycle, start_trb, td); + start_cycle, start_trb); return 0; } @@ -2818,13 +2821,17 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, /* Queue setup TRB - see section 6.4.1.2.1 */ /* FIXME better way to translate setup_packet into two u32 fields? */ setup = (struct usb_ctrlrequest *) urb->setup_packet; + field = 0; + field |= TRB_IDT | TRB_TYPE(TRB_SETUP); + if (start_cycle == 0) + field |= 0x1; queue_trb(xhci, ep_ring, false, true, /* FIXME endianness is probably going to bite my ass here. */ setup->bRequestType | setup->bRequest << 8 | setup->wValue << 16, setup->wIndex | setup->wLength << 16, TRB_LEN(8) | TRB_INTR_TARGET(0), /* Immediate data in pointer */ - TRB_IDT | TRB_TYPE(TRB_SETUP)); + field); /* If there's data, queue data TRBs */ field = 0; @@ -2859,7 +2866,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, field | TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state); giveback_first_trb(xhci, slot_id, ep_index, 0, - start_cycle, start_trb, td); + start_cycle, start_trb); return 0; } @@ -2900,6 +2907,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, int running_total, trb_buff_len, td_len, td_remain_len, ret; u64 start_addr, addr; int i, j; + bool more_trbs_coming; ep_ring = xhci->devs[slot_id]->eps[ep_index].ring; @@ -2910,7 +2918,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, } if (!in_interrupt()) - dev_dbg(&urb->dev->dev, "ep %#x - urb len = %#x (%d)," + xhci_dbg(xhci, "ep %#x - urb len = %#x (%d)," " addr = %#llx, num_tds = %d\n", urb->ep->desc.bEndpointAddress, urb->transfer_buffer_length, @@ -2950,7 +2958,10 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, field |= TRB_TYPE(TRB_ISOC); /* Assume URB_ISO_ASAP is set */ field |= TRB_SIA; - if (i > 0) + if (i == 0) { + if (start_cycle == 0) + field |= 0x1; + } else field |= ep_ring->cycle_state; first_trb = false; } else { @@ -2965,9 +2976,11 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, */ if (j < trbs_per_td - 1) { field |= TRB_CHAIN; + more_trbs_coming = true; } else { td->last_trb = ep_ring->enqueue; field |= TRB_IOC; + more_trbs_coming = false; } /* Calculate TRB length */ @@ -2980,7 +2993,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, length_field = TRB_LEN(trb_buff_len) | remainder | TRB_INTR_TARGET(0); - queue_trb(xhci, ep_ring, false, false, + queue_trb(xhci, ep_ring, false, more_trbs_coming, lower_32_bits(addr), upper_32_bits(addr), length_field, @@ -3003,10 +3016,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, } } - wmb(); - start_trb->field[3] |= start_cycle; - - xhci_ring_ep_doorbell(xhci, slot_id, ep_index, urb->stream_id); + giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, + start_cycle, start_trb); return 0; } @@ -3064,7 +3075,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, * to set the polling interval (once the API is added). */ if (xhci_interval != ep_interval) { - if (!printk_ratelimit()) + if (printk_ratelimit()) dev_dbg(&urb->dev->dev, "Driver uses different interval" " (%d microframe%s) than xHCI " "(%d microframe%s)\n", diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 45e4a3108cc3..34cf4e165877 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -226,7 +226,8 @@ static int xhci_setup_msi(struct xhci_hcd *xhci) static int xhci_setup_msix(struct xhci_hcd *xhci) { int i, ret = 0; - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + struct usb_hcd *hcd = xhci_to_hcd(xhci); + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); /* * calculate number of msi-x vectors supported. @@ -265,6 +266,7 @@ static int xhci_setup_msix(struct xhci_hcd *xhci) goto disable_msix; } + hcd->msix_enabled = 1; return ret; disable_msix: @@ -280,7 +282,8 @@ free_entries: /* Free any IRQs and disable MSI-X */ static void xhci_cleanup_msix(struct xhci_hcd *xhci) { - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + struct usb_hcd *hcd = xhci_to_hcd(xhci); + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); xhci_free_irq(xhci); @@ -292,6 +295,7 @@ static void xhci_cleanup_msix(struct xhci_hcd *xhci) pci_disable_msi(pdev); } + hcd->msix_enabled = 0; return; } @@ -508,9 +512,10 @@ void xhci_stop(struct usb_hcd *hcd) spin_lock_irq(&xhci->lock); xhci_halt(xhci); xhci_reset(xhci); - xhci_cleanup_msix(xhci); spin_unlock_irq(&xhci->lock); + xhci_cleanup_msix(xhci); + #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING /* Tell the event ring poll function not to reschedule */ xhci->zombie = 1; @@ -544,9 +549,10 @@ void xhci_shutdown(struct usb_hcd *hcd) spin_lock_irq(&xhci->lock); xhci_halt(xhci); - xhci_cleanup_msix(xhci); spin_unlock_irq(&xhci->lock); + xhci_cleanup_msix(xhci); + xhci_dbg(xhci, "xhci_shutdown completed - status = %x\n", xhci_readl(xhci, &xhci->op_regs->status)); } @@ -647,6 +653,7 @@ int xhci_suspend(struct xhci_hcd *xhci) int rc = 0; struct usb_hcd *hcd = xhci_to_hcd(xhci); u32 command; + int i; spin_lock_irq(&xhci->lock); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); @@ -677,10 +684,15 @@ int xhci_suspend(struct xhci_hcd *xhci) spin_unlock_irq(&xhci->lock); return -ETIMEDOUT; } - /* step 5: remove core well power */ - xhci_cleanup_msix(xhci); spin_unlock_irq(&xhci->lock); + /* step 5: remove core well power */ + /* synchronize irq when using MSI-X */ + if (xhci->msix_entries) { + for (i = 0; i < xhci->msix_count; i++) + synchronize_irq(xhci->msix_entries[i].vector); + } + return rc; } @@ -694,7 +706,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) { u32 command, temp = 0; struct usb_hcd *hcd = xhci_to_hcd(xhci); - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); int old_state, retval; old_state = hcd->state; @@ -729,9 +740,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) xhci_dbg(xhci, "Stop HCD\n"); xhci_halt(xhci); xhci_reset(xhci); - if (hibernated) - xhci_cleanup_msix(xhci); spin_unlock_irq(&xhci->lock); + xhci_cleanup_msix(xhci); #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING /* Tell the event ring poll function not to reschedule */ @@ -765,30 +775,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) return retval; } - spin_unlock_irq(&xhci->lock); - /* Re-setup MSI-X */ - if (hcd->irq) - free_irq(hcd->irq, hcd); - hcd->irq = -1; - - retval = xhci_setup_msix(xhci); - if (retval) - /* fall back to msi*/ - retval = xhci_setup_msi(xhci); - - if (retval) { - /* fall back to legacy interrupt*/ - retval = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED, - hcd->irq_descr, hcd); - if (retval) { - xhci_err(xhci, "request interrupt %d failed\n", - pdev->irq); - return retval; - } - hcd->irq = pdev->irq; - } - - spin_lock_irq(&xhci->lock); /* step 4: set Run/Stop bit */ command = xhci_readl(xhci, &xhci->op_regs->command); command |= CMD_RUN; @@ -2445,8 +2431,12 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) xhci_err(xhci, "Error while assigning device slot ID\n"); return 0; } - /* xhci_alloc_virt_device() does not touch rings; no need to lock */ - if (!xhci_alloc_virt_device(xhci, xhci->slot_id, udev, GFP_KERNEL)) { + /* xhci_alloc_virt_device() does not touch rings; no need to lock. + * Use GFP_NOIO, since this function can be called from + * xhci_discover_or_reset_device(), which may be called as part of + * mass storage driver error handling. + */ + if (!xhci_alloc_virt_device(xhci, xhci->slot_id, udev, GFP_NOIO)) { /* Disable slot, if we can do it without mem alloc */ xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n"); spin_lock_irqsave(&xhci->lock, flags); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 170c367112d2..7f236fd22015 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -436,22 +436,18 @@ struct xhci_run_regs { /** * struct doorbell_array * + * Bits 0 - 7: Endpoint target + * Bits 8 - 15: RsvdZ + * Bits 16 - 31: Stream ID + * * Section 5.6 */ struct xhci_doorbell_array { u32 doorbell[256]; }; -#define DB_TARGET_MASK 0xFFFFFF00 -#define DB_STREAM_ID_MASK 0x0000FFFF -#define DB_TARGET_HOST 0x0 -#define DB_STREAM_ID_HOST 0x0 -#define DB_MASK (0xff << 8) - -/* Endpoint Target - bits 0:7 */ -#define EPI_TO_DB(p) (((p) + 1) & 0xff) -#define STREAM_ID_TO_DB(p) (((p) & 0xffff) << 16) - +#define DB_VALUE(ep, stream) ((((ep) + 1) & 0xff) | ((stream) << 16)) +#define DB_VALUE_HOST 0x00000000 /** * struct xhci_protocol_caps diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c index 1732d9bc097e..1616ad1793a4 100644 --- a/drivers/usb/misc/usbled.c +++ b/drivers/usb/misc/usbled.c @@ -45,7 +45,7 @@ struct usb_led { static void change_color(struct usb_led *led) { - int retval; + int retval = 0; unsigned char *buffer; buffer = kmalloc(8, GFP_KERNEL); diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index 4ff21587ab03..f7a205738032 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -776,7 +776,6 @@ static const struct usb_device_id uss720_table[] = { { USB_DEVICE(0x0557, 0x2001) }, { USB_DEVICE(0x0729, 0x1284) }, { USB_DEVICE(0x1293, 0x0002) }, - { USB_DEVICE(0x1293, 0x0002) }, { USB_DEVICE(0x050d, 0x0002) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index eeba228eb2af..9d49d1cd7ce2 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -404,6 +404,7 @@ static int bfin_musb_init(struct musb *musb) musb->xceiv->set_power = bfin_musb_set_power; musb->isr = blackfin_interrupt; + musb->double_buffer_not_ok = true; return 0; } diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 07cf394e491b..54a8bd1047d6 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -128,12 +128,7 @@ MODULE_ALIAS("platform:" MUSB_DRIVER_NAME); static inline struct musb *dev_to_musb(struct device *dev) { -#ifdef CONFIG_USB_MUSB_HDRC_HCD - /* usbcore insists dev->driver_data is a "struct hcd *" */ - return hcd_to_musb(dev_get_drvdata(dev)); -#else return dev_get_drvdata(dev); -#endif } /*-------------------------------------------------------------------------*/ @@ -1876,10 +1871,9 @@ allocate_instance(struct device *dev, musb = kzalloc(sizeof *musb, GFP_KERNEL); if (!musb) return NULL; - dev_set_drvdata(dev, musb); #endif - + dev_set_drvdata(dev, musb); musb->mregs = mbase; musb->ctrl_base = mbase; musb->nIrq = -ENODEV; @@ -2191,7 +2185,7 @@ static int __init musb_probe(struct platform_device *pdev) void __iomem *base; iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iomem || irq == 0) + if (!iomem || irq <= 0) return -ENODEV; base = ioremap(iomem->start, resource_size(iomem)); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index d0c236f8e191..d74a8113ae74 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -488,6 +488,18 @@ struct musb { unsigned set_address:1; unsigned test_mode:1; unsigned softconnect:1; + /* + * FIXME: Remove this flag. + * + * This is only added to allow Blackfin to work + * with current driver. For some unknown reason + * Blackfin doesn't work with double buffering + * and that's enabled by default. + * + * We added this flag to forcefully disable double + * buffering until we get it working. + */ + unsigned double_buffer_not_ok:1 __deprecated; u8 address; u8 test_mode_nr; diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h index 916065ba9e70..3a97c4e2d4f5 100644 --- a/drivers/usb/musb/musb_dma.h +++ b/drivers/usb/musb/musb_dma.h @@ -169,6 +169,9 @@ struct dma_controller { dma_addr_t dma_addr, u32 length); int (*channel_abort)(struct dma_channel *); + int (*is_compatible)(struct dma_channel *channel, + u16 maxpacket, + void *buf, u32 length); }; /* called after channel_program(), may indicate a fault */ diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index ed58c6c8f15c..2fe304611dcf 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -92,11 +92,33 @@ /* ----------------------------------------------------------------------- */ +#define is_buffer_mapped(req) (is_dma_capable() && \ + (req->map_state != UN_MAPPED)) + /* Maps the buffer to dma */ static inline void map_dma_buffer(struct musb_request *request, - struct musb *musb) + struct musb *musb, struct musb_ep *musb_ep) { + int compatible = true; + struct dma_controller *dma = musb->dma_controller; + + request->map_state = UN_MAPPED; + + if (!is_dma_capable() || !musb_ep->dma) + return; + + /* Check if DMA engine can handle this request. + * DMA code must reject the USB request explicitly. + * Default behaviour is to map the request. + */ + if (dma->is_compatible) + compatible = dma->is_compatible(musb_ep->dma, + musb_ep->packet_sz, request->request.buf, + request->request.length); + if (!compatible) + return; + if (request->request.dma == DMA_ADDR_INVALID) { request->request.dma = dma_map_single( musb->controller, @@ -105,7 +127,7 @@ static inline void map_dma_buffer(struct musb_request *request, request->tx ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - request->mapped = 1; + request->map_state = MUSB_MAPPED; } else { dma_sync_single_for_device(musb->controller, request->request.dma, @@ -113,7 +135,7 @@ static inline void map_dma_buffer(struct musb_request *request, request->tx ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - request->mapped = 0; + request->map_state = PRE_MAPPED; } } @@ -121,11 +143,14 @@ static inline void map_dma_buffer(struct musb_request *request, static inline void unmap_dma_buffer(struct musb_request *request, struct musb *musb) { + if (!is_buffer_mapped(request)) + return; + if (request->request.dma == DMA_ADDR_INVALID) { DBG(20, "not unmapping a never mapped buffer\n"); return; } - if (request->mapped) { + if (request->map_state == MUSB_MAPPED) { dma_unmap_single(musb->controller, request->request.dma, request->request.length, @@ -133,16 +158,15 @@ static inline void unmap_dma_buffer(struct musb_request *request, ? DMA_TO_DEVICE : DMA_FROM_DEVICE); request->request.dma = DMA_ADDR_INVALID; - request->mapped = 0; - } else { + } else { /* PRE_MAPPED */ dma_sync_single_for_cpu(musb->controller, request->request.dma, request->request.length, request->tx ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - } + request->map_state = UN_MAPPED; } /* @@ -172,8 +196,7 @@ __acquires(ep->musb->lock) ep->busy = 1; spin_unlock(&musb->lock); - if (is_dma_capable() && ep->dma) - unmap_dma_buffer(req, musb); + unmap_dma_buffer(req, musb); if (request->status == 0) DBG(5, "%s done request %p, %d/%d\n", ep->end_point.name, request, @@ -335,7 +358,7 @@ static void txstate(struct musb *musb, struct musb_request *req) csr); #ifndef CONFIG_MUSB_PIO_ONLY - if (is_dma_capable() && musb_ep->dma) { + if (is_buffer_mapped(req)) { struct dma_controller *c = musb->dma_controller; size_t request_size; @@ -436,8 +459,7 @@ static void txstate(struct musb *musb, struct musb_request *req) * Unmap the dma buffer back to cpu if dma channel * programming fails */ - if (is_dma_capable() && musb_ep->dma) - unmap_dma_buffer(req, musb); + unmap_dma_buffer(req, musb); musb_write_fifo(musb_ep->hw_ep, fifo_count, (u8 *) (request->buf + request->actual)); @@ -627,7 +649,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) return; } - if (is_cppi_enabled() && musb_ep->dma) { + if (is_cppi_enabled() && is_buffer_mapped(req)) { struct dma_controller *c = musb->dma_controller; struct dma_channel *channel = musb_ep->dma; @@ -658,7 +680,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) len = musb_readw(epio, MUSB_RXCOUNT); if (request->actual < request->length) { #ifdef CONFIG_USB_INVENTRA_DMA - if (is_dma_capable() && musb_ep->dma) { + if (is_buffer_mapped(req)) { struct dma_controller *c; struct dma_channel *channel; int use_dma = 0; @@ -742,7 +764,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) fifo_count = min_t(unsigned, len, fifo_count); #ifdef CONFIG_USB_TUSB_OMAP_DMA - if (tusb_dma_omap() && musb_ep->dma) { + if (tusb_dma_omap() && is_buffer_mapped(req)) { struct dma_controller *c = musb->dma_controller; struct dma_channel *channel = musb_ep->dma; u32 dma_addr = request->dma + request->actual; @@ -762,7 +784,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) * programming fails. This buffer is mapped if the * channel allocation is successful */ - if (is_dma_capable() && musb_ep->dma) { + if (is_buffer_mapped(req)) { unmap_dma_buffer(req, musb); /* @@ -989,7 +1011,11 @@ static int musb_gadget_enable(struct usb_ep *ep, /* Set TXMAXP with the FIFO size of the endpoint * to disable double buffering mode. */ - musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11)); + if (musb->double_buffer_not_ok) + musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx); + else + musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz + | (musb_ep->hb_mult << 11)); csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG; if (musb_readw(regs, MUSB_TXCSR) @@ -1025,7 +1051,11 @@ static int musb_gadget_enable(struct usb_ep *ep, /* Set RXMAXP with the FIFO size of the endpoint * to disable double buffering mode. */ - musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11)); + if (musb->double_buffer_not_ok) + musb_writew(regs, MUSB_RXMAXP, hw_ep->max_packet_sz_tx); + else + musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz + | (musb_ep->hb_mult << 11)); /* force shared fifo to OUT-only mode */ if (hw_ep->is_shared_fifo) { @@ -1214,10 +1244,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, request->epnum = musb_ep->current_epnum; request->tx = musb_ep->is_in; - if (is_dma_capable() && musb_ep->dma) - map_dma_buffer(request, musb); - else - request->mapped = 0; + map_dma_buffer(request, musb, musb_ep); spin_lock_irqsave(&musb->lock, lockflags); diff --git a/drivers/usb/musb/musb_gadget.h b/drivers/usb/musb/musb_gadget.h index dec8dc008191..a55354fbccf5 100644 --- a/drivers/usb/musb/musb_gadget.h +++ b/drivers/usb/musb/musb_gadget.h @@ -35,13 +35,19 @@ #ifndef __MUSB_GADGET_H #define __MUSB_GADGET_H +enum buffer_map_state { + UN_MAPPED = 0, + PRE_MAPPED, + MUSB_MAPPED +}; + struct musb_request { struct usb_request request; struct musb_ep *ep; struct musb *musb; u8 tx; /* endpoint direction */ u8 epnum; - u8 mapped; + enum buffer_map_state map_state; }; static inline struct musb_request *to_musb_request(struct usb_request *req) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 4d5bcb4e14d2..0f523d7db57b 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -609,7 +609,7 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep) /* Set RXMAXP with the FIFO size of the endpoint * to disable double buffer mode. */ - if (musb->hwvers < MUSB_HWVERS_2000) + if (musb->double_buffer_not_ok) musb_writew(ep->regs, MUSB_RXMAXP, ep->max_packet_sz_rx); else musb_writew(ep->regs, MUSB_RXMAXP, @@ -784,14 +784,13 @@ static void musb_ep_program(struct musb *musb, u8 epnum, /* protocol/endpoint/interval/NAKlimit */ if (epnum) { musb_writeb(epio, MUSB_TXTYPE, qh->type_reg); - if (can_bulk_split(musb, qh->type)) + if (musb->double_buffer_not_ok) musb_writew(epio, MUSB_TXMAXP, - packet_sz - | ((hw_ep->max_packet_sz_tx / - packet_sz) - 1) << 11); + hw_ep->max_packet_sz_tx); else musb_writew(epio, MUSB_TXMAXP, - packet_sz); + qh->maxpacket | + ((qh->hb_mult - 1) << 11)); musb_writeb(epio, MUSB_TXINTERVAL, qh->intv_reg); } else { musb_writeb(epio, MUSB_NAKLIMIT0, qh->intv_reg); diff --git a/drivers/usb/musb/musbhsdma.h b/drivers/usb/musb/musbhsdma.h index f763d62f151c..21056c924c74 100644 --- a/drivers/usb/musb/musbhsdma.h +++ b/drivers/usb/musb/musbhsdma.h @@ -94,24 +94,33 @@ static inline void musb_write_hsdma_addr(void __iomem *mbase, { musb_writew(mbase, MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_LOW), - ((u16)((u32) dma_addr & 0xFFFF))); + dma_addr); musb_writew(mbase, MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_HIGH), - ((u16)(((u32) dma_addr >> 16) & 0xFFFF))); + (dma_addr >> 16)); } static inline u32 musb_read_hsdma_count(void __iomem *mbase, u8 bchannel) { - return musb_readl(mbase, + u32 count = musb_readw(mbase, MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH)); + + count = count << 16; + + count |= musb_readw(mbase, + MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW)); + + return count; } static inline void musb_write_hsdma_count(void __iomem *mbase, u8 bchannel, u32 len) { - musb_writel(mbase, + musb_writew(mbase, + MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW),len); + musb_writew(mbase, MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH), - len); + (len >> 16)); } #endif /* CONFIG_BLACKFIN */ diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index 9fb875d5f09c..9ffc8237fb4b 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig @@ -103,6 +103,8 @@ config USB_MSM_OTG_72K required after resetting the hardware and power management. This driver is required even for peripheral only or host only mode configurations. + This driver is not supported on boards like trout which + has an external PHY. config AB8500_USB tristate "AB8500 USB Transceiver Driver" diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c index e70014ab0976..8acf165fe13b 100644 --- a/drivers/usb/otg/nop-usb-xceiv.c +++ b/drivers/usb/otg/nop-usb-xceiv.c @@ -132,6 +132,8 @@ static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev) platform_set_drvdata(pdev, nop); + BLOCKING_INIT_NOTIFIER_HEAD(&nop->otg.notifier); + return 0; exit: kfree(nop); diff --git a/drivers/usb/otg/ulpi.c b/drivers/usb/otg/ulpi.c index 059d9ac0ab5b..770d799d5afb 100644 --- a/drivers/usb/otg/ulpi.c +++ b/drivers/usb/otg/ulpi.c @@ -45,7 +45,7 @@ struct ulpi_info { /* ULPI hardcoded IDs, used for probing */ static struct ulpi_info ulpi_ids[] = { ULPI_INFO(ULPI_ID(0x04cc, 0x1504), "NXP ISP1504"), - ULPI_INFO(ULPI_ID(0x0424, 0x0006), "SMSC USB3319"), + ULPI_INFO(ULPI_ID(0x0424, 0x0006), "SMSC USB331x"), }; static int ulpi_set_otg_flags(struct otg_transceiver *otg) diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index 63f7cc45bcac..7b8815ddf368 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -486,12 +486,22 @@ static void ch341_read_int_callback(struct urb *urb) if (actual_length >= 4) { struct ch341_private *priv = usb_get_serial_port_data(port); unsigned long flags; + u8 prev_line_status = priv->line_status; spin_lock_irqsave(&priv->lock, flags); priv->line_status = (~(data[2])) & CH341_BITS_MODEM_STAT; if ((data[1] & CH341_MULT_STAT)) priv->multi_status_change = 1; spin_unlock_irqrestore(&priv->lock, flags); + + if ((priv->line_status ^ prev_line_status) & CH341_BIT_DCD) { + struct tty_struct *tty = tty_port_tty_get(&port->port); + if (tty) + usb_serial_handle_dcd_change(port, tty, + priv->line_status & CH341_BIT_DCD); + tty_kref_put(tty); + } + wake_up_interruptible(&priv->delta_msr_wait); } diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 8d7731dbf478..735ea03157ab 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -49,7 +49,6 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *, static void cp210x_break_ctl(struct tty_struct *, int); static int cp210x_startup(struct usb_serial *); static void cp210x_dtr_rts(struct usb_serial_port *p, int on); -static int cp210x_carrier_raised(struct usb_serial_port *p); static int debug; @@ -87,7 +86,6 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */ { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */ { USB_DEVICE(0x10C4, 0x813F) }, /* Tams Master Easy Control */ - { USB_DEVICE(0x10C4, 0x8149) }, /* West Mountain Radio Computerized Battery Analyzer */ { USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */ { USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */ { USB_DEVICE(0x10C4, 0x8156) }, /* B&G H3000 link cable */ @@ -110,7 +108,9 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */ { USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */ { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */ + { USB_DEVICE(0x10C4, 0x83D8) }, /* DekTec DTA Plus VHF/UHF Booster/Attenuator */ { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */ + { USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */ { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */ { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ @@ -165,8 +165,7 @@ static struct usb_serial_driver cp210x_device = { .tiocmget = cp210x_tiocmget, .tiocmset = cp210x_tiocmset, .attach = cp210x_startup, - .dtr_rts = cp210x_dtr_rts, - .carrier_raised = cp210x_carrier_raised + .dtr_rts = cp210x_dtr_rts }; /* Config request types */ @@ -765,15 +764,6 @@ static int cp210x_tiocmget (struct tty_struct *tty, struct file *file) return result; } -static int cp210x_carrier_raised(struct usb_serial_port *p) -{ - unsigned int control; - cp210x_get_config(p, CP210X_GET_MDMSTS, &control, 1); - if (control & CONTROL_DCD) - return 1; - return 0; -} - static void cp210x_break_ctl (struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index b92070c103cd..666e5a6edd82 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -455,7 +455,6 @@ static int digi_write_room(struct tty_struct *tty); static int digi_chars_in_buffer(struct tty_struct *tty); static int digi_open(struct tty_struct *tty, struct usb_serial_port *port); static void digi_close(struct usb_serial_port *port); -static int digi_carrier_raised(struct usb_serial_port *port); static void digi_dtr_rts(struct usb_serial_port *port, int on); static int digi_startup_device(struct usb_serial *serial); static int digi_startup(struct usb_serial *serial); @@ -511,7 +510,6 @@ static struct usb_serial_driver digi_acceleport_2_device = { .open = digi_open, .close = digi_close, .dtr_rts = digi_dtr_rts, - .carrier_raised = digi_carrier_raised, .write = digi_write, .write_room = digi_write_room, .write_bulk_callback = digi_write_bulk_callback, @@ -1339,14 +1337,6 @@ static void digi_dtr_rts(struct usb_serial_port *port, int on) digi_set_modem_signals(port, on * (TIOCM_DTR|TIOCM_RTS), 1); } -static int digi_carrier_raised(struct usb_serial_port *port) -{ - struct digi_port *priv = usb_get_serial_port_data(port); - if (priv->dp_modem_signals & TIOCM_CD) - return 1; - return 0; -} - static int digi_open(struct tty_struct *tty, struct usb_serial_port *port) { int ret; diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index a2668d089260..f349a3629d00 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -100,6 +100,7 @@ struct ftdi_sio_quirk { static int ftdi_jtag_probe(struct usb_serial *serial); static int ftdi_mtxorb_hack_setup(struct usb_serial *serial); static int ftdi_NDI_device_setup(struct usb_serial *serial); +static int ftdi_stmclite_probe(struct usb_serial *serial); static void ftdi_USB_UIRT_setup(struct ftdi_private *priv); static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv); @@ -123,6 +124,10 @@ static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = { .port_probe = ftdi_HE_TIRA1_setup, }; +static struct ftdi_sio_quirk ftdi_stmclite_quirk = { + .probe = ftdi_stmclite_probe, +}; + /* * The 8U232AM has the same API as the sio except for: * - it can support MUCH higher baudrates; up to: @@ -616,6 +621,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_OCEANIC_PID) }, { USB_DEVICE(TTI_VID, TTI_QL355P_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) }, + { USB_DEVICE(ACTON_VID, ACTON_SPECTRAPRO_PID) }, { USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) }, { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) }, { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) }, @@ -676,7 +682,17 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RRCIRKITS_LOCOBUFFER_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) }, - { USB_DEVICE(ICOM_ID1_VID, ICOM_ID1_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_1_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_OPC_U_UC_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C1_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C2_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2D_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2VT_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2VR_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVT_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVR_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVT_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVR_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) }, { USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) }, { USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) }, @@ -800,6 +816,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) }, { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(ST_VID, ST_STMCLT1030_PID), + .driver_info = (kernel_ulong_t)&ftdi_stmclite_quirk }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; @@ -1699,6 +1717,25 @@ static int ftdi_jtag_probe(struct usb_serial *serial) } /* + * First and second port on STMCLiteadaptors is reserved for JTAG interface + * and the forth port for pio + */ +static int ftdi_stmclite_probe(struct usb_serial *serial) +{ + struct usb_device *udev = serial->dev; + struct usb_interface *interface = serial->interface; + + dbg("%s", __func__); + + if (interface == udev->actconfig->interface[2]) + return 0; + + dev_info(&udev->dev, "Ignoring serial port reserved for JTAG\n"); + + return -ENODEV; +} + +/* * The Matrix Orbital VK204-25-USB has an invalid IN endpoint. * We have to correct it if we want to read from it. */ diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index bf0867285481..117e8e6f93c6 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -518,6 +518,12 @@ #define RATOC_PRODUCT_ID_USB60F 0xb020 /* + * Acton Research Corp. + */ +#define ACTON_VID 0x0647 /* Vendor ID */ +#define ACTON_SPECTRAPRO_PID 0x0100 + +/* * Contec products (http://www.contec.com) * Submitted by Daniel Sangorrin */ @@ -569,11 +575,23 @@ #define OCT_US101_PID 0x0421 /* OCT US101 USB to RS-232 */ /* - * Icom ID-1 digital transceiver + * Definitions for Icom Inc. devices */ - -#define ICOM_ID1_VID 0x0C26 -#define ICOM_ID1_PID 0x0004 +#define ICOM_VID 0x0C26 /* Icom vendor ID */ +/* Note: ID-1 is a communications tranceiver for HAM-radio operators */ +#define ICOM_ID_1_PID 0x0004 /* ID-1 USB to RS-232 */ +/* Note: OPC is an Optional cable to connect an Icom Tranceiver */ +#define ICOM_OPC_U_UC_PID 0x0018 /* OPC-478UC, OPC-1122U cloning cable */ +/* Note: ID-RP* devices are Icom Repeater Devices for HAM-radio */ +#define ICOM_ID_RP2C1_PID 0x0009 /* ID-RP2C Asset 1 to RS-232 */ +#define ICOM_ID_RP2C2_PID 0x000A /* ID-RP2C Asset 2 to RS-232 */ +#define ICOM_ID_RP2D_PID 0x000B /* ID-RP2D configuration port*/ +#define ICOM_ID_RP2VT_PID 0x000C /* ID-RP2V Transmit config port */ +#define ICOM_ID_RP2VR_PID 0x000D /* ID-RP2V Receive config port */ +#define ICOM_ID_RP4KVT_PID 0x0010 /* ID-RP4000V Transmit config port */ +#define ICOM_ID_RP4KVR_PID 0x0011 /* ID-RP4000V Receive config port */ +#define ICOM_ID_RP2KVT_PID 0x0012 /* ID-RP2000V Transmit config port */ +#define ICOM_ID_RP2KVR_PID 0x0013 /* ID-RP2000V Receive config port */ /* * GN Otometrics (http://www.otometrics.com) @@ -1022,6 +1040,12 @@ #define WHT_PID 0x0004 /* Wireless Handheld Terminal */ /* + * STMicroelectonics + */ +#define ST_VID 0x0483 +#define ST_STMCLT1030_PID 0x3747 /* ST Micro Connect Lite STMCLT1030 */ + +/* * Papouch products (http://www.papouch.com/) * Submitted by Folkert van Heusden */ diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index e6833e216fc9..e4db5ad2bc55 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -479,6 +479,26 @@ int usb_serial_handle_break(struct usb_serial_port *port) } EXPORT_SYMBOL_GPL(usb_serial_handle_break); +/** + * usb_serial_handle_dcd_change - handle a change of carrier detect state + * @port: usb_serial_port structure for the open port + * @tty: tty_struct structure for the port + * @status: new carrier detect status, nonzero if active + */ +void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port, + struct tty_struct *tty, unsigned int status) +{ + struct tty_port *port = &usb_port->port; + + dbg("%s - port %d, status %d", __func__, usb_port->number, status); + + if (status) + wake_up_interruptible(&port->open_wait); + else if (tty && !C_CLOCAL(tty)) + tty_hangup(tty); +} +EXPORT_SYMBOL_GPL(usb_serial_handle_dcd_change); + int usb_serial_generic_resume(struct usb_serial *serial) { struct usb_serial_port *port; diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index cd769ef24f8a..3b246d93cf22 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -2889,8 +2889,8 @@ static void load_application_firmware(struct edgeport_serial *edge_serial) dbg("%s %d.%d.%d", fw_info, rec->data[0], rec->data[1], build); - edge_serial->product_info.FirmwareMajorVersion = fw->data[0]; - edge_serial->product_info.FirmwareMinorVersion = fw->data[1]; + edge_serial->product_info.FirmwareMajorVersion = rec->data[0]; + edge_serial->product_info.FirmwareMinorVersion = rec->data[1]; edge_serial->product_info.FirmwareBuildNumber = cpu_to_le16(build); for (rec = ihex_next_binrec(rec); rec; diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h index 6ab2a3f97fe8..178b22eb32b1 100644 --- a/drivers/usb/serial/io_tables.h +++ b/drivers/usb/serial/io_tables.h @@ -199,6 +199,7 @@ static struct usb_serial_driver epic_device = { .name = "epic", }, .description = "EPiC device", + .usb_driver = &io_driver, .id_table = Epic_port_id_table, .num_ports = 1, .open = edge_open, diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 12ed594f5f80..99b97c04896f 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -1275,6 +1275,7 @@ static struct usb_serial_driver iuu_device = { .name = "iuu_phoenix", }, .id_table = id_table, + .usb_driver = &iuu_driver, .num_ports = 1, .bulk_in_size = 512, .bulk_out_size = 512, diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h index 2d8baf6ac472..ce134dc28ddf 100644 --- a/drivers/usb/serial/keyspan.h +++ b/drivers/usb/serial/keyspan.h @@ -546,6 +546,7 @@ static struct usb_serial_driver keyspan_pre_device = { .name = "keyspan_no_firm", }, .description = "Keyspan - (without firmware)", + .usb_driver = &keyspan_driver, .id_table = keyspan_pre_ids, .num_ports = 1, .attach = keyspan_fake_startup, @@ -557,6 +558,7 @@ static struct usb_serial_driver keyspan_1port_device = { .name = "keyspan_1", }, .description = "Keyspan 1 port adapter", + .usb_driver = &keyspan_driver, .id_table = keyspan_1port_ids, .num_ports = 1, .open = keyspan_open, @@ -579,6 +581,7 @@ static struct usb_serial_driver keyspan_2port_device = { .name = "keyspan_2", }, .description = "Keyspan 2 port adapter", + .usb_driver = &keyspan_driver, .id_table = keyspan_2port_ids, .num_ports = 2, .open = keyspan_open, @@ -601,6 +604,7 @@ static struct usb_serial_driver keyspan_4port_device = { .name = "keyspan_4", }, .description = "Keyspan 4 port adapter", + .usb_driver = &keyspan_driver, .id_table = keyspan_4port_ids, .num_ports = 4, .open = keyspan_open, diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index a10dd5676ccc..554a8693a463 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -679,22 +679,6 @@ static void keyspan_pda_dtr_rts(struct usb_serial_port *port, int on) } } -static int keyspan_pda_carrier_raised(struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - unsigned char modembits; - - /* If we can read the modem status and the DCD is low then - carrier is not raised yet */ - if (keyspan_pda_get_modem_info(serial, &modembits) >= 0) { - if (!(modembits & (1>>6))) - return 0; - } - /* Carrier raised, or we failed (eg disconnected) so - progress accordingly */ - return 1; -} - static int keyspan_pda_open(struct tty_struct *tty, struct usb_serial_port *port) @@ -881,7 +865,6 @@ static struct usb_serial_driver keyspan_pda_device = { .id_table = id_table_std, .num_ports = 1, .dtr_rts = keyspan_pda_dtr_rts, - .carrier_raised = keyspan_pda_carrier_raised, .open = keyspan_pda_open, .close = keyspan_pda_close, .write = keyspan_pda_write, diff --git a/drivers/usb/serial/moto_modem.c b/drivers/usb/serial/moto_modem.c index cf1718394e18..653465f61d4a 100644 --- a/drivers/usb/serial/moto_modem.c +++ b/drivers/usb/serial/moto_modem.c @@ -44,6 +44,7 @@ static struct usb_serial_driver moto_device = { .name = "moto-modem", }, .id_table = id_table, + .usb_driver = &moto_driver, .num_ports = 1, }; diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 748778288d94..5f46838dfee5 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -382,7 +382,16 @@ static void option_instat_callback(struct urb *urb); #define HAIER_VENDOR_ID 0x201e #define HAIER_PRODUCT_CE100 0x2009 -#define CINTERION_VENDOR_ID 0x0681 +/* Cinterion (formerly Siemens) products */ +#define SIEMENS_VENDOR_ID 0x0681 +#define CINTERION_VENDOR_ID 0x1e2d +#define CINTERION_PRODUCT_HC25_MDM 0x0047 +#define CINTERION_PRODUCT_HC25_MDMNET 0x0040 +#define CINTERION_PRODUCT_HC28_MDM 0x004C +#define CINTERION_PRODUCT_HC28_MDMNET 0x004A /* same for HC28J */ +#define CINTERION_PRODUCT_EU3_E 0x0051 +#define CINTERION_PRODUCT_EU3_P 0x0052 +#define CINTERION_PRODUCT_PH8 0x0053 /* Olivetti products */ #define OLIVETTI_VENDOR_ID 0x0b3c @@ -944,7 +953,17 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100F) }, { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1011)}, { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1012)}, - { USB_DEVICE(CINTERION_VENDOR_ID, 0x0047) }, + /* Cinterion */ + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_E) }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8) }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDM) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDMNET) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, /* HC28 enumerates with Siemens or Cinterion VID depending on FW revision */ + { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) }, + { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) }, { USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */ { USB_DEVICE(ONDA_VENDOR_ID, ONDA_MT825UP) }, /* ONDA MT825UP modem */ diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 5be866bb7a41..73613205be7a 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -157,6 +157,7 @@ static struct usb_serial_driver oti6858_device = { .name = "oti6858", }, .id_table = id_table, + .usb_driver = &oti6858_driver, .num_ports = 1, .open = oti6858_open, .close = oti6858_close, diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 8ae4c6cbc38a..08c9181b8e48 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -50,6 +50,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, @@ -677,9 +678,11 @@ static void pl2303_update_line_status(struct usb_serial_port *port, { struct pl2303_private *priv = usb_get_serial_port_data(port); + struct tty_struct *tty; unsigned long flags; u8 status_idx = UART_STATE; u8 length = UART_STATE + 1; + u8 prev_line_status; u16 idv, idp; idv = le16_to_cpu(port->serial->dev->descriptor.idVendor); @@ -701,11 +704,20 @@ static void pl2303_update_line_status(struct usb_serial_port *port, /* Save off the uart status for others to look at */ spin_lock_irqsave(&priv->lock, flags); + prev_line_status = priv->line_status; priv->line_status = data[status_idx]; spin_unlock_irqrestore(&priv->lock, flags); if (priv->line_status & UART_BREAK_ERROR) usb_serial_handle_break(port); wake_up_interruptible(&priv->delta_msr_wait); + + tty = tty_port_tty_get(&port->port); + if (!tty) + return; + if ((priv->line_status ^ prev_line_status) & UART_DCD) + usb_serial_handle_dcd_change(port, tty, + priv->line_status & UART_DCD); + tty_kref_put(tty); } static void pl2303_read_int_callback(struct urb *urb) diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 43eb9bdad422..1b025f75dafd 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -21,6 +21,7 @@ #define PL2303_PRODUCT_ID_MMX 0x0612 #define PL2303_PRODUCT_ID_GPRS 0x0609 #define PL2303_PRODUCT_ID_HCR331 0x331a +#define PL2303_PRODUCT_ID_MOTOROLA 0x0307 #define ATEN_VENDOR_ID 0x0557 #define ATEN_VENDOR_ID2 0x0547 diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c index 214a3e504292..30b73e68a904 100644 --- a/drivers/usb/serial/qcaux.c +++ b/drivers/usb/serial/qcaux.c @@ -36,6 +36,7 @@ #define UTSTARCOM_PRODUCT_UM175_V1 0x3712 #define UTSTARCOM_PRODUCT_UM175_V2 0x3714 #define UTSTARCOM_PRODUCT_UM175_ALLTEL 0x3715 +#define PANTECH_PRODUCT_UML290_VZW 0x3718 /* CMOTECH devices */ #define CMOTECH_VENDOR_ID 0x16d8 @@ -66,6 +67,7 @@ static struct usb_device_id id_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(LG_VENDOR_ID, LG_PRODUCT_VX4400_6000, 0xff, 0xff, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(SANYO_VENDOR_ID, SANYO_PRODUCT_KATANA_LX, 0xff, 0xff, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_U520, 0xff, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xff, 0xff) }, { }, }; MODULE_DEVICE_TABLE(usb, id_table); @@ -84,6 +86,7 @@ static struct usb_serial_driver qcaux_device = { .name = "qcaux", }, .id_table = id_table, + .usb_driver = &qcaux_driver, .num_ports = 1, }; diff --git a/drivers/usb/serial/siemens_mpi.c b/drivers/usb/serial/siemens_mpi.c index cb8195cabfde..74cd4ccdb3fc 100644 --- a/drivers/usb/serial/siemens_mpi.c +++ b/drivers/usb/serial/siemens_mpi.c @@ -42,6 +42,7 @@ static struct usb_serial_driver siemens_usb_mpi_device = { .name = "siemens_mpi", }, .id_table = id_table, + .usb_driver = &siemens_usb_mpi_driver, .num_ports = 1, }; diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index 765aa983bf58..cbfb70bffdd0 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -133,7 +133,7 @@ struct spcp8x5_usb_ctrl_arg { /* how come ??? */ #define UART_STATE 0x08 -#define UART_STATE_TRANSIENT_MASK 0x74 +#define UART_STATE_TRANSIENT_MASK 0x75 #define UART_DCD 0x01 #define UART_DSR 0x02 #define UART_BREAK_ERROR 0x04 @@ -525,6 +525,10 @@ static void spcp8x5_process_read_urb(struct urb *urb) /* overrun is special, not associated with a char */ if (status & UART_OVERRUN_ERROR) tty_insert_flip_char(tty, 0, TTY_OVERRUN); + + if (status & UART_DCD) + usb_serial_handle_dcd_change(port, tty, + priv->line_status & MSR_STATUS_LINE_DCD); } tty_insert_flip_string_fixed_flag(tty, data, tty_flag, @@ -645,6 +649,7 @@ static struct usb_serial_driver spcp8x5_device = { .name = "SPCP8x5", }, .id_table = id_table, + .usb_driver = &spcp8x5_driver, .num_ports = 1, .open = spcp8x5_open, .dtr_rts = spcp8x5_dtr_rts, diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index b2902f307b47..a910004f4079 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -369,9 +369,9 @@ failed_1port: static void __exit ti_exit(void) { + usb_deregister(&ti_usb_driver); usb_serial_deregister(&ti_1port_device); usb_serial_deregister(&ti_2port_device); - usb_deregister(&ti_usb_driver); } diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 6954de50c0ff..546a52179bec 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1344,11 +1344,15 @@ int usb_serial_register(struct usb_serial_driver *driver) return -ENODEV; fixup_generic(driver); - if (driver->usb_driver) - driver->usb_driver->supports_autosuspend = 1; if (!driver->description) driver->description = driver->driver.name; + if (!driver->usb_driver) { + WARN(1, "Serial driver %s has no usb_driver\n", + driver->description); + return -EINVAL; + } + driver->usb_driver->supports_autosuspend = 1; /* Add this device to our list of devices */ mutex_lock(&table_lock); diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c index f2ed6a31be77..95a82148ee81 100644 --- a/drivers/usb/serial/usb_debug.c +++ b/drivers/usb/serial/usb_debug.c @@ -75,6 +75,7 @@ static struct usb_serial_driver debug_device = { .name = "debug", }, .id_table = id_table, + .usb_driver = &debug_driver, .num_ports = 1, .bulk_out_size = USB_DEBUG_MAX_PACKET_SIZE, .break_ctl = usb_debug_break_ctl, diff --git a/drivers/usb/storage/unusual_cypress.h b/drivers/usb/storage/unusual_cypress.h index c854fdebe0ae..2c8553026222 100644 --- a/drivers/usb/storage/unusual_cypress.h +++ b/drivers/usb/storage/unusual_cypress.h @@ -31,4 +31,9 @@ UNUSUAL_DEV( 0x04b4, 0x6831, 0x0000, 0x9999, "Cypress ISD-300LP", USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0), +UNUSUAL_DEV( 0x14cd, 0x6116, 0x0000, 0x9999, + "Super Top", + "USB 2.0 SATA BRIDGE", + USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0), + #endif /* defined(CONFIG_USB_STORAGE_CYPRESS_ATACB) || ... */ diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index fcc1e32ce256..c1602b8c5594 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1044,6 +1044,15 @@ UNUSUAL_DEV( 0x084d, 0x0011, 0x0110, 0x0110, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_BULK32), +/* Reported by <ttkspam@free.fr> + * The device reports a vendor-specific device class, requiring an + * explicit vendor/product match. + */ +UNUSUAL_DEV( 0x0851, 0x1542, 0x0002, 0x0002, + "MagicPixel", + "FW_Omega2", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, 0), + /* Andrew Lunn <andrew@lunn.ch> * PanDigital Digital Picture Frame. Does not like ALLOW_MEDIUM_REMOVAL * on LUN 4. @@ -1388,6 +1397,13 @@ UNUSUAL_DEV( 0x0f19, 0x0105, 0x0100, 0x0100, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Submitted by Nick Holloway */ +UNUSUAL_DEV( 0x0f88, 0x042e, 0x0100, 0x0100, + "VTech", + "Kidizoom", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + /* Reported by Michael Stattmann <michael@stattmann.com> */ UNUSUAL_DEV( 0x0fce, 0xd008, 0x0000, 0x0000, "Sony Ericsson", @@ -1872,6 +1888,22 @@ UNUSUAL_DEV( 0x1908, 0x3335, 0x0200, 0x0200, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_READ_DISC_INFO ), +/* Patch by Richard Schütz <r.schtz@t-online.de> + * This external hard drive enclosure uses a JMicron chip which + * needs the US_FL_IGNORE_RESIDUE flag to work properly. */ +UNUSUAL_DEV( 0x1e68, 0x001b, 0x0000, 0x0000, + "TrekStor GmbH & Co. KG", + "DataStation maxi g.u", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE | US_FL_SANE_SENSE ), + +/* Reported by Jasper Mackenzie <scarletpimpernal@hotmail.com> */ +UNUSUAL_DEV( 0x1e74, 0x4621, 0x0000, 0x0000, + "Coby Electronics", + "MP3 Player", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_BULK_IGNORE_TAG | US_FL_MAX_SECTORS_64 ), + UNUSUAL_DEV( 0x2116, 0x0320, 0x0001, 0x0001, "ST", "2A", diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index d583bea608fd..391ac939f011 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -23,7 +23,7 @@ #include <linux/svga.h> #include <linux/init.h> #include <linux/pci.h> -#include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */ +#include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */ #include <video/vga.h> #ifdef CONFIG_MTRR @@ -1091,12 +1091,12 @@ static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state) dev_info(info->device, "suspend\n"); - acquire_console_sem(); + console_lock(); mutex_lock(&(par->open_lock)); if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) { mutex_unlock(&(par->open_lock)); - release_console_sem(); + console_unlock(); return 0; } @@ -1107,7 +1107,7 @@ static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state) pci_set_power_state(dev, pci_choose_state(dev, state)); mutex_unlock(&(par->open_lock)); - release_console_sem(); + console_unlock(); return 0; } @@ -1122,7 +1122,7 @@ static int ark_pci_resume (struct pci_dev* dev) dev_info(info->device, "resume\n"); - acquire_console_sem(); + console_lock(); mutex_lock(&(par->open_lock)); if (par->ref_count == 0) @@ -1141,7 +1141,7 @@ static int ark_pci_resume (struct pci_dev* dev) fail: mutex_unlock(&(par->open_lock)); - release_console_sem(); + console_unlock(); return 0; } #else diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index dd9de2e80580..4cb6a576c567 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -1860,11 +1860,11 @@ static void aty128_early_resume(void *data) { struct aty128fb_par *par = data; - if (try_acquire_console_sem()) + if (!console_trylock()) return; pci_restore_state(par->pdev); aty128_do_resume(par->pdev); - release_console_sem(); + console_unlock(); } #endif /* CONFIG_PPC_PMAC */ @@ -2438,7 +2438,7 @@ static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state) printk(KERN_DEBUG "aty128fb: suspending...\n"); - acquire_console_sem(); + console_lock(); fb_set_suspend(info, 1); @@ -2470,7 +2470,7 @@ static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state) if (state.event != PM_EVENT_ON) aty128_set_suspend(par, 1); - release_console_sem(); + console_unlock(); pdev->dev.power.power_state = state; @@ -2527,9 +2527,9 @@ static int aty128_pci_resume(struct pci_dev *pdev) { int rc; - acquire_console_sem(); + console_lock(); rc = aty128_do_resume(pdev); - release_console_sem(); + console_unlock(); return rc; } diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 767ab4fb1a05..94e293fce1d2 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2069,7 +2069,7 @@ static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state) if (state.event == pdev->dev.power.power_state.event) return 0; - acquire_console_sem(); + console_lock(); fb_set_suspend(info, 1); @@ -2097,14 +2097,14 @@ static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state) par->lock_blank = 0; atyfb_blank(FB_BLANK_UNBLANK, info); fb_set_suspend(info, 0); - release_console_sem(); + console_unlock(); return -EIO; } #else pci_set_power_state(pdev, pci_choose_state(pdev, state)); #endif - release_console_sem(); + console_unlock(); pdev->dev.power.power_state = state; @@ -2133,7 +2133,7 @@ static int atyfb_pci_resume(struct pci_dev *pdev) if (pdev->dev.power.power_state.event == PM_EVENT_ON) return 0; - acquire_console_sem(); + console_lock(); /* * PCI state will have been restored by the core, so @@ -2161,7 +2161,7 @@ static int atyfb_pci_resume(struct pci_dev *pdev) par->lock_blank = 0; atyfb_blank(FB_BLANK_UNBLANK, info); - release_console_sem(); + console_unlock(); pdev->dev.power.power_state = PMSG_ON; diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c index c4e17642d9c5..92bda5848516 100644 --- a/drivers/video/aty/radeon_pm.c +++ b/drivers/video/aty/radeon_pm.c @@ -2626,7 +2626,7 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) goto done; } - acquire_console_sem(); + console_lock(); fb_set_suspend(info, 1); @@ -2690,7 +2690,7 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) if (rinfo->pm_mode & radeon_pm_d2) radeon_set_suspend(rinfo, 1); - release_console_sem(); + console_unlock(); done: pdev->dev.power.power_state = mesg; @@ -2715,10 +2715,10 @@ int radeonfb_pci_resume(struct pci_dev *pdev) return 0; if (rinfo->no_schedule) { - if (try_acquire_console_sem()) + if (!console_trylock()) return 0; } else - acquire_console_sem(); + console_lock(); printk(KERN_DEBUG "radeonfb (%s): resuming from state: %d...\n", pci_name(pdev), pdev->dev.power.power_state.event); @@ -2783,7 +2783,7 @@ int radeonfb_pci_resume(struct pci_dev *pdev) pdev->dev.power.power_state = PMSG_ON; bail: - release_console_sem(); + console_unlock(); return rc; } diff --git a/drivers/video/bf537-lq035.c b/drivers/video/bf537-lq035.c index 18c507874ff1..47c21fb2c82f 100644 --- a/drivers/video/bf537-lq035.c +++ b/drivers/video/bf537-lq035.c @@ -696,6 +696,7 @@ static int __devinit bfin_lq035_probe(struct platform_device *pdev) { struct backlight_properties props; dma_addr_t dma_handle; + int ret; if (request_dma(CH_PPI, KBUILD_MODNAME)) { pr_err("couldn't request PPI DMA\n"); @@ -704,17 +705,16 @@ static int __devinit bfin_lq035_probe(struct platform_device *pdev) if (request_ports()) { pr_err("couldn't request gpio port\n"); - free_dma(CH_PPI); - return -EFAULT; + ret = -EFAULT; + goto out_ports; } fb_buffer = dma_alloc_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, &dma_handle, GFP_KERNEL); if (fb_buffer == NULL) { pr_err("couldn't allocate dma buffer\n"); - free_dma(CH_PPI); - free_ports(); - return -ENOMEM; + ret = -ENOMEM; + goto out_dma_coherent; } if (L1_DATA_A_LENGTH) @@ -725,10 +725,8 @@ static int __devinit bfin_lq035_probe(struct platform_device *pdev) if (dma_desc_table == NULL) { pr_err("couldn't allocate dma descriptor\n"); - free_dma(CH_PPI); - free_ports(); - dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0); - return -ENOMEM; + ret = -ENOMEM; + goto out_table; } bfin_lq035_fb.screen_base = (void *)fb_buffer; @@ -771,31 +769,21 @@ static int __devinit bfin_lq035_probe(struct platform_device *pdev) bfin_lq035_fb.pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL); if (bfin_lq035_fb.pseudo_palette == NULL) { pr_err("failed to allocate pseudo_palette\n"); - free_dma(CH_PPI); - free_ports(); - dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0); - return -ENOMEM; + ret = -ENOMEM; + goto out_palette; } if (fb_alloc_cmap(&bfin_lq035_fb.cmap, NBR_PALETTE, 0) < 0) { pr_err("failed to allocate colormap (%d entries)\n", NBR_PALETTE); - free_dma(CH_PPI); - free_ports(); - dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0); - kfree(bfin_lq035_fb.pseudo_palette); - return -EFAULT; + ret = -EFAULT; + goto out_cmap; } if (register_framebuffer(&bfin_lq035_fb) < 0) { pr_err("unable to register framebuffer\n"); - free_dma(CH_PPI); - free_ports(); - dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0); - fb_buffer = NULL; - kfree(bfin_lq035_fb.pseudo_palette); - fb_dealloc_cmap(&bfin_lq035_fb.cmap); - return -EINVAL; + ret = -EINVAL; + goto out_reg; } i2c_add_driver(&ad5280_driver); @@ -807,11 +795,31 @@ static int __devinit bfin_lq035_probe(struct platform_device *pdev) lcd_dev = lcd_device_register(KBUILD_MODNAME, &pdev->dev, NULL, &bfin_lcd_ops); + if (IS_ERR(lcd_dev)) { + pr_err("unable to register lcd\n"); + ret = PTR_ERR(lcd_dev); + goto out_lcd; + } lcd_dev->props.max_contrast = 255, pr_info("initialized"); return 0; +out_lcd: + unregister_framebuffer(&bfin_lq035_fb); +out_reg: + fb_dealloc_cmap(&bfin_lq035_fb.cmap); +out_cmap: + kfree(bfin_lq035_fb.pseudo_palette); +out_palette: +out_table: + dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0); + fb_buffer = NULL; +out_dma_coherent: + free_ports(); +out_ports: + free_dma(CH_PPI); + return ret; } static int __devexit bfin_lq035_remove(struct platform_device *pdev) diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c index d637e1f53172..cff742abdc5d 100644 --- a/drivers/video/chipsfb.c +++ b/drivers/video/chipsfb.c @@ -460,10 +460,10 @@ static int chipsfb_pci_suspend(struct pci_dev *pdev, pm_message_t state) if (!(state.event & PM_EVENT_SLEEP)) goto done; - acquire_console_sem(); + console_lock(); chipsfb_blank(1, p); fb_set_suspend(p, 1); - release_console_sem(); + console_unlock(); done: pdev->dev.power.power_state = state; return 0; @@ -473,10 +473,10 @@ static int chipsfb_pci_resume(struct pci_dev *pdev) { struct fb_info *p = pci_get_drvdata(pdev); - acquire_console_sem(); + console_lock(); fb_set_suspend(p, 0); chipsfb_blank(0, p); - release_console_sem(); + console_unlock(); pdev->dev.power.power_state = PMSG_ON; return 0; diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 7ccc967831f0..9c092b8d64e6 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -375,14 +375,14 @@ static void fb_flashcursor(struct work_struct *work) int c; int mode; - acquire_console_sem(); + console_lock(); if (ops && ops->currcon != -1) vc = vc_cons[ops->currcon].d; if (!vc || !CON_IS_VISIBLE(vc) || registered_fb[con2fb_map[vc->vc_num]] != info || vc->vc_deccm != 1) { - release_console_sem(); + console_unlock(); return; } @@ -392,7 +392,7 @@ static void fb_flashcursor(struct work_struct *work) CM_ERASE : CM_DRAW; ops->cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1), get_color(vc, info, c, 0)); - release_console_sem(); + console_unlock(); } static void cursor_timer_handler(unsigned long dev_addr) @@ -836,7 +836,7 @@ static int set_con2fb_map(int unit, int newidx, int user) found = search_fb_in_map(newidx); - acquire_console_sem(); + console_lock(); con2fb_map[unit] = newidx; if (!err && !found) err = con2fb_acquire_newinfo(vc, info, unit, oldidx); @@ -863,7 +863,7 @@ static int set_con2fb_map(int unit, int newidx, int user) if (!search_fb_in_map(info_idx)) info_idx = newidx; - release_console_sem(); + console_unlock(); return err; } @@ -3321,7 +3321,7 @@ static ssize_t store_rotate(struct device *device, if (fbcon_has_exited) return count; - acquire_console_sem(); + console_lock(); idx = con2fb_map[fg_console]; if (idx == -1 || registered_fb[idx] == NULL) @@ -3331,7 +3331,7 @@ static ssize_t store_rotate(struct device *device, rotate = simple_strtoul(buf, last, 0); fbcon_rotate(info, rotate); err: - release_console_sem(); + console_unlock(); return count; } @@ -3346,7 +3346,7 @@ static ssize_t store_rotate_all(struct device *device, if (fbcon_has_exited) return count; - acquire_console_sem(); + console_lock(); idx = con2fb_map[fg_console]; if (idx == -1 || registered_fb[idx] == NULL) @@ -3356,7 +3356,7 @@ static ssize_t store_rotate_all(struct device *device, rotate = simple_strtoul(buf, last, 0); fbcon_rotate_all(info, rotate); err: - release_console_sem(); + console_unlock(); return count; } @@ -3369,7 +3369,7 @@ static ssize_t show_rotate(struct device *device, if (fbcon_has_exited) return 0; - acquire_console_sem(); + console_lock(); idx = con2fb_map[fg_console]; if (idx == -1 || registered_fb[idx] == NULL) @@ -3378,7 +3378,7 @@ static ssize_t show_rotate(struct device *device, info = registered_fb[idx]; rotate = fbcon_get_rotate(info); err: - release_console_sem(); + console_unlock(); return snprintf(buf, PAGE_SIZE, "%d\n", rotate); } @@ -3392,7 +3392,7 @@ static ssize_t show_cursor_blink(struct device *device, if (fbcon_has_exited) return 0; - acquire_console_sem(); + console_lock(); idx = con2fb_map[fg_console]; if (idx == -1 || registered_fb[idx] == NULL) @@ -3406,7 +3406,7 @@ static ssize_t show_cursor_blink(struct device *device, blink = (ops->flags & FBCON_FLAGS_CURSOR_TIMER) ? 1 : 0; err: - release_console_sem(); + console_unlock(); return snprintf(buf, PAGE_SIZE, "%d\n", blink); } @@ -3421,7 +3421,7 @@ static ssize_t store_cursor_blink(struct device *device, if (fbcon_has_exited) return count; - acquire_console_sem(); + console_lock(); idx = con2fb_map[fg_console]; if (idx == -1 || registered_fb[idx] == NULL) @@ -3443,7 +3443,7 @@ static ssize_t store_cursor_blink(struct device *device, } err: - release_console_sem(); + console_unlock(); return count; } @@ -3482,7 +3482,7 @@ static void fbcon_start(void) if (num_registered_fb) { int i; - acquire_console_sem(); + console_lock(); for (i = 0; i < FB_MAX; i++) { if (registered_fb[i] != NULL) { @@ -3491,7 +3491,7 @@ static void fbcon_start(void) } } - release_console_sem(); + console_unlock(); fbcon_takeover(0); } } @@ -3552,7 +3552,7 @@ static int __init fb_console_init(void) { int i; - acquire_console_sem(); + console_lock(); fb_register_client(&fbcon_event_notifier); fbcon_device = device_create(fb_class, NULL, MKDEV(0, 0), NULL, "fbcon"); @@ -3568,7 +3568,7 @@ static int __init fb_console_init(void) for (i = 0; i < MAX_NR_CONSOLES; i++) con2fb_map[i] = -1; - release_console_sem(); + console_unlock(); fbcon_start(); return 0; } @@ -3591,12 +3591,12 @@ static void __exit fbcon_deinit_device(void) static void __exit fb_console_exit(void) { - acquire_console_sem(); + console_lock(); fb_unregister_client(&fbcon_event_notifier); fbcon_deinit_device(); device_destroy(fb_class, MKDEV(0, 0)); fbcon_exit(); - release_console_sem(); + console_unlock(); unregister_con_driver(&fb_con); } diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index c97491b8b39b..915fd74da7a2 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -202,11 +202,7 @@ static void vgacon_scrollback_init(int pitch) } } -/* - * Called only duing init so call of alloc_bootmen is ok. - * Marked __init_refok to silence modpost. - */ -static void __init_refok vgacon_scrollback_startup(void) +static void vgacon_scrollback_startup(void) { vgacon_scrollback = kcalloc(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE, 1024, GFP_NOWAIT); vgacon_scrollback_init(vga_video_num_columns * 2); diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index c265aed09e04..8d61ef96eedd 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c @@ -1092,9 +1092,10 @@ static int __init fb_probe(struct platform_device *device) irq_freq: #ifdef CONFIG_CPU_FREQ + lcd_da8xx_cpufreq_deregister(par); +#endif err_cpu_freq: unregister_framebuffer(da8xx_fb_info); -#endif err_dealloc_cmap: fb_dealloc_cmap(&da8xx_fb_info->cmap); @@ -1130,14 +1131,14 @@ static int fb_suspend(struct platform_device *dev, pm_message_t state) struct fb_info *info = platform_get_drvdata(dev); struct da8xx_fb_par *par = info->par; - acquire_console_sem(); + console_lock(); if (par->panel_power_ctrl) par->panel_power_ctrl(0); fb_set_suspend(info, 1); lcd_disable_raster(); clk_disable(par->lcdc_clk); - release_console_sem(); + console_unlock(); return 0; } @@ -1146,14 +1147,14 @@ static int fb_resume(struct platform_device *dev) struct fb_info *info = platform_get_drvdata(dev); struct da8xx_fb_par *par = info->par; - acquire_console_sem(); + console_lock(); if (par->panel_power_ctrl) par->panel_power_ctrl(1); clk_enable(par->lcdc_clk); lcd_enable_raster(); fb_set_suspend(info, 0); - release_console_sem(); + console_unlock(); return 0; } diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 4ac1201ad6c2..e2bf95370e40 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1036,11 +1036,11 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, return -EFAULT; if (!lock_fb_info(info)) return -ENODEV; - acquire_console_sem(); + console_lock(); info->flags |= FBINFO_MISC_USEREVENT; ret = fb_set_var(info, &var); info->flags &= ~FBINFO_MISC_USEREVENT; - release_console_sem(); + console_unlock(); unlock_fb_info(info); if (!ret && copy_to_user(argp, &var, sizeof(var))) ret = -EFAULT; @@ -1072,9 +1072,9 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, return -EFAULT; if (!lock_fb_info(info)) return -ENODEV; - acquire_console_sem(); + console_lock(); ret = fb_pan_display(info, &var); - release_console_sem(); + console_unlock(); unlock_fb_info(info); if (ret == 0 && copy_to_user(argp, &var, sizeof(var))) return -EFAULT; @@ -1119,11 +1119,11 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, case FBIOBLANK: if (!lock_fb_info(info)) return -ENODEV; - acquire_console_sem(); + console_lock(); info->flags |= FBINFO_MISC_USEREVENT; ret = fb_blank(info, arg); info->flags &= ~FBINFO_MISC_USEREVENT; - release_console_sem(); + console_unlock(); unlock_fb_info(info); break; default: diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index 0a08f1341227..f4a32779168b 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c @@ -90,11 +90,11 @@ static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var) int err; var->activate |= FB_ACTIVATE_FORCE; - acquire_console_sem(); + console_lock(); fb_info->flags |= FBINFO_MISC_USEREVENT; err = fb_set_var(fb_info, var); fb_info->flags &= ~FBINFO_MISC_USEREVENT; - release_console_sem(); + console_unlock(); if (err) return err; return 0; @@ -175,7 +175,7 @@ static ssize_t store_modes(struct device *device, if (i * sizeof(struct fb_videomode) != count) return -EINVAL; - acquire_console_sem(); + console_lock(); list_splice(&fb_info->modelist, &old_list); fb_videomode_to_modelist((const struct fb_videomode *)buf, i, &fb_info->modelist); @@ -185,7 +185,7 @@ static ssize_t store_modes(struct device *device, } else fb_destroy_modelist(&old_list); - release_console_sem(); + console_unlock(); return 0; } @@ -301,11 +301,11 @@ static ssize_t store_blank(struct device *device, char *last = NULL; int err; - acquire_console_sem(); + console_lock(); fb_info->flags |= FBINFO_MISC_USEREVENT; err = fb_blank(fb_info, simple_strtoul(buf, &last, 0)); fb_info->flags &= ~FBINFO_MISC_USEREVENT; - release_console_sem(); + console_unlock(); if (err < 0) return err; return count; @@ -364,9 +364,9 @@ static ssize_t store_pan(struct device *device, return -EINVAL; var.yoffset = simple_strtoul(last, &last, 0); - acquire_console_sem(); + console_lock(); err = fb_pan_display(fb_info, &var); - release_console_sem(); + console_unlock(); if (err < 0) return err; @@ -399,9 +399,9 @@ static ssize_t store_fbstate(struct device *device, state = simple_strtoul(buf, &last, 0); - acquire_console_sem(); + console_lock(); fb_set_suspend(fb_info, (int)state); - release_console_sem(); + console_unlock(); return count; } diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c index 70b1d9d51c96..b4f19db9bb54 100644 --- a/drivers/video/geode/gxfb_core.c +++ b/drivers/video/geode/gxfb_core.c @@ -344,10 +344,10 @@ static int gxfb_suspend(struct pci_dev *pdev, pm_message_t state) struct fb_info *info = pci_get_drvdata(pdev); if (state.event == PM_EVENT_SUSPEND) { - acquire_console_sem(); + console_lock(); gx_powerdown(info); fb_set_suspend(info, 1); - release_console_sem(); + console_unlock(); } /* there's no point in setting PCI states; we emulate PCI, so @@ -361,7 +361,7 @@ static int gxfb_resume(struct pci_dev *pdev) struct fb_info *info = pci_get_drvdata(pdev); int ret; - acquire_console_sem(); + console_lock(); ret = gx_powerup(info); if (ret) { printk(KERN_ERR "gxfb: power up failed!\n"); @@ -369,7 +369,7 @@ static int gxfb_resume(struct pci_dev *pdev) } fb_set_suspend(info, 0); - release_console_sem(); + console_unlock(); return 0; } #endif diff --git a/drivers/video/geode/lxfb_core.c b/drivers/video/geode/lxfb_core.c index 39bdbedf43b4..416851ca8754 100644 --- a/drivers/video/geode/lxfb_core.c +++ b/drivers/video/geode/lxfb_core.c @@ -465,10 +465,10 @@ static int lxfb_suspend(struct pci_dev *pdev, pm_message_t state) struct fb_info *info = pci_get_drvdata(pdev); if (state.event == PM_EVENT_SUSPEND) { - acquire_console_sem(); + console_lock(); lx_powerdown(info); fb_set_suspend(info, 1); - release_console_sem(); + console_unlock(); } /* there's no point in setting PCI states; we emulate PCI, so @@ -482,7 +482,7 @@ static int lxfb_resume(struct pci_dev *pdev) struct fb_info *info = pci_get_drvdata(pdev); int ret; - acquire_console_sem(); + console_lock(); ret = lx_powerup(info); if (ret) { printk(KERN_ERR "lxfb: power up failed!\n"); @@ -490,7 +490,7 @@ static int lxfb_resume(struct pci_dev *pdev) } fb_set_suspend(info, 0); - release_console_sem(); + console_unlock(); return 0; } #else diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index 5743ea25e818..318f6fb895b2 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -1574,7 +1574,7 @@ static int i810fb_suspend(struct pci_dev *dev, pm_message_t mesg) return 0; } - acquire_console_sem(); + console_lock(); fb_set_suspend(info, 1); if (info->fbops->fb_sync) @@ -1587,7 +1587,7 @@ static int i810fb_suspend(struct pci_dev *dev, pm_message_t mesg) pci_save_state(dev); pci_disable_device(dev); pci_set_power_state(dev, pci_choose_state(dev, mesg)); - release_console_sem(); + console_unlock(); return 0; } @@ -1605,7 +1605,7 @@ static int i810fb_resume(struct pci_dev *dev) return 0; } - acquire_console_sem(); + console_lock(); pci_set_power_state(dev, PCI_D0); pci_restore_state(dev); @@ -1621,7 +1621,7 @@ static int i810fb_resume(struct pci_dev *dev) fb_set_suspend (info, 0); info->fbops->fb_blank(VESA_NO_BLANKING, info); fail: - release_console_sem(); + console_unlock(); return 0; } /*********************************************************************** diff --git a/drivers/video/jz4740_fb.c b/drivers/video/jz4740_fb.c index 670ecaa0385a..de366937c933 100644 --- a/drivers/video/jz4740_fb.c +++ b/drivers/video/jz4740_fb.c @@ -778,9 +778,9 @@ static int jzfb_suspend(struct device *dev) { struct jzfb *jzfb = dev_get_drvdata(dev); - acquire_console_sem(); + console_lock(); fb_set_suspend(jzfb->fb, 1); - release_console_sem(); + console_unlock(); mutex_lock(&jzfb->lock); if (jzfb->is_enabled) @@ -800,9 +800,9 @@ static int jzfb_resume(struct device *dev) jzfb_enable(jzfb); mutex_unlock(&jzfb->lock); - acquire_console_sem(); + console_lock(); fb_set_suspend(jzfb->fb, 0); - release_console_sem(); + console_unlock(); return 0; } diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index cb013919e9ce..7e3a490e8d76 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -1177,9 +1177,9 @@ static int mx3fb_suspend(struct platform_device *pdev, pm_message_t state) struct mx3fb_data *mx3fb = platform_get_drvdata(pdev); struct mx3fb_info *mx3_fbi = mx3fb->fbi->par; - acquire_console_sem(); + console_lock(); fb_set_suspend(mx3fb->fbi, 1); - release_console_sem(); + console_unlock(); if (mx3_fbi->blank == FB_BLANK_UNBLANK) { sdc_disable_channel(mx3_fbi); @@ -1202,9 +1202,9 @@ static int mx3fb_resume(struct platform_device *pdev) sdc_set_brightness(mx3fb, mx3fb->backlight_level); } - acquire_console_sem(); + console_lock(); fb_set_suspend(mx3fb->fbi, 0); - release_console_sem(); + console_unlock(); return 0; } diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c index 62498bd662fc..f838d9e277f0 100644 --- a/drivers/video/nuc900fb.c +++ b/drivers/video/nuc900fb.c @@ -696,6 +696,8 @@ static int nuc900fb_remove(struct platform_device *pdev) nuc900fb_stop_lcd(fbinfo); msleep(1); + unregister_framebuffer(fbinfo); + nuc900fb_cpufreq_deregister(fbi); nuc900fb_unmap_video_memory(fbinfo); iounmap(fbi->io); @@ -723,7 +725,7 @@ static int nuc900fb_suspend(struct platform_device *dev, pm_message_t state) struct fb_info *fbinfo = platform_get_drvdata(dev); struct nuc900fb_info *info = fbinfo->par; - nuc900fb_stop_lcd(); + nuc900fb_stop_lcd(fbinfo); msleep(1); clk_disable(info->clk); return 0; @@ -740,7 +742,7 @@ static int nuc900fb_resume(struct platform_device *dev) msleep(1); nuc900fb_init_registers(fbinfo); - nuc900fb_activate_var(bfinfo); + nuc900fb_activate_var(fbinfo); return 0; } diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index efe10ff86d63..081dc4745274 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -1057,7 +1057,7 @@ static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t mesg) if (mesg.event == PM_EVENT_PRETHAW) mesg.event = PM_EVENT_FREEZE; - acquire_console_sem(); + console_lock(); par->pm_state = mesg.event; if (mesg.event & PM_EVENT_SLEEP) { @@ -1070,7 +1070,7 @@ static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t mesg) } dev->dev.power.power_state = mesg; - release_console_sem(); + console_unlock(); return 0; } @@ -1079,7 +1079,7 @@ static int nvidiafb_resume(struct pci_dev *dev) struct fb_info *info = pci_get_drvdata(dev); struct nvidia_par *par = info->par; - acquire_console_sem(); + console_lock(); pci_set_power_state(dev, PCI_D0); if (par->pm_state != PM_EVENT_FREEZE) { @@ -1097,7 +1097,7 @@ static int nvidiafb_resume(struct pci_dev *dev) nvidiafb_blank(FB_BLANK_UNBLANK, info); fail: - release_console_sem(); + console_unlock(); return 0; } #else diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 9c0144ee7ae5..65560a1a0439 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -513,9 +513,9 @@ static int ps3fb_release(struct fb_info *info, int user) if (atomic_dec_and_test(&ps3fb.f_count)) { if (atomic_read(&ps3fb.ext_flip)) { atomic_set(&ps3fb.ext_flip, 0); - if (!try_acquire_console_sem()) { + if (console_trylock()) { ps3fb_sync(info, 0); /* single buffer */ - release_console_sem(); + console_unlock(); } } } @@ -830,14 +830,14 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, if (vmode) { var = info->var; fb_videomode_to_var(&var, vmode); - acquire_console_sem(); + console_lock(); info->flags |= FBINFO_MISC_USEREVENT; /* Force, in case only special bits changed */ var.activate |= FB_ACTIVATE_FORCE; par->new_mode_id = val; retval = fb_set_var(info, &var); info->flags &= ~FBINFO_MISC_USEREVENT; - release_console_sem(); + console_unlock(); } break; } @@ -881,9 +881,9 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, break; dev_dbg(info->device, "PS3FB_IOCTL_FSEL:%d\n", val); - acquire_console_sem(); + console_lock(); retval = ps3fb_sync(info, val); - release_console_sem(); + console_unlock(); break; default: @@ -903,9 +903,9 @@ static int ps3fbd(void *arg) set_current_state(TASK_INTERRUPTIBLE); if (ps3fb.is_kicked) { ps3fb.is_kicked = 0; - acquire_console_sem(); + console_lock(); ps3fb_sync(info, 0); /* single buffer */ - release_console_sem(); + console_unlock(); } schedule(); } diff --git a/drivers/video/pxa168fb.c b/drivers/video/pxa168fb.c index cea6403ae71c..35f61dd0cb3a 100644 --- a/drivers/video/pxa168fb.c +++ b/drivers/video/pxa168fb.c @@ -701,16 +701,12 @@ static int __devinit pxa168fb_probe(struct platform_device *pdev) */ pxa168fb_init_mode(info, mi); - ret = pxa168fb_check_var(&info->var, info); - if (ret) - goto failed_free_fbmem; - /* * Fill in sane defaults. */ ret = pxa168fb_check_var(&info->var, info); if (ret) - goto failed; + goto failed_free_fbmem; /* * enable controller clock diff --git a/drivers/video/pxa3xx-gcu.c b/drivers/video/pxa3xx-gcu.c index b81168df253d..cf4beb9dc9bb 100644 --- a/drivers/video/pxa3xx-gcu.c +++ b/drivers/video/pxa3xx-gcu.c @@ -1,5 +1,5 @@ /* - * pxa3xx-gc.c - Linux kernel module for PXA3xx graphics controllers + * pxa3xx-gcu.c - Linux kernel module for PXA3xx graphics controllers * * This driver needs a DirectFB counterpart in user space, communication * is handled via mmap()ed memory areas and an ioctl. @@ -421,7 +421,7 @@ pxa3xx_gcu_misc_write(struct file *filp, const char *buff, buffer->next = priv->free; priv->free = buffer; spin_unlock_irqrestore(&priv->spinlock, flags); - return ret; + return -EFAULT; } buffer->length = words; diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index dce8c97b4333..75738a928610 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -22,7 +22,7 @@ #include <linux/svga.h> #include <linux/init.h> #include <linux/pci.h> -#include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */ +#include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */ #include <video/vga.h> #ifdef CONFIG_MTRR @@ -1113,12 +1113,12 @@ static int s3_pci_suspend(struct pci_dev* dev, pm_message_t state) dev_info(info->device, "suspend\n"); - acquire_console_sem(); + console_lock(); mutex_lock(&(par->open_lock)); if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) { mutex_unlock(&(par->open_lock)); - release_console_sem(); + console_unlock(); return 0; } @@ -1129,7 +1129,7 @@ static int s3_pci_suspend(struct pci_dev* dev, pm_message_t state) pci_set_power_state(dev, pci_choose_state(dev, state)); mutex_unlock(&(par->open_lock)); - release_console_sem(); + console_unlock(); return 0; } @@ -1145,12 +1145,12 @@ static int s3_pci_resume(struct pci_dev* dev) dev_info(info->device, "resume\n"); - acquire_console_sem(); + console_lock(); mutex_lock(&(par->open_lock)); if (par->ref_count == 0) { mutex_unlock(&(par->open_lock)); - release_console_sem(); + console_unlock(); return 0; } @@ -1159,7 +1159,7 @@ static int s3_pci_resume(struct pci_dev* dev) err = pci_enable_device(dev); if (err) { mutex_unlock(&(par->open_lock)); - release_console_sem(); + console_unlock(); dev_err(info->device, "error %d enabling device for resume\n", err); return err; } @@ -1169,7 +1169,7 @@ static int s3_pci_resume(struct pci_dev* dev) fb_set_suspend(info, 0); mutex_unlock(&(par->open_lock)); - release_console_sem(); + console_unlock(); return 0; } diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index 842d157e1025..487911e2926c 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c @@ -2373,7 +2373,7 @@ static int savagefb_suspend(struct pci_dev *dev, pm_message_t mesg) if (mesg.event == PM_EVENT_FREEZE) return 0; - acquire_console_sem(); + console_lock(); fb_set_suspend(info, 1); if (info->fbops->fb_sync) @@ -2385,7 +2385,7 @@ static int savagefb_suspend(struct pci_dev *dev, pm_message_t mesg) pci_save_state(dev); pci_disable_device(dev); pci_set_power_state(dev, pci_choose_state(dev, mesg)); - release_console_sem(); + console_unlock(); return 0; } @@ -2409,7 +2409,7 @@ static int savagefb_resume(struct pci_dev* dev) return 0; } - acquire_console_sem(); + console_lock(); pci_set_power_state(dev, PCI_D0); pci_restore_state(dev); @@ -2423,7 +2423,7 @@ static int savagefb_resume(struct pci_dev* dev) savagefb_set_par(info); fb_set_suspend(info, 0); savagefb_blank(FB_BLANK_UNBLANK, info); - release_console_sem(); + console_unlock(); return 0; } diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index 74d9f546a2e8..2b9e56a6bde4 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -1151,7 +1151,7 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) ch = info->par; - acquire_console_sem(); + console_lock(); /* HDMI plug in */ if (!sh_hdmi_must_reconfigure(hdmi) && @@ -1171,7 +1171,7 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) fb_set_suspend(info, 0); } - release_console_sem(); + console_unlock(); } else { ret = 0; if (!hdmi->info) @@ -1181,12 +1181,12 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) fb_destroy_modedb(hdmi->monspec.modedb); hdmi->monspec.modedb = NULL; - acquire_console_sem(); + console_lock(); /* HDMI disconnect */ fb_set_suspend(hdmi->info, 1); - release_console_sem(); + console_unlock(); pm_runtime_put(hdmi->dev); } diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index bd4840a8a6b7..bf12e53aed5c 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -912,9 +912,9 @@ static int sh_mobile_release(struct fb_info *info, int user) /* Nothing to reconfigure, when called from fbcon */ if (user) { - acquire_console_sem(); + console_lock(); sh_mobile_fb_reconfig(info); - release_console_sem(); + console_unlock(); } mutex_unlock(&ch->open_lock); diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index b7dc1800efa9..bcb44a594ebc 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -2010,9 +2010,9 @@ static int sm501fb_suspend_fb(struct sm501fb_info *info, /* tell console/fb driver we are suspending */ - acquire_console_sem(); + console_lock(); fb_set_suspend(fbi, 1); - release_console_sem(); + console_unlock(); /* backup copies in case chip is powered down over suspend */ @@ -2069,9 +2069,9 @@ static void sm501fb_resume_fb(struct sm501fb_info *info, memcpy_toio(par->cursor.k_addr, par->store_cursor, par->cursor.size); - acquire_console_sem(); + console_lock(); fb_set_suspend(fbi, 0); - release_console_sem(); + console_unlock(); vfree(par->store_fb); vfree(par->store_cursor); diff --git a/drivers/video/tmiofb.c b/drivers/video/tmiofb.c index 6913fe168c25..dfef88c803d4 100644 --- a/drivers/video/tmiofb.c +++ b/drivers/video/tmiofb.c @@ -25,7 +25,7 @@ #include <linux/fb.h> #include <linux/interrupt.h> #include <linux/delay.h> -/* Why should fb driver call console functions? because acquire_console_sem() */ +/* Why should fb driver call console functions? because console_lock() */ #include <linux/console.h> #include <linux/mfd/core.h> #include <linux/mfd/tmio.h> @@ -944,7 +944,7 @@ static int tmiofb_suspend(struct platform_device *dev, pm_message_t state) struct mfd_cell *cell = dev->dev.platform_data; int retval = 0; - acquire_console_sem(); + console_lock(); fb_set_suspend(info, 1); @@ -965,7 +965,7 @@ static int tmiofb_suspend(struct platform_device *dev, pm_message_t state) if (cell->suspend) retval = cell->suspend(dev); - release_console_sem(); + console_unlock(); return retval; } @@ -976,7 +976,7 @@ static int tmiofb_resume(struct platform_device *dev) struct mfd_cell *cell = dev->dev.platform_data; int retval = 0; - acquire_console_sem(); + console_lock(); if (cell->resume) { retval = cell->resume(dev); @@ -992,7 +992,7 @@ static int tmiofb_resume(struct platform_device *dev) fb_set_suspend(info, 0); out: - release_console_sem(); + console_unlock(); return retval; } #else diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 289edd519527..4e66349e4366 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -1674,17 +1674,17 @@ static int parse_mode(const char *str, u32 *xres, u32 *yres) #ifdef CONFIG_PM static int viafb_suspend(void *unused) { - acquire_console_sem(); + console_lock(); fb_set_suspend(viafbinfo, 1); viafb_sync(viafbinfo); - release_console_sem(); + console_unlock(); return 0; } static int viafb_resume(void *unused) { - acquire_console_sem(); + console_lock(); if (viaparinfo->shared->vdev->engine_mmio) viafb_reset_engine(viaparinfo); viafb_set_par(viafbinfo); @@ -1692,7 +1692,7 @@ static int viafb_resume(void *unused) viafb_set_par(viafbinfo1); fb_set_suspend(viafbinfo, 0); - release_console_sem(); + console_unlock(); return 0; } diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index 85d76ec4c63e..a2965ab92cfb 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -23,7 +23,7 @@ #include <linux/svga.h> #include <linux/init.h> #include <linux/pci.h> -#include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */ +#include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */ #include <video/vga.h> #ifdef CONFIG_MTRR @@ -819,12 +819,12 @@ static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state) dev_info(info->device, "suspend\n"); - acquire_console_sem(); + console_lock(); mutex_lock(&(par->open_lock)); if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) { mutex_unlock(&(par->open_lock)); - release_console_sem(); + console_unlock(); return 0; } @@ -835,7 +835,7 @@ static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state) pci_set_power_state(dev, pci_choose_state(dev, state)); mutex_unlock(&(par->open_lock)); - release_console_sem(); + console_unlock(); return 0; } @@ -850,7 +850,7 @@ static int vt8623_pci_resume(struct pci_dev* dev) dev_info(info->device, "resume\n"); - acquire_console_sem(); + console_lock(); mutex_lock(&(par->open_lock)); if (par->ref_count == 0) @@ -869,7 +869,7 @@ static int vt8623_pci_resume(struct pci_dev* dev) fail: mutex_unlock(&(par->open_lock)); - release_console_sem(); + console_unlock(); return 0; } diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c index 3e6934d4bea8..a20218c2fda8 100644 --- a/drivers/video/xen-fbfront.c +++ b/drivers/video/xen-fbfront.c @@ -491,12 +491,12 @@ xenfb_make_preferred_console(void) if (console_set_on_cmdline) return; - acquire_console_sem(); + console_lock(); for_each_console(c) { if (!strcmp(c->name, "tty") && c->index == 0) break; } - release_console_sem(); + console_unlock(); if (c) { unregister_console(c); c->flags |= CON_CONSDEV; diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c index 3a7e9ff8a746..38e96ab90945 100644 --- a/drivers/w1/masters/omap_hdq.c +++ b/drivers/w1/masters/omap_hdq.c @@ -593,19 +593,17 @@ static int __devinit omap_hdq_probe(struct platform_device *pdev) /* get interface & functional clock objects */ hdq_data->hdq_ick = clk_get(&pdev->dev, "ick"); - hdq_data->hdq_fck = clk_get(&pdev->dev, "fck"); + if (IS_ERR(hdq_data->hdq_ick)) { + dev_dbg(&pdev->dev, "Can't get HDQ ick clock object\n"); + ret = PTR_ERR(hdq_data->hdq_ick); + goto err_ick; + } - if (IS_ERR(hdq_data->hdq_ick) || IS_ERR(hdq_data->hdq_fck)) { - dev_dbg(&pdev->dev, "Can't get HDQ clock objects\n"); - if (IS_ERR(hdq_data->hdq_ick)) { - ret = PTR_ERR(hdq_data->hdq_ick); - goto err_clk; - } - if (IS_ERR(hdq_data->hdq_fck)) { - ret = PTR_ERR(hdq_data->hdq_fck); - clk_put(hdq_data->hdq_ick); - goto err_clk; - } + hdq_data->hdq_fck = clk_get(&pdev->dev, "fck"); + if (IS_ERR(hdq_data->hdq_fck)) { + dev_dbg(&pdev->dev, "Can't get HDQ fck clock object\n"); + ret = PTR_ERR(hdq_data->hdq_fck); + goto err_fck; } hdq_data->hdq_usecount = 0; @@ -665,10 +663,12 @@ err_fnclk: clk_disable(hdq_data->hdq_ick); err_intfclk: - clk_put(hdq_data->hdq_ick); clk_put(hdq_data->hdq_fck); -err_clk: +err_fck: + clk_put(hdq_data->hdq_ick); + +err_ick: iounmap(hdq_data->hdq_base); err_ioremap: diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 2e2400e7322e..31649b7b672f 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -862,12 +862,12 @@ config SBC_EPX_C3_WATCHDOG # M68K Architecture -config M548x_WATCHDOG - tristate "MCF548x watchdog support" +config M54xx_WATCHDOG + tristate "MCF54xx watchdog support" depends on M548x help To compile this driver as a module, choose M here: the - module will be called m548x_wdt. + module will be called m54xx_wdt. # MIPS Architecture diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index dd776651917c..20e44c4782b3 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -106,7 +106,7 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o # M32R Architecture # M68K Architecture -obj-$(CONFIG_M548x_WATCHDOG) += m548x_wdt.o +obj-$(CONFIG_M54xx_WATCHDOG) += m54xx_wdt.o # MIPS Architecture obj-$(CONFIG_ATH79_WDT) += ath79_wdt.o diff --git a/drivers/watchdog/m548x_wdt.c b/drivers/watchdog/m54xx_wdt.c index cabbcfe1c847..4d43286074aa 100644 --- a/drivers/watchdog/m548x_wdt.c +++ b/drivers/watchdog/m54xx_wdt.c @@ -1,7 +1,7 @@ /* - * drivers/watchdog/m548x_wdt.c + * drivers/watchdog/m54xx_wdt.c * - * Watchdog driver for ColdFire MCF548x processors + * Watchdog driver for ColdFire MCF547x & MCF548x processors * Copyright 2010 (c) Philippe De Muyter <phdm@macqel.be> * * Adapted from the IXP4xx watchdog driver, which carries these notices: @@ -29,8 +29,8 @@ #include <linux/uaccess.h> #include <asm/coldfire.h> -#include <asm/m548xsim.h> -#include <asm/m548xgpt.h> +#include <asm/m54xxsim.h> +#include <asm/m54xxgpt.h> static int nowayout = WATCHDOG_NOWAYOUT; static unsigned int heartbeat = 30; /* (secs) Default is 0.5 minute */ @@ -76,7 +76,7 @@ static void wdt_keepalive(void) __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0); } -static int m548x_wdt_open(struct inode *inode, struct file *file) +static int m54xx_wdt_open(struct inode *inode, struct file *file) { if (test_and_set_bit(WDT_IN_USE, &wdt_status)) return -EBUSY; @@ -86,7 +86,7 @@ static int m548x_wdt_open(struct inode *inode, struct file *file) return nonseekable_open(inode, file); } -static ssize_t m548x_wdt_write(struct file *file, const char *data, +static ssize_t m54xx_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) { if (len) { @@ -112,10 +112,10 @@ static ssize_t m548x_wdt_write(struct file *file, const char *data, static const struct watchdog_info ident = { .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, - .identity = "Coldfire M548x Watchdog", + .identity = "Coldfire M54xx Watchdog", }; -static long m548x_wdt_ioctl(struct file *file, unsigned int cmd, +static long m54xx_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = -ENOTTY; @@ -161,7 +161,7 @@ static long m548x_wdt_ioctl(struct file *file, unsigned int cmd, return ret; } -static int m548x_wdt_release(struct inode *inode, struct file *file) +static int m54xx_wdt_release(struct inode *inode, struct file *file) { if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) wdt_disable(); @@ -177,45 +177,45 @@ static int m548x_wdt_release(struct inode *inode, struct file *file) } -static const struct file_operations m548x_wdt_fops = { +static const struct file_operations m54xx_wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, - .write = m548x_wdt_write, - .unlocked_ioctl = m548x_wdt_ioctl, - .open = m548x_wdt_open, - .release = m548x_wdt_release, + .write = m54xx_wdt_write, + .unlocked_ioctl = m54xx_wdt_ioctl, + .open = m54xx_wdt_open, + .release = m54xx_wdt_release, }; -static struct miscdevice m548x_wdt_miscdev = { +static struct miscdevice m54xx_wdt_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", - .fops = &m548x_wdt_fops, + .fops = &m54xx_wdt_fops, }; -static int __init m548x_wdt_init(void) +static int __init m54xx_wdt_init(void) { if (!request_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4, - "Coldfire M548x Watchdog")) { + "Coldfire M54xx Watchdog")) { printk(KERN_WARNING - "Coldfire M548x Watchdog : I/O region busy\n"); + "Coldfire M54xx Watchdog : I/O region busy\n"); return -EBUSY; } printk(KERN_INFO "ColdFire watchdog driver is loaded.\n"); - return misc_register(&m548x_wdt_miscdev); + return misc_register(&m54xx_wdt_miscdev); } -static void __exit m548x_wdt_exit(void) +static void __exit m54xx_wdt_exit(void) { - misc_deregister(&m548x_wdt_miscdev); + misc_deregister(&m54xx_wdt_miscdev); release_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4); } -module_init(m548x_wdt_init); -module_exit(m548x_wdt_exit); +module_init(m54xx_wdt_init); +module_exit(m54xx_wdt_exit); MODULE_AUTHOR("Philippe De Muyter <phdm@macqel.be>"); -MODULE_DESCRIPTION("Coldfire M548x Watchdog"); +MODULE_DESCRIPTION("Coldfire M54xx Watchdog"); module_param(heartbeat, int, 0); MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 30s)"); diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index db8c4c4ac880..24177272bcb8 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -37,11 +37,19 @@ static enum shutdown_state shutting_down = SHUTDOWN_INVALID; #ifdef CONFIG_PM_SLEEP static int xen_hvm_suspend(void *data) { + int err; struct sched_shutdown r = { .reason = SHUTDOWN_suspend }; int *cancelled = data; BUG_ON(!irqs_disabled()); + err = sysdev_suspend(PMSG_SUSPEND); + if (err) { + printk(KERN_ERR "xen_hvm_suspend: sysdev_suspend failed: %d\n", + err); + return err; + } + *cancelled = HYPERVISOR_sched_op(SCHEDOP_shutdown, &r); xen_hvm_post_suspend(*cancelled); @@ -53,6 +61,8 @@ static int xen_hvm_suspend(void *data) xen_timer_resume(); } + sysdev_resume(); + return 0; } |