From 85bcc13072c54592596c5b41d40d1c6a18b04e19 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 8 May 2005 19:35:27 +0100 Subject: [PATCH] MMC: wbsd update Updates to the wbsd driver. * Fix to handle DAT3 card detection. * Fixed bug which could cause large writes to stall in FIFO mode. * Plug 'n Play support. In most cases you need ACPI PNP for this to work. * Uses generic DMA API (ISA dependency removed). --- drivers/mmc/Kconfig | 2 +- drivers/mmc/wbsd.c | 716 ++++++++++++++++++++++++++++++++++++++-------------- drivers/mmc/wbsd.h | 12 + 3 files changed, 544 insertions(+), 186 deletions(-) diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 2e70d74fbde..4991bbd054f 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -51,7 +51,7 @@ config MMC_PXA config MMC_WBSD tristate "Winbond W83L51xD SD/MMC Card Interface support" - depends on MMC && ISA && ISA_DMA_API + depends on MMC && ISA_DMA_API help This selects the Winbond(R) W83L51xD Secure digital and Multimedia card Interface. diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 39747526c71..b7fbd30b49a 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -28,7 +28,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -40,7 +42,7 @@ #include "wbsd.h" #define DRIVER_NAME "wbsd" -#define DRIVER_VERSION "1.1" +#define DRIVER_VERSION "1.2" #ifdef CONFIG_MMC_DEBUG #define DBG(x...) \ @@ -52,10 +54,6 @@ #define DBGF(x...) do { } while (0) #endif -static unsigned int io = 0x248; -static unsigned int irq = 6; -static int dma = 2; - #ifdef CONFIG_MMC_DEBUG void DBG_REG(int reg, u8 value) { @@ -78,29 +76,62 @@ void DBG_REG(int reg, u8 value) #define DBG_REG(r, v) do {} while (0) #endif +/* + * Device resources + */ + +#ifdef CONFIG_PNP + +static const struct pnp_device_id pnp_dev_table[] = { + { "WEC0517", 0 }, + { "WEC0518", 0 }, + { "", 0 }, +}; + +MODULE_DEVICE_TABLE(pnp, pnp_dev_table); + +#endif /* CONFIG_PNP */ + +#ifdef CONFIG_PNP +static unsigned int nopnp = 0; +#else +static const unsigned int nopnp = 1; +#endif +static unsigned int io = 0x248; +static unsigned int irq = 6; +static int dma = 2; + /* * Basic functions */ static inline void wbsd_unlock_config(struct wbsd_host* host) { + BUG_ON(host->config == 0); + outb(host->unlock_code, host->config); outb(host->unlock_code, host->config); } static inline void wbsd_lock_config(struct wbsd_host* host) { + BUG_ON(host->config == 0); + outb(LOCK_CODE, host->config); } static inline void wbsd_write_config(struct wbsd_host* host, u8 reg, u8 value) { + BUG_ON(host->config == 0); + outb(reg, host->config); outb(value, host->config + 1); } static inline u8 wbsd_read_config(struct wbsd_host* host, u8 reg) { + BUG_ON(host->config == 0); + outb(reg, host->config); return inb(host->config + 1); } @@ -132,6 +163,13 @@ static void wbsd_init_device(struct wbsd_host* host) setup |= WBSD_FIFO_RESET | WBSD_SOFT_RESET; wbsd_write_index(host, WBSD_IDX_SETUP, setup); + /* + * Set DAT3 to input + */ + setup &= ~WBSD_DAT3_H; + wbsd_write_index(host, WBSD_IDX_SETUP, setup); + host->flags &= ~WBSD_FIGNORE_DETECT; + /* * Read back default clock. */ @@ -147,6 +185,14 @@ static void wbsd_init_device(struct wbsd_host* host) */ wbsd_write_index(host, WBSD_IDX_TAAC, 0x7F); + /* + * Test for card presence + */ + if (inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT) + host->flags |= WBSD_FCARD_PRESENT; + else + host->flags &= ~WBSD_FCARD_PRESENT; + /* * Enable interesting interrupts. */ @@ -407,8 +453,6 @@ static inline void wbsd_get_long_reply(struct wbsd_host* host, } } -static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs); - static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd) { int i; @@ -646,6 +690,13 @@ static void wbsd_fill_fifo(struct wbsd_host* host) } wbsd_kunmap_sg(host); + + /* + * The controller stops sending interrupts for + * 'FIFO empty' under certain conditions. So we + * need to be a bit more pro-active. + */ + tasklet_schedule(&host->fifo_tasklet); } static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) @@ -850,9 +901,11 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data) wbsd_request_end(host, host->mrq); } -/* - * MMC Callbacks - */ +/*****************************************************************************\ + * * + * MMC layer callbacks * + * * +\*****************************************************************************/ static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq) { @@ -874,7 +927,7 @@ static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq) * If there is no card in the slot then * timeout immediatly. */ - if (!(inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT)) + if (!(host->flags & WBSD_FCARD_PRESENT)) { cmd->error = MMC_ERR_TIMEOUT; goto done; @@ -953,33 +1006,50 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) host->clk = clk; } + /* + * Power up card. + */ if (ios->power_mode != MMC_POWER_OFF) { - /* - * Power up card. - */ pwr = inb(host->base + WBSD_CSR); pwr &= ~WBSD_POWER_N; outb(pwr, host->base + WBSD_CSR); - - /* - * This behaviour is stolen from the - * Windows driver. Don't know why, but - * it is needed. - */ - setup = wbsd_read_index(host, WBSD_IDX_SETUP); - if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) - setup |= WBSD_DAT3_H; - else - setup &= ~WBSD_DAT3_H; - wbsd_write_index(host, WBSD_IDX_SETUP, setup); - - mdelay(1); } + /* + * MMC cards need to have pin 1 high during init. + * Init time corresponds rather nicely with the bus mode. + * It wreaks havoc with the card detection though so + * that needs to be disabed. + */ + setup = wbsd_read_index(host, WBSD_IDX_SETUP); + if ((ios->power_mode == MMC_POWER_ON) && + (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)) + { + setup |= WBSD_DAT3_H; + host->flags |= WBSD_FIGNORE_DETECT; + } + else + { + setup &= ~WBSD_DAT3_H; + host->flags &= ~WBSD_FIGNORE_DETECT; + } + wbsd_write_index(host, WBSD_IDX_SETUP, setup); + spin_unlock_bh(&host->lock); } +static struct mmc_host_ops wbsd_ops = { + .request = wbsd_request, + .set_ios = wbsd_set_ios, +}; + +/*****************************************************************************\ + * * + * Interrupt handling * + * * +\*****************************************************************************/ + /* * Tasklets */ @@ -1005,17 +1075,33 @@ static void wbsd_tasklet_card(unsigned long param) { struct wbsd_host* host = (struct wbsd_host*)param; u8 csr; + int change = 0; spin_lock(&host->lock); + if (host->flags & WBSD_FIGNORE_DETECT) + { + spin_unlock(&host->lock); + return; + } + csr = inb(host->base + WBSD_CSR); WARN_ON(csr == 0xff); if (csr & WBSD_CARDPRESENT) - DBG("Card inserted\n"); - else + { + if (!(host->flags & WBSD_FCARD_PRESENT)) + { + DBG("Card inserted\n"); + host->flags |= WBSD_FCARD_PRESENT; + change = 1; + } + } + else if (host->flags & WBSD_FCARD_PRESENT) { DBG("Card removed\n"); + host->flags &= ~WBSD_FCARD_PRESENT; + change = 1; if (host->mrq) { @@ -1033,7 +1119,8 @@ static void wbsd_tasklet_card(unsigned long param) */ spin_unlock(&host->lock); - mmc_detect_change(host->mmc); + if (change) + mmc_detect_change(host->mmc); } static void wbsd_tasklet_fifo(unsigned long param) @@ -1200,11 +1287,85 @@ static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } +/*****************************************************************************\ + * * + * Device initialisation and shutdown * + * * +\*****************************************************************************/ + /* - * Support functions for probe + * Allocate/free MMC structure. */ -static int wbsd_scan(struct wbsd_host* host) +static int __devinit wbsd_alloc_mmc(struct device* dev) +{ + struct mmc_host* mmc; + struct wbsd_host* host; + + /* + * Allocate MMC structure. + */ + mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev); + if (!mmc) + return -ENOMEM; + + host = mmc_priv(mmc); + host->mmc = mmc; + + host->dma = -1; + + /* + * Set host parameters. + */ + mmc->ops = &wbsd_ops; + mmc->f_min = 375000; + mmc->f_max = 24000000; + mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; + + spin_lock_init(&host->lock); + + /* + * Maximum number of segments. Worst case is one sector per segment + * so this will be 64kB/512. + */ + mmc->max_hw_segs = 128; + mmc->max_phys_segs = 128; + + /* + * Maximum number of sectors in one transfer. Also limited by 64kB + * buffer. + */ + mmc->max_sectors = 128; + + /* + * Maximum segment size. Could be one segment with the maximum number + * of segments. + */ + mmc->max_seg_size = mmc->max_sectors * 512; + + dev_set_drvdata(dev, mmc); + + return 0; +} + +static void __devexit wbsd_free_mmc(struct device* dev) +{ + struct mmc_host* mmc; + + mmc = dev_get_drvdata(dev); + if (!mmc) + return; + + mmc_free_host(mmc); + + dev_set_drvdata(dev, NULL); +} + +/* + * Scan for known chip id:s + */ + +static int __devinit wbsd_scan(struct wbsd_host* host) { int i, j, k; int id; @@ -1258,12 +1419,16 @@ static int wbsd_scan(struct wbsd_host* host) return -ENODEV; } -static int wbsd_request_regions(struct wbsd_host* host) +/* + * Allocate/free io port ranges + */ + +static int __devinit wbsd_request_region(struct wbsd_host* host, int base) { if (io & 0x7) return -EINVAL; - if (!request_region(io, 8, DRIVER_NAME)) + if (!request_region(base, 8, DRIVER_NAME)) return -EIO; host->base = io; @@ -1271,19 +1436,25 @@ static int wbsd_request_regions(struct wbsd_host* host) return 0; } -static void wbsd_release_regions(struct wbsd_host* host) +static void __devexit wbsd_release_regions(struct wbsd_host* host) { if (host->base) release_region(host->base, 8); + + host->base = 0; if (host->config) release_region(host->config, 2); + + host->config = 0; } -static void wbsd_init_dma(struct wbsd_host* host) +/* + * Allocate/free DMA port and buffer + */ + +static void __devinit wbsd_request_dma(struct wbsd_host* host, int dma) { - host->dma = -1; - if (dma < 0) return; @@ -1294,7 +1465,7 @@ static void wbsd_init_dma(struct wbsd_host* host) * We need to allocate a special buffer in * order for ISA to be able to DMA to it. */ - host->dma_buffer = kmalloc(65536, + host->dma_buffer = kmalloc(WBSD_DMA_SIZE, GFP_NOIO | GFP_DMA | __GFP_REPEAT | __GFP_NOWARN); if (!host->dma_buffer) goto free; @@ -1302,7 +1473,8 @@ static void wbsd_init_dma(struct wbsd_host* host) /* * Translate the address to a physical address. */ - host->dma_addr = isa_virt_to_bus(host->dma_buffer); + host->dma_addr = dma_map_single(host->mmc->dev, host->dma_buffer, + WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); /* * ISA DMA must be aligned on a 64k basis. @@ -1325,6 +1497,10 @@ kfree: */ BUG_ON(1); + dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE, + DMA_BIDIRECTIONAL); + host->dma_addr = (dma_addr_t)NULL; + kfree(host->dma_buffer); host->dma_buffer = NULL; @@ -1336,60 +1512,122 @@ err: "Falling back on FIFO.\n", dma); } -static struct mmc_host_ops wbsd_ops = { - .request = wbsd_request, - .set_ios = wbsd_set_ios, -}; +static void __devexit wbsd_release_dma(struct wbsd_host* host) +{ + if (host->dma_addr) + dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE, + DMA_BIDIRECTIONAL); + if (host->dma_buffer) + kfree(host->dma_buffer); + if (host->dma >= 0) + free_dma(host->dma); + + host->dma = -1; + host->dma_buffer = NULL; + host->dma_addr = (dma_addr_t)NULL; +} /* - * Device probe + * Allocate/free IRQ. */ -static int wbsd_probe(struct device* dev) +static int __devinit wbsd_request_irq(struct wbsd_host* host, int irq) { - struct wbsd_host* host = NULL; - struct mmc_host* mmc = NULL; int ret; /* - * Allocate MMC structure. + * Allocate interrupt. */ - mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev); - if (!mmc) - return -ENOMEM; - - host = mmc_priv(mmc); - host->mmc = mmc; + + ret = request_irq(irq, wbsd_irq, SA_SHIRQ, DRIVER_NAME, host); + if (ret) + return ret; + host->irq = irq; + /* - * Scan for hardware. + * Set up tasklets. */ - ret = wbsd_scan(host); - if (ret) - goto freemmc; + tasklet_init(&host->card_tasklet, wbsd_tasklet_card, (unsigned long)host); + tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo, (unsigned long)host); + tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc, (unsigned long)host); + tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, (unsigned long)host); + tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, (unsigned long)host); + tasklet_init(&host->block_tasklet, wbsd_tasklet_block, (unsigned long)host); + + return 0; +} - /* - * Reset the chip. - */ - wbsd_write_config(host, WBSD_CONF_SWRST, 1); - wbsd_write_config(host, WBSD_CONF_SWRST, 0); +static void __devexit wbsd_release_irq(struct wbsd_host* host) +{ + if (!host->irq) + return; + free_irq(host->irq, host); + + host->irq = 0; + + tasklet_kill(&host->card_tasklet); + tasklet_kill(&host->fifo_tasklet); + tasklet_kill(&host->crc_tasklet); + tasklet_kill(&host->timeout_tasklet); + tasklet_kill(&host->finish_tasklet); + tasklet_kill(&host->block_tasklet); +} + +/* + * Allocate all resources for the host. + */ + +static int __devinit wbsd_request_resources(struct wbsd_host* host, + int base, int irq, int dma) +{ + int ret; + /* * Allocate I/O ports. */ - ret = wbsd_request_regions(host); + ret = wbsd_request_region(host, base); if (ret) - goto release; + return ret; /* - * Set host parameters. + * Allocate interrupt. */ - mmc->ops = &wbsd_ops; - mmc->f_min = 375000; - mmc->f_max = 24000000; - mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; + ret = wbsd_request_irq(host, irq); + if (ret) + return ret; + + /* + * Allocate DMA. + */ + wbsd_request_dma(host, dma); - spin_lock_init(&host->lock); + return 0; +} + +/* + * Release all resources for the host. + */ + +static void __devexit wbsd_release_resources(struct wbsd_host* host) +{ + wbsd_release_dma(host); + wbsd_release_irq(host); + wbsd_release_regions(host); +} + +/* + * Configure the resources the chip should use. + */ + +static void __devinit wbsd_chip_config(struct wbsd_host* host) +{ + /* + * Reset the chip. + */ + wbsd_write_config(host, WBSD_CONF_SWRST, 1); + wbsd_write_config(host, WBSD_CONF_SWRST, 0); /* * Select SD/MMC function. @@ -1399,165 +1637,241 @@ static int wbsd_probe(struct device* dev) /* * Set up card detection. */ - wbsd_write_config(host, WBSD_CONF_PINS, 0x02); + wbsd_write_config(host, WBSD_CONF_PINS, WBSD_PINS_DETECT_GP11); /* - * Configure I/O port. + * Configure chip */ wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8); wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff); - - /* - * Allocate interrupt. - */ - ret = request_irq(irq, wbsd_irq, SA_SHIRQ, DRIVER_NAME, host); - if (ret) - goto release; - host->irq = irq; + wbsd_write_config(host, WBSD_CONF_IRQ, host->irq); - /* - * Set up tasklets. - */ - tasklet_init(&host->card_tasklet, wbsd_tasklet_card, (unsigned long)host); - tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo, (unsigned long)host); - tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc, (unsigned long)host); - tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, (unsigned long)host); - tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, (unsigned long)host); - tasklet_init(&host->block_tasklet, wbsd_tasklet_block, (unsigned long)host); + if (host->dma >= 0) + wbsd_write_config(host, WBSD_CONF_DRQ, host->dma); /* - * Configure interrupt. + * Enable and power up chip. */ - wbsd_write_config(host, WBSD_CONF_IRQ, host->irq); + wbsd_write_config(host, WBSD_CONF_ENABLE, 1); + wbsd_write_config(host, WBSD_CONF_POWER, 0x20); +} + +/* + * Check that configured resources are correct. + */ + +static int __devinit wbsd_chip_validate(struct wbsd_host* host) +{ + int base, irq, dma; /* - * Allocate DMA. + * Select SD/MMC function. */ - wbsd_init_dma(host); + wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); /* - * If all went well, then configure DMA. + * Read configuration. */ - if (host->dma >= 0) - wbsd_write_config(host, WBSD_CONF_DRQ, host->dma); + base = wbsd_read_config(host, WBSD_CONF_PORT_HI) << 8; + base |= wbsd_read_config(host, WBSD_CONF_PORT_LO); - /* - * Maximum number of segments. Worst case is one sector per segment - * so this will be 64kB/512. - */ - mmc->max_hw_segs = 128; - mmc->max_phys_segs = 128; + irq = wbsd_read_config(host, WBSD_CONF_IRQ); + + dma = wbsd_read_config(host, WBSD_CONF_DRQ); /* - * Maximum number of sectors in one transfer. Also limited by 64kB - * buffer. + * Validate against given configuration. */ - mmc->max_sectors = 128; + if (base != host->base) + return 0; + if (irq != host->irq) + return 0; + if ((dma != host->dma) && (host->dma != -1)) + return 0; + + return 1; +} + +/*****************************************************************************\ + * * + * Devices setup and shutdown * + * * +\*****************************************************************************/ + +static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma, + int pnp) +{ + struct wbsd_host* host = NULL; + struct mmc_host* mmc = NULL; + int ret; + + ret = wbsd_alloc_mmc(dev); + if (ret) + return ret; + + mmc = dev_get_drvdata(dev); + host = mmc_priv(mmc); /* - * Maximum segment size. Could be one segment with the maximum number - * of segments. + * Scan for hardware. */ - mmc->max_seg_size = mmc->max_sectors * 512; + ret = wbsd_scan(host); + if (ret) + { + if (pnp && (ret == -ENODEV)) + { + printk(KERN_WARNING DRIVER_NAME + ": Unable to confirm device presence. You may " + "experience lock-ups.\n"); + } + else + { + wbsd_free_mmc(dev); + return ret; + } + } /* - * Enable chip. + * Request resources. */ - wbsd_write_config(host, WBSD_CONF_ENABLE, 1); + ret = wbsd_request_resources(host, io, irq, dma); + if (ret) + { + wbsd_release_resources(host); + wbsd_free_mmc(dev); + return ret; + } /* - * Power up chip. + * See if chip needs to be configured. */ - wbsd_write_config(host, WBSD_CONF_POWER, 0x20); + if (pnp && (host->config != 0)) + { + if (!wbsd_chip_validate(host)) + { + printk(KERN_WARNING DRIVER_NAME + ": PnP active but chip not configured! " + "You probably have a buggy BIOS. " + "Configuring chip manually.\n"); + wbsd_chip_config(host); + } + } + else + wbsd_chip_config(host); /* * Power Management stuff. No idea how this works. * Not tested. */ #ifdef CONFIG_PM - wbsd_write_config(host, WBSD_CONF_PME, 0xA0); + if (host->config) + wbsd_write_config(host, WBSD_CONF_PME, 0xA0); #endif + /* + * Allow device to initialise itself properly. + */ + mdelay(5); /* * Reset the chip into a known state. */ wbsd_init_device(host); - dev_set_drvdata(dev, mmc); - - /* - * Add host to MMC layer. - */ mmc_add_host(mmc); - printk(KERN_INFO "%s: W83L51xD id %x at 0x%x irq %d dma %d\n", - mmc->host_name, (int)host->chip_id, (int)host->base, - (int)host->irq, (int)host->dma); + printk(KERN_INFO "%s: W83L51xD", mmc->host_name); + if (host->chip_id != 0) + printk(" id %x", (int)host->chip_id); + printk(" at 0x%x irq %d", (int)host->base, (int)host->irq); + if (host->dma >= 0) + printk(" dma %d", (int)host->dma); + else + printk(" FIFO"); + if (pnp) + printk(" PnP"); + printk("\n"); return 0; - -release: - wbsd_release_regions(host); - -freemmc: - mmc_free_host(mmc); - - return ret; } -/* - * Device remove - */ - -static int wbsd_remove(struct device* dev) +static void __devexit wbsd_shutdown(struct device* dev, int pnp) { struct mmc_host* mmc = dev_get_drvdata(dev); struct wbsd_host* host; if (!mmc) - return 0; + return; host = mmc_priv(mmc); - /* - * Unregister host with MMC layer. - */ mmc_remove_host(mmc); - /* - * Power down the SD/MMC function. - */ - wbsd_unlock_config(host); - wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); - wbsd_write_config(host, WBSD_CONF_ENABLE, 0); - wbsd_lock_config(host); + if (!pnp) + { + /* + * Power down the SD/MMC function. + */ + wbsd_unlock_config(host); + wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); + wbsd_write_config(host, WBSD_CONF_ENABLE, 0); + wbsd_lock_config(host); + } - /* - * Free resources. - */ - if (host->dma_buffer) - kfree(host->dma_buffer); + wbsd_release_resources(host); - if (host->dma >= 0) - free_dma(host->dma); + wbsd_free_mmc(dev); +} - free_irq(host->irq, host); +/* + * Non-PnP + */ + +static int __devinit wbsd_probe(struct device* dev) +{ + return wbsd_init(dev, io, irq, dma, 0); +} + +static int __devexit wbsd_remove(struct device* dev) +{ + wbsd_shutdown(dev, 0); + + return 0; +} + +/* + * PnP + */ + +#ifdef CONFIG_PNP + +static int __devinit +wbsd_pnp_probe(struct pnp_dev * pnpdev, const struct pnp_device_id *dev_id) +{ + int io, irq, dma; - tasklet_kill(&host->card_tasklet); - tasklet_kill(&host->fifo_tasklet); - tasklet_kill(&host->crc_tasklet); - tasklet_kill(&host->timeout_tasklet); - tasklet_kill(&host->finish_tasklet); - tasklet_kill(&host->block_tasklet); + /* + * Get resources from PnP layer. + */ + io = pnp_port_start(pnpdev, 0); + irq = pnp_irq(pnpdev, 0); + if (pnp_dma_valid(pnpdev, 0)) + dma = pnp_dma(pnpdev, 0); + else + dma = -1; - wbsd_release_regions(host); + DBGF("PnP resources: port %3x irq %d dma %d\n", io, irq, dma); - mmc_free_host(mmc); + return wbsd_init(&pnpdev->dev, io, irq, dma, 1); +} - return 0; +static void __devexit wbsd_pnp_remove(struct pnp_dev * dev) +{ + wbsd_shutdown(&dev->dev, 1); } +#endif /* CONFIG_PNP */ + /* * Power management */ @@ -1581,17 +1895,7 @@ static int wbsd_resume(struct device *dev, u32 level) #define wbsd_resume NULL #endif -static void wbsd_release(struct device *dev) -{ -} - -static struct platform_device wbsd_device = { - .name = DRIVER_NAME, - .id = -1, - .dev = { - .release = wbsd_release, - }, -}; +static struct platform_device *wbsd_device; static struct device_driver wbsd_driver = { .name = DRIVER_NAME, @@ -1603,6 +1907,17 @@ static struct device_driver wbsd_driver = { .resume = wbsd_resume, }; +#ifdef CONFIG_PNP + +static struct pnp_driver wbsd_pnp_driver = { + .name = DRIVER_NAME, + .id_table = pnp_dev_table, + .probe = wbsd_pnp_probe, + .remove = wbsd_pnp_remove, +}; + +#endif /* CONFIG_PNP */ + /* * Module loading/unloading */ @@ -1615,29 +1930,57 @@ static int __init wbsd_drv_init(void) ": Winbond W83L51xD SD/MMC card interface driver, " DRIVER_VERSION "\n"); printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); - - result = driver_register(&wbsd_driver); - if (result < 0) - return result; - result = platform_device_register(&wbsd_device); - if (result < 0) - return result; +#ifdef CONFIG_PNP + + if (!nopnp) + { + result = pnp_register_driver(&wbsd_pnp_driver); + if (result < 0) + return result; + } + +#endif /* CONFIG_PNP */ + + if (nopnp) + { + result = driver_register(&wbsd_driver); + if (result < 0) + return result; + + wbsd_device = platform_device_register_simple(DRIVER_NAME, -1, + NULL, 0); + if (IS_ERR(wbsd_device)) + return PTR_ERR(wbsd_device); + } return 0; } static void __exit wbsd_drv_exit(void) { - platform_device_unregister(&wbsd_device); +#ifdef CONFIG_PNP + + if (!nopnp) + pnp_unregister_driver(&wbsd_pnp_driver); - driver_unregister(&wbsd_driver); +#endif /* CONFIG_PNP */ + + if (nopnp) + { + platform_device_unregister(wbsd_device); + + driver_unregister(&wbsd_driver); + } DBG("unloaded\n"); } module_init(wbsd_drv_init); module_exit(wbsd_drv_exit); +#ifdef CONFIG_PNP +module_param(nopnp, uint, 0444); +#endif module_param(io, uint, 0444); module_param(irq, uint, 0444); module_param(dma, int, 0444); @@ -1646,6 +1989,9 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver"); MODULE_VERSION(DRIVER_VERSION); +#ifdef CONFIG_PNP +MODULE_PARM_DESC(nopnp, "Scan for device instead of relying on PNP. (default 0)"); +#endif MODULE_PARM_DESC(io, "I/O base to allocate. Must be 8 byte aligned. (default 0x248)"); MODULE_PARM_DESC(irq, "IRQ to allocate. (default 6)"); MODULE_PARM_DESC(dma, "DMA channel to allocate. -1 for no DMA. (default 2)"); diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h index fdc03b56a81..864f30828d0 100644 --- a/drivers/mmc/wbsd.h +++ b/drivers/mmc/wbsd.h @@ -35,6 +35,12 @@ const int valid_ids[] = { #define DEVICE_SD 0x03 +#define WBSD_PINS_DAT3_HI 0x20 +#define WBSD_PINS_DAT3_OUT 0x10 +#define WBSD_PINS_GP11_HI 0x04 +#define WBSD_PINS_DETECT_GP11 0x02 +#define WBSD_PINS_DETECT_DAT3 0x01 + #define WBSD_CMDR 0x00 #define WBSD_DFR 0x01 #define WBSD_EIR 0x02 @@ -133,6 +139,7 @@ const int valid_ids[] = { #define WBSD_CRC_OK 0x05 /* S010E (00101) */ #define WBSD_CRC_FAIL 0x0B /* S101E (01011) */ +#define WBSD_DMA_SIZE 65536 struct wbsd_host { @@ -140,6 +147,11 @@ struct wbsd_host spinlock_t lock; /* Mutex */ + int flags; /* Driver states */ + +#define WBSD_FCARD_PRESENT (1<<0) /* Card is present */ +#define WBSD_FIGNORE_DETECT (1<<1) /* Ignore card detection */ + struct mmc_request* mrq; /* Current request */ u8 isr; /* Accumulated ISR */ -- cgit v1.2.3 From 155bb14482cc567761c13b4efc064de400c55e18 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 9 May 2005 20:52:51 +0100 Subject: [PATCH] ARM: Add inline functions to find the pmd from virtual address Add pmd_off() and pmd_off_k() to obtain the pmd pointer for a virtual address, and use them throughout the mm initialisation. Signed-off-by: Russell King --- arch/arm/mm/mm-armv.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index 585dfb8e20b..2a514b05cd5 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -142,6 +142,16 @@ __setup("noalign", noalign_setup); #define FIRST_KERNEL_PGD_NR (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD) +static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt) +{ + return pmd_offset(pgd, virt); +} + +static inline pmd_t *pmd_off_k(unsigned long virt) +{ + return pmd_off(pgd_offset_k(virt), virt); +} + /* * need to get a 16k page for level 1 */ @@ -220,7 +230,7 @@ void free_pgd_slow(pgd_t *pgd) return; /* pgd is always present and good */ - pmd = (pmd_t *)pgd; + pmd = pmd_off(pgd, 0); if (pmd_none(*pmd)) goto free; if (pmd_bad(*pmd)) { @@ -246,9 +256,8 @@ free: static inline void alloc_init_section(unsigned long virt, unsigned long phys, int prot) { - pmd_t *pmdp; + pmd_t *pmdp = pmd_off_k(virt); - pmdp = pmd_offset(pgd_offset_k(virt), virt); if (virt & (1 << 20)) pmdp++; @@ -283,11 +292,9 @@ alloc_init_supersection(unsigned long virt, unsigned long phys, int prot) static inline void alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pgprot_t prot) { - pmd_t *pmdp; + pmd_t *pmdp = pmd_off_k(virt); pte_t *ptep; - pmdp = pmd_offset(pgd_offset_k(virt), virt); - if (pmd_none(*pmdp)) { unsigned long pmdval; ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * @@ -310,7 +317,7 @@ alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pg */ static inline void clear_mapping(unsigned long virt) { - pmd_clear(pmd_offset(pgd_offset_k(virt), virt)); + pmd_clear(pmd_off_k(virt)); } struct mem_types { @@ -578,7 +585,7 @@ void setup_mm_for_reboot(char mode) PMD_TYPE_SECT; if (cpu_arch <= CPU_ARCH_ARMv5) pmdval |= PMD_BIT4; - pmd = pmd_offset(pgd + i, i << PGDIR_SHIFT); + pmd = pmd_off(pgd, i << PGDIR_SHIFT); pmd[0] = __pmd(pmdval); pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1))); flush_pmd_entry(pmd); -- cgit v1.2.3 From 05ab3014636ff60a319d37cdf37dca594b015eec Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 9 May 2005 23:21:59 +0100 Subject: [PATCH] Serial: Add uart_insert_char() Add uart_insert_char(), which handles inserting characters into the flip buffer. This helper function handles the correct semantics for handling overrun in addition to inserting normal characters. Signed-off-by: Russell King --- drivers/serial/21285.c | 14 ++------------ drivers/serial/8250.c | 15 +++------------ drivers/serial/amba-pl010.c | 14 ++------------ drivers/serial/amba-pl011.c | 14 ++------------ drivers/serial/clps711x.c | 5 +---- drivers/serial/pxa.c | 16 ++++------------ drivers/serial/s3c2410.c | 15 +-------------- drivers/serial/sa1100.c | 5 +---- drivers/serial/serial_lh7a40x.c | 13 +------------ drivers/serial/serial_txx9.c | 15 +++------------ drivers/serial/vr41xx_siu.c | 6 ++---- include/linux/serial_core.h | 19 +++++++++++++++++++ 12 files changed, 41 insertions(+), 110 deletions(-) diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c index 33fbda79f35..0b10169961e 100644 --- a/drivers/serial/21285.c +++ b/drivers/serial/21285.c @@ -126,18 +126,8 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *r flag = TTY_FRAME; } - if ((rxs & port->ignore_status_mask) == 0) { - tty_insert_flip_char(tty, ch, flag); - } - if ((rxs & RXSTAT_OVERRUN) && - tty->flip.count < TTY_FLIPBUF_SIZE) { - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character. - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } + uart_insert_char(port, rxs, RXSTAT_OVERRUN, ch, flag); + status = *CSR_UARTFLG; } tty_flip_buffer_push(tty); diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 0d9358608fd..3bbf0cc6e53 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1122,18 +1122,9 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) } if (uart_handle_sysrq_char(&up->port, ch, regs)) goto ignore_char; - if ((lsr & up->port.ignore_status_mask) == 0) { - tty_insert_flip_char(tty, ch, flag); - } - if ((lsr & UART_LSR_OE) && - tty->flip.count < TTY_FLIPBUF_SIZE) { - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character. - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } + + uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); + ignore_char: lsr = serial_inp(up, UART_LSR); } while ((lsr & UART_LSR_DR) && (max_count-- > 0)); diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index f2a5e2933c4..2884b310e54 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c @@ -198,18 +198,8 @@ pl010_rx_chars(struct uart_port *port) if (uart_handle_sysrq_char(port, ch, regs)) goto ignore_char; - if ((rsr & port->ignore_status_mask) == 0) { - tty_insert_flip_char(tty, ch, flag); - } - if ((rsr & UART01x_RSR_OE) && - tty->flip.count < TTY_FLIPBUF_SIZE) { - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } + uart_insert_char(port, rsr, UART01x_RSR_OE, ch, flag); + ignore_char: status = UART_GET_FR(port); } diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index d5cbef3fe8b..7db88ee18f7 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -163,18 +163,8 @@ pl011_rx_chars(struct uart_amba_port *uap) if (uart_handle_sysrq_char(&uap->port, ch, regs)) goto ignore_char; - if ((rsr & uap->port.ignore_status_mask) == 0) { - tty_insert_flip_char(tty, ch, flag); - } - if ((rsr & UART01x_RSR_OE) && - tty->flip.count < TTY_FLIPBUF_SIZE) { - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } + uart_insert_char(&uap->port, rsr, UART01x_RSR_OE, ch, flag); + ignore_char: status = readw(uap->port.membase + UART01x_FR); } diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c index 6242f3090a9..e92522b33c4 100644 --- a/drivers/serial/clps711x.c +++ b/drivers/serial/clps711x.c @@ -143,10 +143,7 @@ static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *re * CHECK: does overrun affect the current character? * ASSUMPTION: it does not. */ - if ((ch & port->ignore_status_mask & ~RXSTAT_OVERRUN) == 0) - tty_insert_flip_char(tty, ch, flg); - if ((ch & ~port->ignore_status_mask & RXSTAT_OVERRUN) == 0) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + uart_insert_char(port, ch, UARTDR_OVERR, ch, flg); ignore_char: status = clps_readl(SYSFLG(port)); diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index 51d8a49f447..9dc151d8fa6 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -161,20 +161,12 @@ receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs) else if (*status & UART_LSR_FE) flag = TTY_FRAME; } + if (uart_handle_sysrq_char(&up->port, ch, regs)) goto ignore_char; - if ((*status & up->port.ignore_status_mask) == 0) { - tty_insert_flip_char(tty, ch, flag); - } - if ((*status & UART_LSR_OE) && - tty->flip.count < TTY_FLIPBUF_SIZE) { - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character. - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } + + uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag); + ignore_char: *status = serial_in(up, UART_LSR); } while ((*status & UART_LSR_DR) && (max_count-- > 0)); diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index 435750d40a4..2a9f7ade2c9 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -394,20 +394,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id, struct pt_regs *regs) if (uart_handle_sysrq_char(port, ch, regs)) goto ignore_char; - if ((uerstat & port->ignore_status_mask) == 0) { - tty_insert_flip_char(tty, ch, flag); - } - - if ((uerstat & S3C2410_UERSTAT_OVERRUN) && - tty->flip.count < TTY_FLIPBUF_SIZE) { - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character. - */ - - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } + uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, ch, flag); ignore_char: continue; diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c index 157218bc6c6..22565a67a57 100644 --- a/drivers/serial/sa1100.c +++ b/drivers/serial/sa1100.c @@ -237,10 +237,7 @@ sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs) if (uart_handle_sysrq_char(&sport->port, ch, regs)) goto ignore_char; - if ((status & port->ignore_status_mask & ~UTSR1_TO_SM(UTSR1_ROR)) == 0) - tty_insert_flip_char(tty, ch, flg); - if (status & ~port->ignore_status_mask & UTSR1_TO_SM(UTSR1_ROR)) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + uart_insert_char(&sport->port, status, UTSR1_TO_SM(UTSR1_ROR), ch, flg); ignore_char: status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) | diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c index 85cfa08d3ba..56f269b6bfb 100644 --- a/drivers/serial/serial_lh7a40x.c +++ b/drivers/serial/serial_lh7a40x.c @@ -190,18 +190,7 @@ lh7a40xuart_rx_chars (struct uart_port* port) if (uart_handle_sysrq_char (port, (unsigned char) data, regs)) continue; - if ((data & port->ignore_status_mask) == 0) { - tty_insert_flip_char(tty, data, flag); - } - if ((data & RxOverrunError) - && tty->flip.count < TTY_FLIPBUF_SIZE) { - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } + uart_insert_char(port, data, RxOverrunError, data, flag); } tty_flip_buffer_push (tty); return; diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c index 37b2ef297cb..3f1051a4a13 100644 --- a/drivers/serial/serial_txx9.c +++ b/drivers/serial/serial_txx9.c @@ -350,18 +350,9 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r } if (uart_handle_sysrq_char(&up->port, ch, regs)) goto ignore_char; - if ((disr & up->port.ignore_status_mask) == 0) { - tty_insert_flip_char(tty, ch, flag); - } - if ((disr & TXX9_SIDISR_UOER) && - tty->flip.count < TTY_FLIPBUF_SIZE) { - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character. - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } + + uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag); + ignore_char: disr = sio_in(up, TXX9_SIDISR); } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0)); diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c index 307886199f2..5d2ceb623e6 100644 --- a/drivers/serial/vr41xx_siu.c +++ b/drivers/serial/vr41xx_siu.c @@ -412,10 +412,8 @@ static inline void receive_chars(struct uart_port *port, uint8_t *status, if (uart_handle_sysrq_char(port, ch, regs)) goto ignore_char; - if ((lsr & port->ignore_status_mask) == 0) - tty_insert_flip_char(tty, ch, flag); - if ((lsr & UART_LSR_OE) && (tty->flip.count < TTY_FLIPBUF_SIZE)) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + + uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); ignore_char: lsr = siu_read(port, UART_LSR); diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index c3fb5984f25..d6025af7efa 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -479,6 +479,25 @@ uart_handle_cts_change(struct uart_port *port, unsigned int status) } } +#include + +static inline void +uart_insert_char(struct uart_port *port, unsigned int status, + unsigned int overrun, unsigned int ch, unsigned int flag) +{ + struct tty_struct *tty = port->info->tty; + + if ((status & port->ignore_status_mask & ~overrun) == 0) + tty_insert_flip_char(tty, ch, flag); + + /* + * Overrun is special. Since it's reported immediately, + * it doesn't affect the current character. + */ + if (status & ~port->ignore_status_mask & overrun) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); +} + /* * UART_ENABLE_MS - determine if port should enable modem status irqs */ -- cgit v1.2.3 From c4e1f6f6bf82af89994a0ee760fc5e036c4d3c1f Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 10 May 2005 10:40:19 +0100 Subject: [PATCH] ARM: Add top_pmd, which points at the top-most page table Signed-off-by: Russell King --- arch/arm/mm/mm-armv.c | 4 ++++ include/asm-arm/page.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index 2a514b05cd5..fa60fd65fcf 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -37,6 +37,8 @@ pgprot_t pgprot_kernel; EXPORT_SYMBOL(pgprot_kernel); +pmd_t *top_pmd; + struct cachepolicy { const char policy[16]; unsigned int cr_mask; @@ -682,6 +684,8 @@ void __init memtable_init(struct meminfo *mi) flush_cache_all(); flush_tlb_all(); + + top_pmd = pmd_off_k(VECTORS_HIGH); } /* diff --git a/include/asm-arm/page.h b/include/asm-arm/page.h index 4ca3a8e9348..d26d1574d97 100644 --- a/include/asm-arm/page.h +++ b/include/asm-arm/page.h @@ -171,6 +171,9 @@ typedef unsigned long pgprot_t; #endif /* STRICT_MM_TYPECHECKS */ +/* the upper-most page table pointer */ +extern pmd_t *top_pmd; + /* Pure 2^n version of get_order */ static inline int get_order(unsigned long size) { -- cgit v1.2.3 From d2bab05ac1f9a2f5ddcd2f3256237e5c47fc127f Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 10 May 2005 14:23:01 +0100 Subject: [PATCH] ARM: Move copy/clear user_page locking into implementation Move the locking for copy_user_page() and clear_user_page() into the implementations which require locking. For simple memcpy/ memset based implementations, the locking is extra overhead which is not necessary, and prevents preemption occuring. Signed-off-by: Russell King --- arch/arm/mm/copypage-v4mc.S | 80 ------------------------------- arch/arm/mm/copypage-v4mc.c | 111 ++++++++++++++++++++++++++++++++++++++++++++ include/asm-arm/page.h | 15 +----- 3 files changed, 113 insertions(+), 93 deletions(-) delete mode 100644 arch/arm/mm/copypage-v4mc.S create mode 100644 arch/arm/mm/copypage-v4mc.c diff --git a/arch/arm/mm/copypage-v4mc.S b/arch/arm/mm/copypage-v4mc.S deleted file mode 100644 index 305af3dab3d..00000000000 --- a/arch/arm/mm/copypage-v4mc.S +++ /dev/null @@ -1,80 +0,0 @@ -/* - * linux/arch/arm/lib/copy_page-armv4mc.S - * - * Copyright (C) 1995-2001 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * ASM optimised string functions - */ -#include -#include -#include - - .text - .align 5 -/* - * ARMv4 mini-dcache optimised copy_user_page - * - * We flush the destination cache lines just before we write the data into the - * corresponding address. Since the Dcache is read-allocate, this removes the - * Dcache aliasing issue. The writes will be forwarded to the write buffer, - * and merged as appropriate. - * - * Note: We rely on all ARMv4 processors implementing the "invalidate D line" - * instruction. If your processor does not supply this, you have to write your - * own copy_user_page that does the right thing. - */ -ENTRY(v4_mc_copy_user_page) - stmfd sp!, {r4, lr} @ 2 - mov r4, r0 - mov r0, r1 - bl map_page_minicache - mov r1, #PAGE_SZ/64 @ 1 - ldmia r0!, {r2, r3, ip, lr} @ 4 -1: mcr p15, 0, r4, c7, c6, 1 @ 1 invalidate D line - stmia r4!, {r2, r3, ip, lr} @ 4 - ldmia r0!, {r2, r3, ip, lr} @ 4+1 - stmia r4!, {r2, r3, ip, lr} @ 4 - ldmia r0!, {r2, r3, ip, lr} @ 4 - mcr p15, 0, r4, c7, c6, 1 @ 1 invalidate D line - stmia r4!, {r2, r3, ip, lr} @ 4 - ldmia r0!, {r2, r3, ip, lr} @ 4 - subs r1, r1, #1 @ 1 - stmia r4!, {r2, r3, ip, lr} @ 4 - ldmneia r0!, {r2, r3, ip, lr} @ 4 - bne 1b @ 1 - ldmfd sp!, {r4, pc} @ 3 - - .align 5 -/* - * ARMv4 optimised clear_user_page - * - * Same story as above. - */ -ENTRY(v4_mc_clear_user_page) - str lr, [sp, #-4]! - mov r1, #PAGE_SZ/64 @ 1 - mov r2, #0 @ 1 - mov r3, #0 @ 1 - mov ip, #0 @ 1 - mov lr, #0 @ 1 -1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line - stmia r0!, {r2, r3, ip, lr} @ 4 - stmia r0!, {r2, r3, ip, lr} @ 4 - mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line - stmia r0!, {r2, r3, ip, lr} @ 4 - stmia r0!, {r2, r3, ip, lr} @ 4 - subs r1, r1, #1 @ 1 - bne 1b @ 1 - ldr pc, [sp], #4 - - __INITDATA - - .type v4_mc_user_fns, #object -ENTRY(v4_mc_user_fns) - .long v4_mc_clear_user_page - .long v4_mc_copy_user_page - .size v4_mc_user_fns, . - v4_mc_user_fns diff --git a/arch/arm/mm/copypage-v4mc.c b/arch/arm/mm/copypage-v4mc.c new file mode 100644 index 00000000000..16384a7600a --- /dev/null +++ b/arch/arm/mm/copypage-v4mc.c @@ -0,0 +1,111 @@ +/* + * linux/arch/arm/lib/copypage-armv4mc.S + * + * Copyright (C) 1995-2005 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This handles the mini data cache, as found on SA11x0 and XScale + * processors. When we copy a user page page, we map it in such a way + * that accesses to this page will not touch the main data cache, but + * will be cached in the mini data cache. This prevents us thrashing + * the main data cache on page faults. + */ +#include +#include + +#include +#include +#include + +/* + * 0xffff8000 to 0xffffffff is reserved for any ARM architecture + * specific hacks for copying pages efficiently. + */ +#define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \ + L_PTE_CACHEABLE) + +#define TOP_PTE(x) pte_offset_kernel(top_pmd, x) + +static DEFINE_SPINLOCK(minicache_lock); + +/* + * ARMv4 mini-dcache optimised copy_user_page + * + * We flush the destination cache lines just before we write the data into the + * corresponding address. Since the Dcache is read-allocate, this removes the + * Dcache aliasing issue. The writes will be forwarded to the write buffer, + * and merged as appropriate. + * + * Note: We rely on all ARMv4 processors implementing the "invalidate D line" + * instruction. If your processor does not supply this, you have to write your + * own copy_user_page that does the right thing. + */ +static void __attribute__((naked)) +mc_copy_user_page(void *from, void *to) +{ + asm volatile( + "stmfd sp!, {r4, lr} @ 2\n\ + mov r4, %2 @ 1\n\ + ldmia %0!, {r2, r3, ip, lr} @ 4\n\ +1: mcr p15, 0, %1, c7, c6, 1 @ 1 invalidate D line\n\ + stmia %1!, {r2, r3, ip, lr} @ 4\n\ + ldmia %0!, {r2, r3, ip, lr} @ 4+1\n\ + stmia %1!, {r2, r3, ip, lr} @ 4\n\ + ldmia %0!, {r2, r3, ip, lr} @ 4\n\ + mcr p15, 0, %1, c7, c6, 1 @ 1 invalidate D line\n\ + stmia %1!, {r2, r3, ip, lr} @ 4\n\ + ldmia %0!, {r2, r3, ip, lr} @ 4\n\ + subs r4, r4, #1 @ 1\n\ + stmia %1!, {r2, r3, ip, lr} @ 4\n\ + ldmneia %0!, {r2, r3, ip, lr} @ 4\n\ + bne 1b @ 1\n\ + ldmfd sp!, {r4, pc} @ 3" + : + : "r" (from), "r" (to), "I" (PAGE_SIZE / 64)); +} + +void v4_mc_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr) +{ + spin_lock(&minicache_lock); + + set_pte(TOP_PTE(COPYPAGE_MINICACHE), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot)); + flush_tlb_kernel_page(COPYPAGE_MINICACHE); + + mc_copy_user_page((void *)COPYPAGE_MINICACHE, kto); + + spin_unlock(&minicache_lock); +} + +/* + * ARMv4 optimised clear_user_page + */ +void __attribute__((naked)) +v4_mc_clear_user_page(void *kaddr, unsigned long vaddr) +{ + asm volatile( + "str lr, [sp, #-4]!\n\ + mov r1, %0 @ 1\n\ + mov r2, #0 @ 1\n\ + mov r3, #0 @ 1\n\ + mov ip, #0 @ 1\n\ + mov lr, #0 @ 1\n\ +1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line\n\ + stmia r0!, {r2, r3, ip, lr} @ 4\n\ + stmia r0!, {r2, r3, ip, lr} @ 4\n\ + mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line\n\ + stmia r0!, {r2, r3, ip, lr} @ 4\n\ + stmia r0!, {r2, r3, ip, lr} @ 4\n\ + subs r1, r1, #1 @ 1\n\ + bne 1b @ 1\n\ + ldr pc, [sp], #4" + : + : "I" (PAGE_SIZE / 64)); +} + +struct cpu_user_fns v4_mc_user_fns __initdata = { + .cpu_clear_user_page = v4_mc_clear_user_page, + .cpu_copy_user_page = v4_mc_copy_user_page, +}; diff --git a/include/asm-arm/page.h b/include/asm-arm/page.h index d26d1574d97..019c45d7573 100644 --- a/include/asm-arm/page.h +++ b/include/asm-arm/page.h @@ -114,19 +114,8 @@ extern void __cpu_copy_user_page(void *to, const void *from, unsigned long user); #endif -#define clear_user_page(addr,vaddr,pg) \ - do { \ - preempt_disable(); \ - __cpu_clear_user_page(addr, vaddr); \ - preempt_enable(); \ - } while (0) - -#define copy_user_page(to,from,vaddr,pg) \ - do { \ - preempt_disable(); \ - __cpu_copy_user_page(to, from, vaddr); \ - preempt_enable(); \ - } while (0) +#define clear_user_page(addr,vaddr,pg) __cpu_clear_user_page(addr, vaddr) +#define copy_user_page(to,from,vaddr,pg) __cpu_copy_user_page(to, from, vaddr) #define clear_page(page) memzero((void *)(page), PAGE_SIZE) extern void copy_page(void *to, const void *from); -- cgit v1.2.3 From 08ee4e4c5fd3fb0857eeb6a5a0ff66881432e8a3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 10 May 2005 17:30:47 +0100 Subject: [PATCH] ARM: Use top_pmd for V6 copy/clear user_page Remove needless page table walking for v6 page operations. Signed-off-by: Russell King --- arch/arm/mm/copypage-v6.c | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c index 694ac820885..a8c00236bd3 100644 --- a/arch/arm/mm/copypage-v6.c +++ b/arch/arm/mm/copypage-v6.c @@ -26,8 +26,8 @@ #define to_address (0xffffc000) #define to_pgprot PAGE_KERNEL -static pte_t *from_pte; -static pte_t *to_pte; +#define TOP_PTE(x) pte_offset_kernel(top_pmd, x) + static DEFINE_SPINLOCK(v6_lock); #define DCACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT) @@ -74,8 +74,8 @@ void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned long vadd */ spin_lock(&v6_lock); - set_pte(from_pte + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, from_pgprot)); - set_pte(to_pte + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, to_pgprot)); + set_pte(TOP_PTE(from_address) + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, from_pgprot)); + set_pte(TOP_PTE(to_address) + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, to_pgprot)); from = from_address + (offset << PAGE_SHIFT); to = to_address + (offset << PAGE_SHIFT); @@ -114,7 +114,7 @@ void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr) */ spin_lock(&v6_lock); - set_pte(to_pte + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, to_pgprot)); + set_pte(TOP_PTE(to_address) + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, to_pgprot)); flush_tlb_kernel_page(to); clear_page((void *)to); @@ -129,21 +129,6 @@ struct cpu_user_fns v6_user_fns __initdata = { static int __init v6_userpage_init(void) { if (cache_is_vipt_aliasing()) { - pgd_t *pgd; - pmd_t *pmd; - - pgd = pgd_offset_k(from_address); - pmd = pmd_alloc(&init_mm, pgd, from_address); - if (!pmd) - BUG(); - from_pte = pte_alloc_kernel(&init_mm, pmd, from_address); - if (!from_pte) - BUG(); - - to_pte = pte_alloc_kernel(&init_mm, pmd, to_address); - if (!to_pte) - BUG(); - cpu_user.cpu_clear_user_page = v6_clear_user_page_aliasing; cpu_user.cpu_copy_user_page = v6_copy_user_page_aliasing; } @@ -151,5 +136,4 @@ static int __init v6_userpage_init(void) return 0; } -__initcall(v6_userpage_init); - +core_initcall(v6_userpage_init); -- cgit v1.2.3 From 8d802d28c23122a57d7dddf4886b0486ca183d2d Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 10 May 2005 17:31:43 +0100 Subject: [PATCH] ARM: Add V6 aliasing cache flush Add cache flushing support for aliased V6 caches to flush_dcache_page. Signed-off-by: Russell King --- arch/arm/mm/flush.c | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index c6de48d8950..4085ed983e4 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -13,6 +13,29 @@ #include #include +#include + +#ifdef CONFIG_CPU_CACHE_VIPT +#define ALIAS_FLUSH_START 0xffff4000 + +#define TOP_PTE(x) pte_offset_kernel(top_pmd, x) + +static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr) +{ + unsigned long to = ALIAS_FLUSH_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT); + + set_pte(TOP_PTE(to), pfn_pte(pfn, PAGE_KERNEL)); + flush_tlb_kernel_page(to); + + asm( "mcrr p15, 0, %1, %0, c14\n" + " mcrr p15, 0, %1, %0, c5\n" + : + : "r" (to), "r" (to + PAGE_SIZE - L1_CACHE_BYTES) + : "cc"); +} +#else +#define flush_pfn_alias(pfn,vaddr) do { } while (0) +#endif static void __flush_dcache_page(struct address_space *mapping, struct page *page) { @@ -36,6 +59,18 @@ static void __flush_dcache_page(struct address_space *mapping, struct page *page if (!mapping) return; + /* + * This is a page cache page. If we have a VIPT cache, we + * only need to do one flush - which would be at the relevant + * userspace colour, which is congruent with page->index. + */ + if (cache_is_vipt()) { + if (cache_is_vipt_aliasing()) + flush_pfn_alias(page_to_pfn(page), + page->index << PAGE_CACHE_SHIFT); + return; + } + /* * There are possible user space mappings of this page: * - VIVT cache: we need to also write back and invalidate all user @@ -57,8 +92,6 @@ static void __flush_dcache_page(struct address_space *mapping, struct page *page continue; offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; flush_cache_page(mpnt, mpnt->vm_start + offset, page_to_pfn(page)); - if (cache_is_vipt()) - break; } flush_dcache_mmap_unlock(mapping); } -- cgit v1.2.3 From fa4354359f800ef9d68ed644438efd45b559b443 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 10 May 2005 17:36:29 +0100 Subject: [PATCH] ARM: 2663/2: I can't type Patch from Nicolas Pitre Signed-off-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/mm/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index c4fc6be629d..07646d25e26 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -427,6 +427,6 @@ config HAS_TLS_REG help This selects support for the CP15 thread register. It is defined to be available on ARMv6 or later. If a particular - ARMv6 or later CPU doesn't support it then it must omc;ide "select - TLS_REG_EMUL" along with its other caracteristics. + ARMv6 or later CPU doesn't support it then it must include "select + TLS_REG_EMUL" along with its other characteristics. -- cgit v1.2.3 From d7def6c22dfa9f32b3d9e5546a7a6a90c644ff5f Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 10 May 2005 19:01:35 +0100 Subject: [PATCH] ARM: 2666/1: i.MX pwm controller defines Patch from Sascha Hauer This patch adds the defines for the i.MX PWM controller Signed-off-by: Steven Scholz Signed-off-by: Sascha Hauer Signed-off-by: Russell King --- include/asm-arm/arch-imx/imx-regs.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/asm-arm/arch-imx/imx-regs.h b/include/asm-arm/arch-imx/imx-regs.h index f32c203952c..93b840e8fa6 100644 --- a/include/asm-arm/arch-imx/imx-regs.h +++ b/include/asm-arm/arch-imx/imx-regs.h @@ -227,6 +227,30 @@ #define PD31_PF_TMR2OUT ( GPIO_PORTD | GPIO_PF | 31 ) #define PD31_BIN_SPI2_TXD ( GPIO_PORTD | GPIO_BIN | 31 ) +/* + * PWM controller + */ +#define PWMC __REG(IMX_PWM_BASE + 0x00) /* PWM Control Register */ +#define PWMS __REG(IMX_PWM_BASE + 0x04) /* PWM Sample Register */ +#define PWMP __REG(IMX_PWM_BASE + 0x08) /* PWM Period Register */ +#define PWMCNT __REG(IMX_PWM_BASE + 0x0C) /* PWM Counter Register */ + +#define PWMC_HCTR (0x01<<18) /* Halfword FIFO Data Swapping */ +#define PWMC_BCTR (0x01<<17) /* Byte FIFO Data Swapping */ +#define PWMC_SWR (0x01<<16) /* Software Reset */ +#define PWMC_CLKSRC (0x01<<15) /* Clock Source */ +#define PWMC_PRESCALER(x) (((x-1) & 0x7F) << 8) /* PRESCALER */ +#define PWMC_IRQ (0x01<< 7) /* Interrupt Request */ +#define PWMC_IRQEN (0x01<< 6) /* Interrupt Request Enable */ +#define PWMC_FIFOAV (0x01<< 5) /* FIFO Available */ +#define PWMC_EN (0x01<< 4) /* Enables/Disables the PWM */ +#define PWMC_REPEAT(x) (((x) & 0x03) << 2) /* Sample Repeats */ +#define PWMC_CLKSEL(x) (((x) & 0x03) << 0) /* Clock Selection */ + +#define PWMS_SAMPLE(x) ((x) & 0xFFFF) /* Contains a two-sample word */ +#define PWMP_PERIOD(x) ((x) & 0xFFFF) /* Represents the PWM's period */ +#define PWMC_COUNTER(x) ((x) & 0xFFFF) /* Represents the current count value */ + /* * DMA Controller */ -- cgit v1.2.3 From e4fdee8e3b41239242a8f421a28736ef8e08ca55 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 11 May 2005 11:34:32 -0700 Subject: [SUNSAB]: Defer register updates until transmitter is idle. The chip can emit garbage characters if we touch the settings while characters are going out. Signed-off-by: David S. Miller --- drivers/serial/sunsab.c | 109 +++++++++++++++++++++++++++++++----------------- drivers/serial/sunsab.h | 1 + 2 files changed, 72 insertions(+), 38 deletions(-) diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 39b788d95e3..10e2990a40d 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -61,6 +61,16 @@ struct uart_sunsab_port { unsigned char pvr_dtr_bit; /* Which PVR bit is DTR */ unsigned char pvr_dsr_bit; /* Which PVR bit is DSR */ int type; /* SAB82532 version */ + + /* Setting configuration bits while the transmitter is active + * can cause garbage characters to get emitted by the chip. + * Therefore, we cache such writes here and do the real register + * write the next time the transmitter becomes idle. + */ + unsigned int cached_ebrg; + unsigned char cached_mode; + unsigned char cached_pvr; + unsigned char cached_dafo; }; /* @@ -236,6 +246,7 @@ receive_chars(struct uart_sunsab_port *up, } static void sunsab_stop_tx(struct uart_port *, unsigned int); +static void sunsab_tx_idle(struct uart_sunsab_port *); static void transmit_chars(struct uart_sunsab_port *up, union sab82532_irq_status *stat) @@ -258,6 +269,7 @@ static void transmit_chars(struct uart_sunsab_port *up, return; set_bit(SAB82532_XPR, &up->irqflags); + sunsab_tx_idle(up); if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { up->interrupt_mask1 |= SAB82532_IMR1_XPR; @@ -397,21 +409,21 @@ static void sunsab_set_mctrl(struct uart_port *port, unsigned int mctrl) struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; if (mctrl & TIOCM_RTS) { - writeb(readb(&up->regs->rw.mode) & ~SAB82532_MODE_FRTS, - &up->regs->rw.mode); - writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RTS, - &up->regs->rw.mode); + up->cached_mode &= ~SAB82532_MODE_FRTS; + up->cached_mode |= SAB82532_MODE_RTS; } else { - writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_FRTS, - &up->regs->rw.mode); - writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RTS, - &up->regs->rw.mode); + up->cached_mode |= (SAB82532_MODE_FRTS | + SAB82532_MODE_RTS); } if (mctrl & TIOCM_DTR) { - writeb(readb(&up->regs->rw.pvr) & ~(up->pvr_dtr_bit), &up->regs->rw.pvr); + up->cached_pvr &= ~(up->pvr_dtr_bit); } else { - writeb(readb(&up->regs->rw.pvr) | up->pvr_dtr_bit, &up->regs->rw.pvr); + up->cached_pvr |= up->pvr_dtr_bit; } + + set_bit(SAB82532_REGS_PENDING, &up->irqflags); + if (test_bit(SAB82532_XPR, &up->irqflags)) + sunsab_tx_idle(up); } /* port->lock is not held. */ @@ -449,6 +461,25 @@ static void sunsab_stop_tx(struct uart_port *port, unsigned int tty_stop) writeb(up->interrupt_mask1, &up->regs->w.imr1); } +/* port->lock held by caller. */ +static void sunsab_tx_idle(struct uart_sunsab_port *up) +{ + if (test_bit(SAB82532_REGS_PENDING, &up->irqflags)) { + u8 tmp; + + clear_bit(SAB82532_REGS_PENDING, &up->irqflags); + writeb(up->cached_mode, &up->regs->rw.mode); + writeb(up->cached_pvr, &up->regs->rw.pvr); + writeb(up->cached_dafo, &up->regs->w.dafo); + + writeb(up->cached_ebrg & 0xff, &up->regs->w.bgr); + tmp = readb(&up->regs->rw.ccr2); + tmp &= ~0xc0; + tmp |= (up->cached_ebrg >> 2) & 0xc0; + writeb(tmp, &up->regs->rw.ccr2); + } +} + /* port->lock held by caller. */ static void sunsab_start_tx(struct uart_port *port, unsigned int tty_start) { @@ -517,12 +548,16 @@ static void sunsab_break_ctl(struct uart_port *port, int break_state) spin_lock_irqsave(&up->port.lock, flags); - val = readb(&up->regs->rw.dafo); + val = up->cached_dafo; if (break_state) val |= SAB82532_DAFO_XBRK; else val &= ~SAB82532_DAFO_XBRK; - writeb(val, &up->regs->rw.dafo); + up->cached_dafo = val; + + set_bit(SAB82532_REGS_PENDING, &up->irqflags); + if (test_bit(SAB82532_XPR, &up->irqflags)) + sunsab_tx_idle(up); spin_unlock_irqrestore(&up->port.lock, flags); } @@ -566,8 +601,9 @@ static int sunsab_startup(struct uart_port *port) SAB82532_CCR2_TOE, &up->regs->w.ccr2); writeb(0, &up->regs->w.ccr3); writeb(SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG, &up->regs->w.ccr4); - writeb(SAB82532_MODE_RTS | SAB82532_MODE_FCTS | - SAB82532_MODE_RAC, &up->regs->w.mode); + up->cached_mode = (SAB82532_MODE_RTS | SAB82532_MODE_FCTS | + SAB82532_MODE_RAC); + writeb(up->cached_mode, &up->regs->w.mode); writeb(SAB82532_RFC_DPS|SAB82532_RFC_RFTH_32, &up->regs->w.rfc); tmp = readb(&up->regs->rw.ccr0); @@ -598,7 +634,6 @@ static void sunsab_shutdown(struct uart_port *port) { struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; unsigned long flags; - unsigned char tmp; spin_lock_irqsave(&up->port.lock, flags); @@ -609,14 +644,13 @@ static void sunsab_shutdown(struct uart_port *port) writeb(up->interrupt_mask1, &up->regs->w.imr1); /* Disable break condition */ - tmp = readb(&up->regs->rw.dafo); - tmp &= ~SAB82532_DAFO_XBRK; - writeb(tmp, &up->regs->rw.dafo); + up->cached_dafo = readb(&up->regs->rw.dafo); + up->cached_dafo &= ~SAB82532_DAFO_XBRK; + writeb(up->cached_dafo, &up->regs->rw.dafo); /* Disable Receiver */ - tmp = readb(&up->regs->rw.mode); - tmp &= ~SAB82532_MODE_RAC; - writeb(tmp, &up->regs->rw.mode); + up->cached_mode &= ~SAB82532_MODE_RAC; + writeb(up->cached_mode, &up->regs->rw.mode); /* * XXX FIXME @@ -685,7 +719,6 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla unsigned int iflag, unsigned int baud, unsigned int quot) { - unsigned int ebrg; unsigned char dafo; int bits, n, m; @@ -714,10 +747,11 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla } else { dafo |= SAB82532_DAFO_PAR_EVEN; } + up->cached_dafo = dafo; calc_ebrg(baud, &n, &m); - ebrg = n | (m << 6); + up->cached_ebrg = n | (m << 6); up->tec_timeout = (10 * 1000000) / baud; up->cec_timeout = up->tec_timeout >> 2; @@ -770,16 +804,13 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla uart_update_timeout(&up->port, cflag, (up->port.uartclk / (16 * quot))); - /* Now bang the new settings into the chip. */ - sunsab_cec_wait(up); - sunsab_tec_wait(up); - writeb(dafo, &up->regs->w.dafo); - writeb(ebrg & 0xff, &up->regs->w.bgr); - writeb((readb(&up->regs->rw.ccr2) & ~0xc0) | ((ebrg >> 2) & 0xc0), - &up->regs->rw.ccr2); - - writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RAC, &up->regs->rw.mode); - + /* Now schedule a register update when the chip's + * transmitter is idle. + */ + up->cached_mode |= SAB82532_MODE_RAC; + set_bit(SAB82532_REGS_PENDING, &up->irqflags); + if (test_bit(SAB82532_XPR, &up->irqflags)) + sunsab_tx_idle(up); } /* port->lock is not held. */ @@ -1084,11 +1115,13 @@ static void __init sunsab_init_hw(void) up->pvr_dsr_bit = (1 << 3); up->pvr_dtr_bit = (1 << 2); } - writeb((1 << 1) | (1 << 2) | (1 << 4), &up->regs->w.pvr); - writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_FRTS, - &up->regs->rw.mode); - writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RTS, - &up->regs->rw.mode); + up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4); + writeb(up->cached_pvr, &up->regs->w.pvr); + up->cached_mode = readb(&up->regs->rw.mode); + up->cached_mode |= SAB82532_MODE_FRTS; + writeb(up->cached_mode, &up->regs->rw.mode); + up->cached_mode |= SAB82532_MODE_RTS; + writeb(up->cached_mode, &up->regs->rw.mode); up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT; up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT; diff --git a/drivers/serial/sunsab.h b/drivers/serial/sunsab.h index 686086fcbbf..b78e1f7b805 100644 --- a/drivers/serial/sunsab.h +++ b/drivers/serial/sunsab.h @@ -126,6 +126,7 @@ union sab82532_irq_status { /* irqflags bits */ #define SAB82532_ALLS 0x00000001 #define SAB82532_XPR 0x00000002 +#define SAB82532_REGS_PENDING 0x00000004 /* RFIFO Status Byte */ #define SAB82532_RSTAT_PE 0x80 -- cgit v1.2.3 From 4dbc30fb27ac4e647e6efadb382ff7d38c3d368e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 11 May 2005 11:37:00 -0700 Subject: [SPARC64]: Add timeouts to streaming buffer synchronization. If some hardware error occurs and the flush flag never updates, we will hang forever in these routines. Add a timeout, and print out a diagnostic if it is reached. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_iommu.c | 165 ++++++++++++++++------------------------ arch/sparc64/kernel/sbus.c | 31 ++++++-- 2 files changed, 88 insertions(+), 108 deletions(-) diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c index 292983413ae..f009b1b4550 100644 --- a/arch/sparc64/kernel/pci_iommu.c +++ b/arch/sparc64/kernel/pci_iommu.c @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -379,6 +380,54 @@ bad: return PCI_DMA_ERROR_CODE; } +static void pci_strbuf_flush(struct pci_strbuf *strbuf, struct pci_iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages) +{ + int limit; + + PCI_STC_FLUSHFLAG_INIT(strbuf); + if (strbuf->strbuf_ctxflush && + iommu->iommu_ctxflush) { + unsigned long matchreg, flushreg; + + flushreg = strbuf->strbuf_ctxflush; + matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); + + limit = 10000; + do { + pci_iommu_write(flushreg, ctx); + udelay(10); + limit--; + if (!limit) + break; + } while(((long)pci_iommu_read(matchreg)) < 0L); + if (!limit) + printk(KERN_WARNING "pci_strbuf_flush: ctx flush " + "timeout vaddr[%08x] ctx[%lx]\n", + vaddr, ctx); + } else { + unsigned long i; + + for (i = 0; i < npages; i++, vaddr += IO_PAGE_SIZE) + pci_iommu_write(strbuf->strbuf_pflush, vaddr); + } + + pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); + (void) pci_iommu_read(iommu->write_complete_reg); + + limit = 10000; + while (!PCI_STC_FLUSHFLAG_SET(strbuf)) { + limit--; + if (!limit) + break; + udelay(10); + membar("#LoadLoad"); + } + if (!limit) + printk(KERN_WARNING "pci_strbuf_flush: flushflag timeout " + "vaddr[%08x] ctx[%lx] npages[%ld]\n", + vaddr, ctx, npages); +} + /* Unmap a single streaming mode DMA translation. */ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) { @@ -386,7 +435,7 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int struct pci_iommu *iommu; struct pci_strbuf *strbuf; iopte_t *base; - unsigned long flags, npages, i, ctx; + unsigned long flags, npages, ctx; if (direction == PCI_DMA_NONE) BUG(); @@ -414,29 +463,8 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL; /* Step 1: Kick data out of streaming buffers if necessary. */ - if (strbuf->strbuf_enabled) { - u32 vaddr = bus_addr; - - PCI_STC_FLUSHFLAG_INIT(strbuf); - if (strbuf->strbuf_ctxflush && - iommu->iommu_ctxflush) { - unsigned long matchreg, flushreg; - - flushreg = strbuf->strbuf_ctxflush; - matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); - do { - pci_iommu_write(flushreg, ctx); - } while(((long)pci_iommu_read(matchreg)) < 0L); - } else { - for (i = 0; i < npages; i++, vaddr += IO_PAGE_SIZE) - pci_iommu_write(strbuf->strbuf_pflush, vaddr); - } - - pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); - (void) pci_iommu_read(iommu->write_complete_reg); - while (!PCI_STC_FLUSHFLAG_SET(strbuf)) - membar("#LoadLoad"); - } + if (strbuf->strbuf_enabled) + pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages); /* Step 2: Clear out first TSB entry. */ iopte_make_dummy(iommu, base); @@ -647,29 +675,8 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL; /* Step 1: Kick data out of streaming buffers if necessary. */ - if (strbuf->strbuf_enabled) { - u32 vaddr = (u32) bus_addr; - - PCI_STC_FLUSHFLAG_INIT(strbuf); - if (strbuf->strbuf_ctxflush && - iommu->iommu_ctxflush) { - unsigned long matchreg, flushreg; - - flushreg = strbuf->strbuf_ctxflush; - matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); - do { - pci_iommu_write(flushreg, ctx); - } while(((long)pci_iommu_read(matchreg)) < 0L); - } else { - for (i = 0; i < npages; i++, vaddr += IO_PAGE_SIZE) - pci_iommu_write(strbuf->strbuf_pflush, vaddr); - } - - pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); - (void) pci_iommu_read(iommu->write_complete_reg); - while (!PCI_STC_FLUSHFLAG_SET(strbuf)) - membar("#LoadLoad"); - } + if (strbuf->strbuf_enabled) + pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages); /* Step 2: Clear out first TSB entry. */ iopte_make_dummy(iommu, base); @@ -715,28 +722,7 @@ void pci_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size } /* Step 2: Kick data out of streaming buffers. */ - PCI_STC_FLUSHFLAG_INIT(strbuf); - if (iommu->iommu_ctxflush && - strbuf->strbuf_ctxflush) { - unsigned long matchreg, flushreg; - - flushreg = strbuf->strbuf_ctxflush; - matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); - do { - pci_iommu_write(flushreg, ctx); - } while(((long)pci_iommu_read(matchreg)) < 0L); - } else { - unsigned long i; - - for (i = 0; i < npages; i++, bus_addr += IO_PAGE_SIZE) - pci_iommu_write(strbuf->strbuf_pflush, bus_addr); - } - - /* Step 3: Perform flush synchronization sequence. */ - pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); - (void) pci_iommu_read(iommu->write_complete_reg); - while (!PCI_STC_FLUSHFLAG_SET(strbuf)) - membar("#LoadLoad"); + pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages); spin_unlock_irqrestore(&iommu->lock, flags); } @@ -749,7 +735,8 @@ void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, i struct pcidev_cookie *pcp; struct pci_iommu *iommu; struct pci_strbuf *strbuf; - unsigned long flags, ctx; + unsigned long flags, ctx, npages, i; + u32 bus_addr; pcp = pdev->sysdata; iommu = pcp->pbm->iommu; @@ -772,36 +759,14 @@ void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, i } /* Step 2: Kick data out of streaming buffers. */ - PCI_STC_FLUSHFLAG_INIT(strbuf); - if (iommu->iommu_ctxflush && - strbuf->strbuf_ctxflush) { - unsigned long matchreg, flushreg; - - flushreg = strbuf->strbuf_ctxflush; - matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); - do { - pci_iommu_write(flushreg, ctx); - } while (((long)pci_iommu_read(matchreg)) < 0L); - } else { - unsigned long i, npages; - u32 bus_addr; - - bus_addr = sglist[0].dma_address & IO_PAGE_MASK; - - for(i = 1; i < nelems; i++) - if (!sglist[i].dma_length) - break; - i--; - npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - bus_addr) >> IO_PAGE_SHIFT; - for (i = 0; i < npages; i++, bus_addr += IO_PAGE_SIZE) - pci_iommu_write(strbuf->strbuf_pflush, bus_addr); - } - - /* Step 3: Perform flush synchronization sequence. */ - pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); - (void) pci_iommu_read(iommu->write_complete_reg); - while (!PCI_STC_FLUSHFLAG_SET(strbuf)) - membar("#LoadLoad"); + bus_addr = sglist[0].dma_address & IO_PAGE_MASK; + for(i = 1; i < nelems; i++) + if (!sglist[i].dma_length) + break; + i--; + npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) + - bus_addr) >> IO_PAGE_SHIFT; + pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages); spin_unlock_irqrestore(&iommu->lock, flags); } diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index 14d9c3a21b9..d3eca98e1fe 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -117,19 +117,34 @@ static void iommu_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages #define STRBUF_TAG_VALID 0x02UL -static void strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages) +static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages) { + unsigned long n; + int limit; + iommu->strbuf_flushflag = 0UL; - while (npages--) - upa_writeq(base + (npages << IO_PAGE_SHIFT), + n = npages; + while (n--) + upa_writeq(base + (n << IO_PAGE_SHIFT), iommu->strbuf_regs + STRBUF_PFLUSH); /* Whoopee cushion! */ upa_writeq(__pa(&iommu->strbuf_flushflag), iommu->strbuf_regs + STRBUF_FSYNC); upa_readq(iommu->sbus_control_reg); - while (iommu->strbuf_flushflag == 0UL) + + limit = 10000; + while (iommu->strbuf_flushflag == 0UL) { + limit--; + if (!limit) + break; + udelay(10); membar("#LoadLoad"); + } + if (!limit) + printk(KERN_WARNING "sbus_strbuf_flush: flushflag timeout " + "vaddr[%08x] npages[%ld]\n", + base, npages); } static iopte_t *alloc_streaming_cluster(struct sbus_iommu *iommu, unsigned long npages) @@ -406,7 +421,7 @@ void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t dma_addr, size_t size, spin_lock_irqsave(&iommu->lock, flags); free_streaming_cluster(iommu, dma_base, size >> IO_PAGE_SHIFT); - strbuf_flush(iommu, dma_base, size >> IO_PAGE_SHIFT); + sbus_strbuf_flush(iommu, dma_base, size >> IO_PAGE_SHIFT); spin_unlock_irqrestore(&iommu->lock, flags); } @@ -569,7 +584,7 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int iommu = sdev->bus->iommu; spin_lock_irqsave(&iommu->lock, flags); free_streaming_cluster(iommu, dvma_base, size >> IO_PAGE_SHIFT); - strbuf_flush(iommu, dvma_base, size >> IO_PAGE_SHIFT); + sbus_strbuf_flush(iommu, dvma_base, size >> IO_PAGE_SHIFT); spin_unlock_irqrestore(&iommu->lock, flags); } @@ -581,7 +596,7 @@ void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t base, size_t size = (IO_PAGE_ALIGN(base + size) - (base & IO_PAGE_MASK)); spin_lock_irqsave(&iommu->lock, flags); - strbuf_flush(iommu, base & IO_PAGE_MASK, size >> IO_PAGE_SHIFT); + sbus_strbuf_flush(iommu, base & IO_PAGE_MASK, size >> IO_PAGE_SHIFT); spin_unlock_irqrestore(&iommu->lock, flags); } @@ -605,7 +620,7 @@ void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int size = IO_PAGE_ALIGN(sg[i].dma_address + sg[i].dma_length) - base; spin_lock_irqsave(&iommu->lock, flags); - strbuf_flush(iommu, base, size >> IO_PAGE_SHIFT); + sbus_strbuf_flush(iommu, base, size >> IO_PAGE_SHIFT); spin_unlock_irqrestore(&iommu->lock, flags); } -- cgit v1.2.3 From 104e50108c862b13da26850d4b469cc13418b66b Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Sun, 27 Mar 2005 08:50:38 -0500 Subject: [PATCH] typo fix in drivers/scsi/sata_svw.c comment Add missing brace. --- drivers/scsi/sata_svw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c index 8d1a5d25c05..05075bd3a89 100644 --- a/drivers/scsi/sata_svw.c +++ b/drivers/scsi/sata_svw.c @@ -395,7 +395,7 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e /* Clear a magic bit in SCR1 according to Darwin, those help * some funky seagate drives (though so far, those were already - * set by the firmware on the machines I had access to + * set by the firmware on the machines I had access to) */ writel(readl(mmio_base + K2_SATA_SICR1_OFFSET) & ~0x00040000, mmio_base + K2_SATA_SICR1_OFFSET); -- cgit v1.2.3 From 70489c88d0b7e5820ac37a039a910bb396e2a4e3 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 12 May 2005 19:27:12 +0100 Subject: [PATCH] ARM: 2680/1: refine TLS reg availability some more again Patch from Nicolas Pitre Not all ARMv6 processors implement the TLS register. Signed-off-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/mm/Kconfig | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 07646d25e26..48bac7da8c7 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -412,21 +412,20 @@ config CPU_BPREDICT_DISABLE config TLS_REG_EMUL bool - default y if (SMP || CPU_32v6) && (CPU_32v5 || CPU_32v4 || CPU_32v3) + default y if SMP && (CPU_32v5 || CPU_32v4 || CPU_32v3) help - We might be running on an ARMv6+ processor which should have the TLS - register but for some reason we can't use it, or maybe an SMP system - using a pre-ARMv6 processor (there are apparently a few prototypes - like that in existence) and therefore access to that register must - be emulated. + An SMP system using a pre-ARMv6 processor (there are apparently + a few prototypes like that in existence) and therefore access to + that required register must be emulated. config HAS_TLS_REG bool - depends on CPU_32v6 - default y if !TLS_REG_EMUL + depends on !TLS_REG_EMUL + default y if SMP || CPU_32v7 help This selects support for the CP15 thread register. - It is defined to be available on ARMv6 or later. If a particular - ARMv6 or later CPU doesn't support it then it must include "select - TLS_REG_EMUL" along with its other characteristics. + It is defined to be available on some ARMv6 processors (including + all SMP capable ARMv6's) or later processors. User space may + assume directly accessing that register and always obtain the + expected value only on ARMv7 and above. -- cgit v1.2.3 From 9dabf9da18018b99a51334c2ef168019389ed5bf Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 12 May 2005 19:27:13 +0100 Subject: [PATCH] ARM: 2676/1: S3C2440 - NAND register additions Patch from Ben Dooks Add the register definitions for the s3c2440 NAND controller to the s3c2410 NAND register definitions Signed-off-by: Ben Dooks Signed-off-by: Russell King --- include/asm-arm/arch-s3c2410/regs-nand.h | 44 +++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/include/asm-arm/arch-s3c2410/regs-nand.h b/include/asm-arm/arch-s3c2410/regs-nand.h index c443ac83469..7cff235e667 100644 --- a/include/asm-arm/arch-s3c2410/regs-nand.h +++ b/include/asm-arm/arch-s3c2410/regs-nand.h @@ -1,16 +1,17 @@ /* linux/include/asm-arm/arch-s3c2410/regs-nand.h * - * Copyright (c) 2004 Simtec Electronics + * Copyright (c) 2004,2005 Simtec Electronics * http://www.simtec.co.uk/products/SWLINUX/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * S3C2410 clock register definitions + * S3C2410 NAND register definitions * * Changelog: * 18-Aug-2004 BJD Copied file from 2.4 and updated + * 01-May-2005 BJD Added definitions for s3c2440 controller */ #ifndef __ASM_ARM_REGS_NAND @@ -26,6 +27,22 @@ #define S3C2410_NFSTAT S3C2410_NFREG(0x10) #define S3C2410_NFECC S3C2410_NFREG(0x14) +#define S3C2440_NFCONT S3C2410_NFREG(0x04) +#define S3C2440_NFCMD S3C2410_NFREG(0x08) +#define S3C2440_NFADDR S3C2410_NFREG(0x0C) +#define S3C2440_NFDATA S3C2410_NFREG(0x10) +#define S3C2440_NFECCD0 S3C2410_NFREG(0x14) +#define S3C2440_NFECCD1 S3C2410_NFREG(0x18) +#define S3C2440_NFECCD S3C2410_NFREG(0x1C) +#define S3C2440_NFSTAT S3C2410_NFREG(0x20) +#define S3C2440_NFESTAT0 S3C2410_NFREG(0x24) +#define S3C2440_NFESTAT1 S3C2410_NFREG(0x28) +#define S3C2440_NFMECC0 S3C2410_NFREG(0x2C) +#define S3C2440_NFMECC1 S3C2410_NFREG(0x30) +#define S3C2440_NFSECC S3C2410_NFREG(0x34) +#define S3C2440_NFSBLK S3C2410_NFREG(0x38) +#define S3C2440_NFEBLK S3C2410_NFREG(0x3C) + #define S3C2410_NFCONF_EN (1<<15) #define S3C2410_NFCONF_512BYTE (1<<14) #define S3C2410_NFCONF_4STEP (1<<13) @@ -37,7 +54,28 @@ #define S3C2410_NFSTAT_BUSY (1<<0) -/* think ECC can only be 8bit read? */ +#define S3C2440_NFCONF_BUSWIDTH_8 (0<<0) +#define S3C2440_NFCONF_BUSWIDTH_16 (1<<0) +#define S3C2440_NFCONF_ADVFLASH (1<<3) +#define S3C2440_NFCONF_TACLS(x) ((x)<<12) +#define S3C2440_NFCONF_TWRPH0(x) ((x)<<8) +#define S3C2440_NFCONF_TWRPH1(x) ((x)<<4) + +#define S3C2440_NFCONT_LOCKTIGHT (1<<13) +#define S3C2440_NFCONT_SOFTLOCK (1<<12) +#define S3C2440_NFCONT_ILLEGALACC_EN (1<<10) +#define S3C2440_NFCONT_RNBINT_EN (1<<9) +#define S3C2440_NFCONT_RN_FALLING (1<<8) +#define S3C2440_NFCONT_SPARE_ECCLOCK (1<<6) +#define S3C2440_NFCONT_MAIN_ECCLOCK (1<<5) +#define S3C2440_NFCONT_INITECC (1<<4) +#define S3C2440_NFCONT_nFCE (1<<1) +#define S3C2440_NFCONT_ENABLE (1<<0) + +#define S3C2440_NFSTAT_READY (1<<0) +#define S3C2440_NFSTAT_nCE (1<<1) +#define S3C2440_NFSTAT_RnB_CHANGE (1<<2) +#define S3C2440_NFSTAT_ILLEGAL_ACCESS (1<<3) #endif /* __ASM_ARM_REGS_NAND */ -- cgit v1.2.3 From 4ad3a443c9238c8df68f4519049c3c8d80fe62c2 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 12 May 2005 19:27:13 +0100 Subject: [PATCH] ARM: 2677/1: S3C2440 - UPLL frequency doubled Patch from Ben Dooks S3C2440 UPLL is the same as the S3C2410 UPLL, it is only the MPLL which has an extra multiplication factor of 2 in the multiplier. Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/clock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c index e23f534d4e1..8d986b8401c 100644 --- a/arch/arm/mach-s3c2410/clock.c +++ b/arch/arm/mach-s3c2410/clock.c @@ -478,7 +478,7 @@ static int s3c2440_clk_add(struct sys_device *sysdev) { unsigned long upllcon = __raw_readl(S3C2410_UPLLCON); - s3c2440_clk_upll.rate = s3c2410_get_pll(upllcon, clk_xtal.rate) * 2; + s3c2440_clk_upll.rate = s3c2410_get_pll(upllcon, clk_xtal.rate); printk("S3C2440: Clock Support, UPLL %ld.%03ld MHz\n", print_mhz(s3c2440_clk_upll.rate)); -- cgit v1.2.3 From bfd4e0709fb977e64e27d9255be6e7aeadf4fcd4 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 12 May 2005 19:27:14 +0100 Subject: [PATCH] ARM: 2678/1: S3C2440 - cpu fixes, hdiv divisors and nand dev name Patch from Ben Dooks Fix the setting of hdiv when set to divide-by-2. Thanks to Jeonghoon Yoon for pointing this out. Change name of the NAND device to "s3c2440-nand" as it is not similar enough to the "s3c2410-nand" device. Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/s3c2440.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-s3c2410/s3c2440.c b/arch/arm/mach-s3c2410/s3c2440.c index 9a8cc5ae225..d4c8281b55f 100644 --- a/arch/arm/mach-s3c2410/s3c2440.c +++ b/arch/arm/mach-s3c2410/s3c2440.c @@ -192,9 +192,11 @@ void __init s3c2440_map_io(struct map_desc *mach_desc, int size) iotable_init(s3c2440_iodesc, ARRAY_SIZE(s3c2440_iodesc)); iotable_init(mach_desc, size); + /* rename any peripherals used differing from the s3c2410 */ - s3c_device_i2c.name = "s3c2440-i2c"; + s3c_device_i2c.name = "s3c2440-i2c"; + s3c_device_nand.name = "s3c2440-nand"; /* change irq for watchdog */ @@ -225,7 +227,7 @@ void __init s3c2440_init_clocks(int xtal) break; case S3C2440_CLKDIVN_HDIVN_2: - hdiv = 1; + hdiv = 2; break; case S3C2440_CLKDIVN_HDIVN_4_8: -- cgit v1.2.3 From dfa1b73ffb414b64dc0452260132a090eb25bf52 Mon Sep 17 00:00:00 2001 From: Liu Tao Date: Thu, 12 May 2005 19:40:38 -0400 Subject: [PATCH] drivers/net/amd8111e.c: fix NAPI interrupt in poll This patch makes the netif_rx_complete() and rx_interrupt_enable atomic when exiting the poll() method, so to avoid interrupt in poll. It also fixes the rx interrupt check logic in interrupt handler. Signed-off-by: Liu Tao Signed-off-by: Jeff Garzik --- drivers/net/amd8111e.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index f2e937abf7b..b7dd7260caf 100755 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -738,6 +738,7 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget) short vtag; #endif int rx_pkt_limit = dev->quota; + unsigned long flags; do{ /* process receive packets until we use the quota*/ @@ -841,18 +842,19 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget) /* Receive descriptor is empty now */ dev->quota -= num_rx_pkt; *budget -= num_rx_pkt; + + spin_lock_irqsave(&lp->lock, flags); netif_rx_complete(dev); - /* enable receive interrupt */ writel(VAL0|RINTEN0, mmio + INTEN0); writel(VAL2 | RDMD0, mmio + CMD0); + spin_unlock_irqrestore(&lp->lock, flags); return 0; + rx_not_empty: /* Do not call a netif_rx_complete */ dev->quota -= num_rx_pkt; *budget -= num_rx_pkt; return 1; - - } #else @@ -1261,18 +1263,20 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id, struct pt_regs *reg struct net_device * dev = (struct net_device *) dev_id; struct amd8111e_priv *lp = netdev_priv(dev); void __iomem *mmio = lp->mmio; - unsigned int intr0; + unsigned int intr0, intren0; unsigned int handled = 1; - if(dev == NULL) + if(unlikely(dev == NULL)) return IRQ_NONE; - if (regs) spin_lock (&lp->lock); + spin_lock(&lp->lock); + /* disabling interrupt */ writel(INTREN, mmio + CMD0); /* Read interrupt status */ intr0 = readl(mmio + INT0); + intren0 = readl(mmio + INTEN0); /* Process all the INT event until INTR bit is clear. */ @@ -1293,11 +1297,11 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id, struct pt_regs *reg /* Schedule a polling routine */ __netif_rx_schedule(dev); } - else { + else if (intren0 & RINTEN0) { printk("************Driver bug! \ interrupt while in poll\n"); - /* Fix by disabling interrupts */ - writel(RINT0, mmio + INT0); + /* Fix by disable receive interrupts */ + writel(RINTEN0, mmio + INTEN0); } } #else @@ -1321,7 +1325,7 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id, struct pt_regs *reg err_no_interrupt: writel( VAL0 | INTREN,mmio + CMD0); - if (regs) spin_unlock(&lp->lock); + spin_unlock(&lp->lock); return IRQ_RETVAL(handled); } -- cgit v1.2.3 From e4eff7291c977308989b24fdfc7215a501302e6a Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:38:30 -0700 Subject: [PATCH] e1000: made loopback test robust Added enhanced functionality to the loopback diags to wrap the descriptor rings. Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/e1000/e1000_ethtool.c net-drivers-2.6/drivers/net/e1000.new/e1000_ethtool.c --- drivers/net/e1000/e1000_ethtool.c | 81 ++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 23 deletions(-) diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 0a2ca7c73a4..fae58545346 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -919,7 +919,8 @@ e1000_setup_desc_rings(struct e1000_adapter *adapter) /* Setup Tx descriptor ring and Tx buffers */ - txdr->count = 80; + if(!txdr->count) + txdr->count = E1000_DEFAULT_TXD; size = txdr->count * sizeof(struct e1000_buffer); if(!(txdr->buffer_info = kmalloc(size, GFP_KERNEL))) { @@ -974,7 +975,8 @@ e1000_setup_desc_rings(struct e1000_adapter *adapter) /* Setup Rx descriptor ring and Rx buffers */ - rxdr->count = 80; + if(!rxdr->count) + rxdr->count = E1000_DEFAULT_RXD; size = rxdr->count * sizeof(struct e1000_buffer); if(!(rxdr->buffer_info = kmalloc(size, GFP_KERNEL))) { @@ -1310,31 +1312,62 @@ e1000_run_loopback_test(struct e1000_adapter *adapter) struct e1000_desc_ring *txdr = &adapter->test_tx_ring; struct e1000_desc_ring *rxdr = &adapter->test_rx_ring; struct pci_dev *pdev = adapter->pdev; - int i, ret_val; + int i, j, k, l, lc, good_cnt, ret_val=0; + unsigned long time; E1000_WRITE_REG(&adapter->hw, RDT, rxdr->count - 1); - for(i = 0; i < 64; i++) { - e1000_create_lbtest_frame(txdr->buffer_info[i].skb, 1024); - pci_dma_sync_single_for_device(pdev, txdr->buffer_info[i].dma, - txdr->buffer_info[i].length, - PCI_DMA_TODEVICE); - } - E1000_WRITE_REG(&adapter->hw, TDT, i); - - msec_delay(200); - - i = 0; - do { - pci_dma_sync_single_for_cpu(pdev, rxdr->buffer_info[i].dma, - rxdr->buffer_info[i].length, - PCI_DMA_FROMDEVICE); - - ret_val = e1000_check_lbtest_frame(rxdr->buffer_info[i].skb, - 1024); - i++; - } while (ret_val != 0 && i < 64); + /* Calculate the loop count based on the largest descriptor ring + * The idea is to wrap the largest ring a number of times using 64 + * send/receive pairs during each loop + */ + if(rxdr->count <= txdr->count) + lc = ((txdr->count / 64) * 2) + 1; + else + lc = ((rxdr->count / 64) * 2) + 1; + + k = l = 0; + for(j = 0; j <= lc; j++) { /* loop count loop */ + for(i = 0; i < 64; i++) { /* send the packets */ + e1000_create_lbtest_frame(txdr->buffer_info[i].skb, + 1024); + pci_dma_sync_single_for_device(pdev, + txdr->buffer_info[k].dma, + txdr->buffer_info[k].length, + PCI_DMA_TODEVICE); + if(unlikely(++k == txdr->count)) k = 0; + } + E1000_WRITE_REG(&adapter->hw, TDT, k); + msec_delay(200); + time = jiffies; /* set the start time for the receive */ + good_cnt = 0; + do { /* receive the sent packets */ + pci_dma_sync_single_for_cpu(pdev, + rxdr->buffer_info[l].dma, + rxdr->buffer_info[l].length, + PCI_DMA_FROMDEVICE); + + ret_val = e1000_check_lbtest_frame( + rxdr->buffer_info[l].skb, + 1024); + if(!ret_val) + good_cnt++; + if(unlikely(++l == rxdr->count)) l = 0; + /* time + 20 msecs (200 msecs on 2.4) is more than + * enough time to complete the receives, if it's + * exceeded, break and error off + */ + } while (good_cnt < 64 && jiffies < (time + 20)); + if(good_cnt != 64) { + ret_val = 13; /* ret_val is the same as mis-compare */ + break; + } + if(jiffies >= (time + 2)) { + ret_val = 14; /* error code for time out error */ + break; + } + } /* end loop count loop */ return ret_val; } @@ -1371,6 +1404,8 @@ e1000_link_test(struct e1000_adapter *adapter, uint64_t *data) *data = 1; } else { e1000_check_for_link(&adapter->hw); + if(adapter->hw.autoneg) /* if auto_neg is set wait for it */ + msec_delay(4000); if(!(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) { *data = 1; -- cgit v1.2.3 From df25e164878836196ee93d1a5757867da6eac30e Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:38:43 -0700 Subject: [PATCH] e1000: Fix msec-delay definition to use msleep Fix msec-delay definition in e1000_osdep.h to use msleep Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/e1000/e1000_osdep.h net-drivers-2.6/drivers/net/e1000.new/e1000_osdep.h --- drivers/net/e1000/e1000_osdep.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h index 970c656a517..2efa3b1b64d 100644 --- a/drivers/net/e1000/e1000_osdep.h +++ b/drivers/net/e1000/e1000_osdep.h @@ -42,7 +42,12 @@ #include #ifndef msec_delay -#define msec_delay(x) msleep(x) +#define msec_delay(x) do { if(in_interrupt()) { \ + /* Don't mdelay in interrupt context! */ \ + BUG(); \ + } else { \ + msleep(x); \ + } } while(0) /* Some workarounds require millisecond delays and are run during interrupt * context. Most notably, when establishing link, the phy may need tweaking -- cgit v1.2.3 From fa4f7ef3aaa6cee6b04ebe90266ee893e0b2ce07 Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:39:13 -0700 Subject: [PATCH] e1000: MSI support for PCI-e adapters MSI support for PCI-e adapters Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/e1000/e1000.h net-drivers-2.6/drivers/net/e1000.new/e1000.h --- drivers/net/e1000/e1000.h | 3 +++ drivers/net/e1000/e1000_main.c | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 148930d4e9b..da055520daa 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -257,5 +257,8 @@ struct e1000_adapter { int msg_enable; +#ifdef CONFIG_PCI_MSI + boolean_t have_msi; +#endif }; #endif /* _E1000_H_ */ diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 82549a6fcfb..03e3ec74f3f 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -312,6 +312,16 @@ e1000_up(struct e1000_adapter *adapter) e1000_configure_rx(adapter); e1000_alloc_rx_buffers(adapter); +#ifdef CONFIG_PCI_MSI + if(adapter->hw.mac_type > e1000_82547_rev_2) { + adapter->have_msi = TRUE; + if((err = pci_enable_msi(adapter->pdev))) { + DPRINTK(PROBE, ERR, + "Unable to allocate MSI interrupt Error: %d\n", err); + adapter->have_msi = FALSE; + } + } +#endif if((err = request_irq(adapter->pdev->irq, &e1000_intr, SA_SHIRQ | SA_SAMPLE_RANDOM, netdev->name, netdev))) @@ -333,6 +343,11 @@ e1000_down(struct e1000_adapter *adapter) e1000_irq_disable(adapter); free_irq(adapter->pdev->irq, netdev); +#ifdef CONFIG_PCI_MSI + if(adapter->hw.mac_type > e1000_82547_rev_2 && + adapter->have_msi == TRUE) + pci_disable_msi(adapter->pdev); +#endif del_timer_sync(&adapter->tx_fifo_stall_timer); del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_info_timer); -- cgit v1.2.3 From 5de556249fde97493a4c79dbf8979ace0f76789f Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:39:30 -0700 Subject: [PATCH] e1000: Enable polling before enabling interrupts Enable polling before enabling interrupts -- avoids (in NAPI mode) entering the ISR and returning without doing any work because polling is not enabled. [romieu@fr.zoriel.com] Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/e1000/e1000_main.c net-drivers-2.6/drivers/net/e1000.new/e1000_main.c --- drivers/net/e1000/e1000_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 03e3ec74f3f..9927106b76c 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -328,11 +328,12 @@ e1000_up(struct e1000_adapter *adapter) return err; mod_timer(&adapter->watchdog_timer, jiffies); - e1000_irq_enable(adapter); #ifdef CONFIG_E1000_NAPI netif_poll_enable(netdev); #endif + e1000_irq_enable(adapter); + return 0; } -- cgit v1.2.3 From 4e48a2b91d408357cb0747151d8db5368ac8f1d0 Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:39:53 -0700 Subject: [PATCH] e1000: Fix kernel panic with 82541 LOM Fix kernel panic with 82541 LOM when using a 100M cable Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/e1000/e1000_main.c net-drivers-2.6/drivers/net/e1000.new/e1000_main.c --- drivers/net/e1000/e1000_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 9927106b76c..9c6c1fbbc41 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -372,6 +372,7 @@ e1000_down(struct e1000_adapter *adapter) e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg); mii_reg |= MII_CR_POWER_DOWN; e1000_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg); + mdelay(1); } } -- cgit v1.2.3 From 2701234fc0372630457e3da14e36cde53c57d12e Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:40:28 -0700 Subject: [PATCH] e1000: Delay clean-up of last Tx packet Delay clean-up of last Tx packet to fix pre-mature writeback issue of Tx descriptors only when TSO is enabled Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/e1000/e1000_main.c net-drivers-2.6/drivers/net/e1000.new/e1000_main.c --- drivers/net/e1000/e1000_main.c | 43 ++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 9c6c1fbbc41..4a8c069e6c7 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2384,11 +2384,10 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) eop_desc = E1000_TX_DESC(*tx_ring, eop); while(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { - /* pre-mature writeback of Tx descriptors */ - /* clear (free buffers and unmap pci_mapping) */ - /* previous_buffer_info */ + /* Premature writeback of Tx descriptors clear (free buffers + * and unmap pci_mapping) previous_buffer_info */ if (likely(adapter->previous_buffer_info.skb != NULL)) { - e1000_unmap_and_free_tx_resource(adapter, + e1000_unmap_and_free_tx_resource(adapter, &adapter->previous_buffer_info); } @@ -2397,20 +2396,25 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) buffer_info = &tx_ring->buffer_info[i]; cleaned = (i == eop); - /* pre-mature writeback of Tx descriptors */ - /* save the cleaning of the this for the */ - /* next iteration */ - if (cleaned) { - memcpy(&adapter->previous_buffer_info, - buffer_info, - sizeof(struct e1000_buffer)); - memset(buffer_info, - 0, - sizeof(struct e1000_buffer)); +#ifdef NETIF_F_TSO + if (!(netdev->features & NETIF_F_TSO)) { +#endif + e1000_unmap_and_free_tx_resource(adapter, + buffer_info); +#ifdef NETIF_F_TSO } else { - e1000_unmap_and_free_tx_resource(adapter, - buffer_info); + if (cleaned) { + memcpy(&adapter->previous_buffer_info, + buffer_info, + sizeof(struct e1000_buffer)); + memset(buffer_info, 0, + sizeof(struct e1000_buffer)); + } else { + e1000_unmap_and_free_tx_resource( + adapter, buffer_info); + } } +#endif tx_desc->buffer_addr = 0; tx_desc->lower.data = 0; @@ -2443,7 +2447,14 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) !(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF)) netif_stop_queue(netdev); } +#ifdef NETIF_F_TSO + if( unlikely(!(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) && + time_after(jiffies, adapter->previous_buffer_info.time_stamp + HZ))) + e1000_unmap_and_free_tx_resource( + adapter, &adapter->previous_buffer_info); + +#endif return cleaned; } -- cgit v1.2.3 From 70b8f1e16a788eccdd36f39679774b1a08a6ba55 Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:40:40 -0700 Subject: [PATCH] e1000: Dump information on Tx ring Dump information on Tx ring when 'NETDEV: Watchdog' condition is reached Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/e1000/e1000_main.c net-drivers-2.6/drivers/net/e1000.new/e1000_main.c --- drivers/net/e1000/e1000_main.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 4a8c069e6c7..b5811f4f88f 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2442,10 +2442,37 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) /* detect a transmit hang in hardware, this serializes the * check with the clearing of time_stamp and movement of i */ adapter->detect_tx_hung = FALSE; - if(tx_ring->buffer_info[i].dma && - time_after(jiffies, tx_ring->buffer_info[i].time_stamp + HZ) && - !(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF)) + if (tx_ring->buffer_info[i].dma && + time_after(jiffies, tx_ring->buffer_info[i].time_stamp + HZ) + && !(E1000_READ_REG(&adapter->hw, STATUS) & + E1000_STATUS_TXOFF)) { + + /* detected Tx unit hang */ + i = tx_ring->next_to_clean; + eop = tx_ring->buffer_info[i].next_to_watch; + eop_desc = E1000_TX_DESC(*tx_ring, eop); + DPRINTK(TX_ERR, ERR, "Detected Tx Unit Hang\n" + " TDH <%x>\n" + " TDT <%x>\n" + " next_to_use <%x>\n" + " next_to_clean <%x>\n" + "buffer_info[next_to_clean]\n" + " dma <%llx>\n" + " time_stamp <%lx>\n" + " next_to_watch <%x>\n" + " jiffies <%lx>\n" + " next_to_watch.status <%x>\n", + E1000_READ_REG(&adapter->hw, TDH), + E1000_READ_REG(&adapter->hw, TDT), + tx_ring->next_to_use, + i, + tx_ring->buffer_info[i].dma, + tx_ring->buffer_info[i].time_stamp, + eop, + jiffies, + eop_desc->upper.fields.status); netif_stop_queue(netdev); + } } #ifdef NETIF_F_TSO -- cgit v1.2.3 From 6d9157577d926d2a83fe8d4914c0cc216deb5842 Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:41:11 -0700 Subject: [PATCH] e1000:Fix computation of netdev stats from controller stats counters Fix computation of netdev stats from controller stats counters - from sfeldma@pobox.com Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/e1000/e1000_main.c net-drivers-2.6/drivers/net/e1000.new/e1000_main.c --- drivers/net/e1000/e1000_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index b5811f4f88f..ed1e57ac755 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2230,9 +2230,9 @@ e1000_update_stats(struct e1000_adapter *adapter) adapter->net_stats.rx_errors = adapter->stats.rxerrc + adapter->stats.crcerrs + adapter->stats.algnerrc + - adapter->stats.rlec + adapter->stats.rnbc + - adapter->stats.mpc + adapter->stats.cexterr; - adapter->net_stats.rx_dropped = adapter->stats.rnbc; + adapter->stats.rlec + adapter->stats.mpc + + adapter->stats.cexterr; + adapter->net_stats.rx_dropped = adapter->stats.mpc; adapter->net_stats.rx_length_errors = adapter->stats.rlec; adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc; -- cgit v1.2.3 From a4cb847dac40577dd751a4deb4085ed080780679 Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:41:28 -0700 Subject: [PATCH] e1000: e1000 stops working after resume e1000 stops working after resume, call pci_enable_device after pci_restore_state - Modified Andrew Morton's patch Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/e1000/e1000_main.c net-drivers-2.6/drivers/net/e1000.new/e1000_main.c --- drivers/net/e1000/e1000_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index ed1e57ac755..479915a9f0f 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -3173,8 +3173,7 @@ e1000_resume(struct pci_dev *pdev) pci_set_power_state(pdev, 0); pci_restore_state(pdev); ret = pci_enable_device(pdev); - if (pdev->is_busmaster) - pci_set_master(pdev); + pci_set_master(pdev); pci_enable_wake(pdev, 3, 0); pci_enable_wake(pdev, 4, 0); /* 4 == D3 cold */ -- cgit v1.2.3 From 97338bde27d97347bc83203d6ac5e93be1ebcd03 Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:41:46 -0700 Subject: [PATCH] e1000: Implement a workaround for 82546 errata 10 Implement 82546 errata 10 -- first Tx descriptor cannot have more than 2015 byte of data in it or it could hang the transmitter. Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/e1000/e1000_main.c net-drivers-2.6/drivers/net/e1000.new/e1000_main.c --- drivers/net/e1000/e1000_main.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 479915a9f0f..e54890aff5f 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -1777,6 +1777,15 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb, if(unlikely(mss && !nr_frags && size == len && size > 8)) size -= 4; #endif + /* work-around for errata 10 and it applies + * to all controllers in PCI-X mode + * The fix is to make sure that the first descriptor of a + * packet is smaller than 2048 - 16 - 16 (or 2016) bytes + */ + if(unlikely((adapter->hw.bus_type == e1000_bus_type_pcix) && + (size > 2015) && count == 0)) + size = 2015; + /* Workaround for potential 82544 hang in PCI-X. Avoid * terminating buffers within evenly-aligned dwords. */ if(unlikely(adapter->pcix_82544 && @@ -1979,6 +1988,13 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if(adapter->pcix_82544) count++; + /* work-around for errata 10 and it applies to all controllers + * in PCI-X mode, so add one more descriptor to the count + */ + if(unlikely((adapter->hw.bus_type == e1000_bus_type_pcix) && + (len > 2015))) + count++; + nr_frags = skb_shinfo(skb)->nr_frags; for(f = 0; f < nr_frags; f++) count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size, -- cgit v1.2.3 From f1d2e4905eed4b13c3ba56ac6d30c283be996963 Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:42:04 -0700 Subject: [PATCH] e1000:Removed redundant statement in e1000_clean_tx_irq Removed redundant statement in e1000_clean_tx_irq Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/e1000/e1000_main.c net-drivers-2.6/drivers/net/e1000.new/e1000_main.c --- drivers/net/e1000/e1000_main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index e54890aff5f..0fec670e51e 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2436,7 +2436,6 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) tx_desc->lower.data = 0; tx_desc->upper.data = 0; - cleaned = (i == eop); if(unlikely(++i == tx_ring->count)) i = 0; } -- cgit v1.2.3 From f0d11ed0b0650d2f93f56f65167c10a577c16c88 Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:43:28 -0700 Subject: [PATCH] e1000: Modified e1000_clean: exit poll Modified e1000_clean:: exit poll if no Tx and work_done == 0 Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/e1000/e1000_main.c net-drivers-2.6/drivers/net/e1000.new/e1000_main.c --- drivers/net/e1000/e1000_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 0fec670e51e..4cdf371961e 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2368,9 +2368,8 @@ e1000_clean(struct net_device *netdev, int *budget) *budget -= work_done; netdev->quota -= work_done; - /* if no Tx and not enough Rx work done, exit the polling mode */ - if((!tx_cleaned && (work_done < work_to_do)) || - !netif_running(netdev)) { + /* If no Tx and no Rx work done, exit the polling mode */ + if ((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) { netif_rx_complete(netdev); e1000_irq_enable(adapter); return 0; -- cgit v1.2.3 From 2d7edb923a823660b081bd4c660300ee19adca8d Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:43:52 -0700 Subject: [PATCH] e1000:82573 specific code & packet split code 82573 specific code & packet split code Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/e1000/e1000.h net-drivers-2.6/drivers/net/e1000.new/e1000.h --- drivers/net/e1000/e1000.h | 26 + drivers/net/e1000/e1000_hw.c | 2132 ++++++++++++++++++++++++++++++--------- drivers/net/e1000/e1000_hw.h | 568 ++++++++++- drivers/net/e1000/e1000_main.c | 804 ++++++++++++--- drivers/net/e1000/e1000_osdep.h | 23 + 5 files changed, 2956 insertions(+), 597 deletions(-) diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index da055520daa..19858c26753 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -112,6 +112,8 @@ struct e1000_adapter; #define E1000_MAX_82544_RXD 4096 /* Supported Rx Buffer Sizes */ +#define E1000_RXBUFFER_128 128 /* Used for packet split */ +#define E1000_RXBUFFER_256 256 /* Used for packet split */ #define E1000_RXBUFFER_2048 2048 #define E1000_RXBUFFER_4096 4096 #define E1000_RXBUFFER_8192 8192 @@ -146,6 +148,10 @@ struct e1000_adapter; #define E1000_MASTER_SLAVE e1000_ms_hw_default #endif +#define E1000_MNG_VLAN_NONE -1 +/* Number of packet split data buffers (not including the header buffer) */ +#define PS_PAGE_BUFFERS MAX_PS_BUFFERS-1 + /* only works for sizes that are powers of 2 */ #define E1000_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1))) @@ -159,6 +165,9 @@ struct e1000_buffer { uint16_t next_to_watch; }; +struct e1000_ps_page { struct page *ps_page[MAX_PS_BUFFERS]; }; +struct e1000_ps_page_dma { uint64_t ps_page_dma[MAX_PS_BUFFERS]; }; + struct e1000_desc_ring { /* pointer to the descriptor ring memory */ void *desc; @@ -174,12 +183,19 @@ struct e1000_desc_ring { unsigned int next_to_clean; /* array of buffer information structs */ struct e1000_buffer *buffer_info; + /* arrays of page information for packet split */ + struct e1000_ps_page *ps_page; + struct e1000_ps_page_dma *ps_page_dma; }; #define E1000_DESC_UNUSED(R) \ ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \ (R)->next_to_clean - (R)->next_to_use - 1) +#define E1000_RX_DESC_PS(R, i) \ + (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) +#define E1000_RX_DESC_EXT(R, i) \ + (&(((union e1000_rx_desc_extended *)((R).desc))[i])) #define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i])) #define E1000_RX_DESC(R, i) E1000_GET_DESC(R, i, e1000_rx_desc) #define E1000_TX_DESC(R, i) E1000_GET_DESC(R, i, e1000_tx_desc) @@ -192,6 +208,7 @@ struct e1000_adapter { struct timer_list watchdog_timer; struct timer_list phy_info_timer; struct vlan_group *vlgrp; + uint16_t mng_vlan_id; uint32_t bd_number; uint32_t rx_buffer_len; uint32_t part_num; @@ -228,14 +245,23 @@ struct e1000_adapter { boolean_t detect_tx_hung; /* RX */ +#ifdef CONFIG_E1000_NAPI + boolean_t (*clean_rx) (struct e1000_adapter *adapter, int *work_done, + int work_to_do); +#else + boolean_t (*clean_rx) (struct e1000_adapter *adapter); +#endif + void (*alloc_rx_buf) (struct e1000_adapter *adapter); struct e1000_desc_ring rx_ring; uint64_t hw_csum_err; uint64_t hw_csum_good; uint32_t rx_int_delay; uint32_t rx_abs_int_delay; boolean_t rx_csum; + boolean_t rx_ps; uint32_t gorcl; uint64_t gorcl_old; + uint16_t rx_ps_bsize0; /* Interrupt Throttle Rate */ uint32_t itr; diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 786a9b93565..b7a7ceb67f4 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -63,10 +63,11 @@ static uint16_t e1000_shift_in_ee_bits(struct e1000_hw *hw, uint16_t count); static int32_t e1000_acquire_eeprom(struct e1000_hw *hw); static void e1000_release_eeprom(struct e1000_hw *hw); static void e1000_standby_eeprom(struct e1000_hw *hw); -static int32_t e1000_id_led_init(struct e1000_hw * hw); static int32_t e1000_set_vco_speed(struct e1000_hw *hw); static int32_t e1000_polarity_reversal_workaround(struct e1000_hw *hw); static int32_t e1000_set_phy_mode(struct e1000_hw *hw); +static int32_t e1000_host_if_read_cookie(struct e1000_hw *hw, uint8_t *buffer); +static uint8_t e1000_calculate_mng_checksum(char *buffer, uint32_t length); /* IGP cable length table */ static const @@ -80,6 +81,17 @@ uint16_t e1000_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] = 100, 100, 100, 100, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120}; +static const +uint16_t e1000_igp_2_cable_length_table[IGP02E1000_AGC_LENGTH_TABLE_SIZE] = + { 8, 13, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, + 22, 24, 27, 30, 32, 35, 37, 40, 42, 44, 47, 49, 51, 54, 56, 58, + 32, 35, 38, 41, 44, 47, 50, 53, 55, 58, 61, 63, 66, 69, 71, 74, + 43, 47, 51, 54, 58, 61, 64, 67, 71, 74, 77, 80, 82, 85, 88, 90, + 57, 62, 66, 70, 74, 77, 81, 85, 88, 91, 94, 97, 100, 103, 106, 108, + 73, 78, 82, 87, 91, 95, 98, 102, 105, 109, 112, 114, 117, 119, 122, 124, + 91, 96, 101, 105, 109, 113, 116, 119, 122, 125, 127, 128, 128, 128, 128, 128, + 108, 113, 117, 121, 124, 127, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}; + /****************************************************************************** * Set the phy type member in the hw struct. @@ -91,10 +103,14 @@ e1000_set_phy_type(struct e1000_hw *hw) { DEBUGFUNC("e1000_set_phy_type"); + if(hw->mac_type == e1000_undefined) + return -E1000_ERR_PHY_TYPE; + switch(hw->phy_id) { case M88E1000_E_PHY_ID: case M88E1000_I_PHY_ID: case M88E1011_I_PHY_ID: + case M88E1111_I_PHY_ID: hw->phy_type = e1000_phy_m88; break; case IGP01E1000_I_PHY_ID: @@ -271,6 +287,7 @@ e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82546GB_FIBER: case E1000_DEV_ID_82546GB_SERDES: case E1000_DEV_ID_82546GB_PCIE: + case E1000_DEV_ID_82546GB_QUAD_COPPER: hw->mac_type = e1000_82546_rev_3; break; case E1000_DEV_ID_82541EI: @@ -289,12 +306,19 @@ e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82547GI: hw->mac_type = e1000_82547_rev_2; break; + case E1000_DEV_ID_82573E: + case E1000_DEV_ID_82573E_IAMT: + hw->mac_type = e1000_82573; + break; default: /* Should never have loaded on this device */ return -E1000_ERR_MAC_TYPE; } switch(hw->mac_type) { + case e1000_82573: + hw->eeprom_semaphore_present = TRUE; + /* fall through */ case e1000_82541: case e1000_82547: case e1000_82541_rev_2: @@ -360,6 +384,9 @@ e1000_reset_hw(struct e1000_hw *hw) uint32_t icr; uint32_t manc; uint32_t led_ctrl; + uint32_t timeout; + uint32_t extcnf_ctrl; + int32_t ret_val; DEBUGFUNC("e1000_reset_hw"); @@ -369,6 +396,15 @@ e1000_reset_hw(struct e1000_hw *hw) e1000_pci_clear_mwi(hw); } + if(hw->bus_type == e1000_bus_type_pci_express) { + /* Prevent the PCI-E bus from sticking if there is no TLP connection + * on the last TLP read/write transaction when MAC is reset. + */ + if(e1000_disable_pciex_master(hw) != E1000_SUCCESS) { + DEBUGOUT("PCI-E Master disable polling has failed.\n"); + } + } + /* Clear interrupt mask to stop board from generating interrupts */ DEBUGOUT("Masking off all interrupts\n"); E1000_WRITE_REG(hw, IMC, 0xffffffff); @@ -393,10 +429,32 @@ e1000_reset_hw(struct e1000_hw *hw) /* Must reset the PHY before resetting the MAC */ if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) { - E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_PHY_RST)); + E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_PHY_RST)); msec_delay(5); } + /* Must acquire the MDIO ownership before MAC reset. + * Ownership defaults to firmware after a reset. */ + if(hw->mac_type == e1000_82573) { + timeout = 10; + + extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL); + extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; + + do { + E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl); + extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL); + + if(extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP) + break; + else + extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; + + msec_delay(2); + timeout--; + } while(timeout); + } + /* Issue a global reset to the MAC. This will reset the chip's * transmit, receive, DMA, and link units. It will not effect * the current PCI configuration. The global reset bit is self- @@ -450,6 +508,18 @@ e1000_reset_hw(struct e1000_hw *hw) /* Wait for EEPROM reload */ msec_delay(20); break; + case e1000_82573: + udelay(10); + ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_EE_RST; + E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); + E1000_WRITE_FLUSH(hw); + /* fall through */ + ret_val = e1000_get_auto_rd_done(hw); + if(ret_val) + /* We don't want to continue accessing MAC registers. */ + return ret_val; + break; default: /* Wait for EEPROM reload (it happens automatically) */ msec_delay(5); @@ -457,7 +527,7 @@ e1000_reset_hw(struct e1000_hw *hw) } /* Disable HW ARPs on ASF enabled adapters */ - if(hw->mac_type >= e1000_82540) { + if(hw->mac_type >= e1000_82540 && hw->mac_type <= e1000_82547_rev_2) { manc = E1000_READ_REG(hw, MANC); manc &= ~(E1000_MANC_ARP_EN); E1000_WRITE_REG(hw, MANC, manc); @@ -510,6 +580,8 @@ e1000_init_hw(struct e1000_hw *hw) uint16_t pcix_stat_hi_word; uint16_t cmd_mmrbc; uint16_t stat_mmrbc; + uint32_t mta_size; + DEBUGFUNC("e1000_init_hw"); /* Initialize Identification LED */ @@ -524,8 +596,8 @@ e1000_init_hw(struct e1000_hw *hw) /* Disabling VLAN filtering. */ DEBUGOUT("Initializing the IEEE VLAN\n"); - E1000_WRITE_REG(hw, VET, 0); - + if (hw->mac_type < e1000_82545_rev_3) + E1000_WRITE_REG(hw, VET, 0); e1000_clear_vfta(hw); /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */ @@ -553,14 +625,16 @@ e1000_init_hw(struct e1000_hw *hw) /* Zero out the Multicast HASH table */ DEBUGOUT("Zeroing the MTA\n"); - for(i = 0; i < E1000_MC_TBL_SIZE; i++) + mta_size = E1000_MC_TBL_SIZE; + for(i = 0; i < mta_size; i++) E1000_WRITE_REG_ARRAY(hw, MTA, i, 0); /* Set the PCI priority bit correctly in the CTRL register. This * determines if the adapter gives priority to receives, or if it - * gives equal priority to transmits and receives. + * gives equal priority to transmits and receives. Valid only on + * 82542 and 82543 silicon. */ - if(hw->dma_fairness) { + if(hw->dma_fairness && hw->mac_type <= e1000_82543) { ctrl = E1000_READ_REG(hw, CTRL); E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR); } @@ -598,9 +672,21 @@ e1000_init_hw(struct e1000_hw *hw) if(hw->mac_type > e1000_82544) { ctrl = E1000_READ_REG(hw, TXDCTL); ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB; + switch (hw->mac_type) { + default: + break; + case e1000_82573: + ctrl |= E1000_TXDCTL_COUNT_DESC; + break; + } E1000_WRITE_REG(hw, TXDCTL, ctrl); } + if (hw->mac_type == e1000_82573) { + e1000_enable_tx_pkt_filtering(hw); + } + + /* Clear all of the statistics registers (clear on read). It is * important that we do this after we have tried to establish link * because the symbol error count will increment wildly if there @@ -679,7 +765,7 @@ e1000_setup_link(struct e1000_hw *hw) * control setting, then the variable hw->fc will * be initialized based on a value in the EEPROM. */ - if(e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data) < 0) { + if(e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data)) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -736,6 +822,7 @@ e1000_setup_link(struct e1000_hw *hw) E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW); E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH); E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE); + E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time); /* Set the flow control receive threshold registers. Normally, @@ -906,20 +993,18 @@ e1000_setup_fiber_serdes_link(struct e1000_hw *hw) } /****************************************************************************** -* Detects which PHY is present and the speed and duplex +* Make sure we have a valid PHY and change PHY mode before link setup. * * hw - Struct containing variables accessed by shared code ******************************************************************************/ static int32_t -e1000_setup_copper_link(struct e1000_hw *hw) +e1000_copper_link_preconfig(struct e1000_hw *hw) { uint32_t ctrl; - uint32_t led_ctrl; int32_t ret_val; - uint16_t i; uint16_t phy_data; - DEBUGFUNC("e1000_setup_copper_link"); + DEBUGFUNC("e1000_copper_link_preconfig"); ctrl = E1000_READ_REG(hw, CTRL); /* With 82543, we need to force speed and duplex on the MAC equal to what @@ -933,7 +1018,9 @@ e1000_setup_copper_link(struct e1000_hw *hw) } else { ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU); E1000_WRITE_REG(hw, CTRL, ctrl); - e1000_phy_hw_reset(hw); + ret_val = e1000_phy_hw_reset(hw); + if(ret_val) + return ret_val; } /* Make sure we have a valid PHY */ @@ -961,354 +1048,452 @@ e1000_setup_copper_link(struct e1000_hw *hw) hw->mac_type == e1000_82541_rev_2 || hw->mac_type == e1000_82547_rev_2) hw->phy_reset_disable = FALSE; - if(!hw->phy_reset_disable) { - if (hw->phy_type == e1000_phy_igp) { - - ret_val = e1000_phy_reset(hw); - if(ret_val) { - DEBUGOUT("Error Resetting the PHY\n"); - return ret_val; - } - - /* Wait 10ms for MAC to configure PHY from eeprom settings */ - msec_delay(15); + return E1000_SUCCESS; +} - /* Configure activity LED after PHY reset */ - led_ctrl = E1000_READ_REG(hw, LEDCTL); - led_ctrl &= IGP_ACTIVITY_LED_MASK; - led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); - E1000_WRITE_REG(hw, LEDCTL, led_ctrl); - /* disable lplu d3 during driver init */ - ret_val = e1000_set_d3_lplu_state(hw, FALSE); - if(ret_val) { - DEBUGOUT("Error Disabling LPLU D3\n"); - return ret_val; - } +/******************************************************************** +* Copper link setup for e1000_phy_igp series. +* +* hw - Struct containing variables accessed by shared code +*********************************************************************/ +static int32_t +e1000_copper_link_igp_setup(struct e1000_hw *hw) +{ + uint32_t led_ctrl; + int32_t ret_val; + uint16_t phy_data; - /* Configure mdi-mdix settings */ - ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, - &phy_data); - if(ret_val) - return ret_val; + DEBUGFUNC("e1000_copper_link_igp_setup"); - if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) { - hw->dsp_config_state = e1000_dsp_config_disabled; - /* Force MDI for earlier revs of the IGP PHY */ - phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX | - IGP01E1000_PSCR_FORCE_MDI_MDIX); - hw->mdix = 1; + if (hw->phy_reset_disable) + return E1000_SUCCESS; + + ret_val = e1000_phy_reset(hw); + if (ret_val) { + DEBUGOUT("Error Resetting the PHY\n"); + return ret_val; + } - } else { - hw->dsp_config_state = e1000_dsp_config_enabled; - phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX; - - switch (hw->mdix) { - case 1: - phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; - break; - case 2: - phy_data |= IGP01E1000_PSCR_FORCE_MDI_MDIX; - break; - case 0: - default: - phy_data |= IGP01E1000_PSCR_AUTO_MDIX; - break; - } - } - ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, - phy_data); - if(ret_val) - return ret_val; + /* Wait 10ms for MAC to configure PHY from eeprom settings */ + msec_delay(15); - /* set auto-master slave resolution settings */ - if(hw->autoneg) { - e1000_ms_type phy_ms_setting = hw->master_slave; + /* Configure activity LED after PHY reset */ + led_ctrl = E1000_READ_REG(hw, LEDCTL); + led_ctrl &= IGP_ACTIVITY_LED_MASK; + led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); + E1000_WRITE_REG(hw, LEDCTL, led_ctrl); - if(hw->ffe_config_state == e1000_ffe_config_active) - hw->ffe_config_state = e1000_ffe_config_enabled; + /* disable lplu d3 during driver init */ + ret_val = e1000_set_d3_lplu_state(hw, FALSE); + if (ret_val) { + DEBUGOUT("Error Disabling LPLU D3\n"); + return ret_val; + } - if(hw->dsp_config_state == e1000_dsp_config_activated) - hw->dsp_config_state = e1000_dsp_config_enabled; + /* disable lplu d0 during driver init */ + ret_val = e1000_set_d0_lplu_state(hw, FALSE); + if (ret_val) { + DEBUGOUT("Error Disabling LPLU D0\n"); + return ret_val; + } + /* Configure mdi-mdix settings */ + ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data); + if (ret_val) + return ret_val; - /* when autonegotiation advertisment is only 1000Mbps then we - * should disable SmartSpeed and enable Auto MasterSlave - * resolution as hardware default. */ - if(hw->autoneg_advertised == ADVERTISE_1000_FULL) { - /* Disable SmartSpeed */ - ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, - &phy_data); - if(ret_val) - return ret_val; - phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = e1000_write_phy_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - phy_data); - if(ret_val) - return ret_val; - /* Set auto Master/Slave resolution process */ - ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data); - if(ret_val) - return ret_val; - phy_data &= ~CR_1000T_MS_ENABLE; - ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data); - if(ret_val) - return ret_val; - } + if ((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) { + hw->dsp_config_state = e1000_dsp_config_disabled; + /* Force MDI for earlier revs of the IGP PHY */ + phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX | IGP01E1000_PSCR_FORCE_MDI_MDIX); + hw->mdix = 1; - ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data); - if(ret_val) - return ret_val; + } else { + hw->dsp_config_state = e1000_dsp_config_enabled; + phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX; - /* load defaults for future use */ - hw->original_master_slave = (phy_data & CR_1000T_MS_ENABLE) ? - ((phy_data & CR_1000T_MS_VALUE) ? - e1000_ms_force_master : - e1000_ms_force_slave) : - e1000_ms_auto; - - switch (phy_ms_setting) { - case e1000_ms_force_master: - phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE); - break; - case e1000_ms_force_slave: - phy_data |= CR_1000T_MS_ENABLE; - phy_data &= ~(CR_1000T_MS_VALUE); - break; - case e1000_ms_auto: - phy_data &= ~CR_1000T_MS_ENABLE; - default: - break; - } - ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data); - if(ret_val) - return ret_val; - } - } else { - /* Enable CRS on TX. This must be set for half-duplex operation. */ - ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, - &phy_data); - if(ret_val) - return ret_val; + switch (hw->mdix) { + case 1: + phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; + break; + case 2: + phy_data |= IGP01E1000_PSCR_FORCE_MDI_MDIX; + break; + case 0: + default: + phy_data |= IGP01E1000_PSCR_AUTO_MDIX; + break; + } + } + ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data); + if(ret_val) + return ret_val; - phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + /* set auto-master slave resolution settings */ + if(hw->autoneg) { + e1000_ms_type phy_ms_setting = hw->master_slave; - /* Options: - * MDI/MDI-X = 0 (default) - * 0 - Auto for all speeds - * 1 - MDI mode - * 2 - MDI-X mode - * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) - */ - phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; + if(hw->ffe_config_state == e1000_ffe_config_active) + hw->ffe_config_state = e1000_ffe_config_enabled; - switch (hw->mdix) { - case 1: - phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE; - break; - case 2: - phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE; - break; - case 3: - phy_data |= M88E1000_PSCR_AUTO_X_1000T; - break; - case 0: - default: - phy_data |= M88E1000_PSCR_AUTO_X_MODE; - break; - } + if(hw->dsp_config_state == e1000_dsp_config_activated) + hw->dsp_config_state = e1000_dsp_config_enabled; - /* Options: - * disable_polarity_correction = 0 (default) - * Automatic Correction for Reversed Cable Polarity - * 0 - Disabled - * 1 - Enabled - */ - phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; - if(hw->disable_polarity_correction == 1) - phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; - ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, - phy_data); + /* when autonegotiation advertisment is only 1000Mbps then we + * should disable SmartSpeed and enable Auto MasterSlave + * resolution as hardware default. */ + if(hw->autoneg_advertised == ADVERTISE_1000_FULL) { + /* Disable SmartSpeed */ + ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data); if(ret_val) return ret_val; - - /* Force TX_CLK in the Extended PHY Specific Control Register - * to 25MHz clock. - */ - ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, - &phy_data); + phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1000_write_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + phy_data); if(ret_val) return ret_val; + /* Set auto Master/Slave resolution process */ + ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data); + if(ret_val) + return ret_val; + phy_data &= ~CR_1000T_MS_ENABLE; + ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data); + if(ret_val) + return ret_val; + } - phy_data |= M88E1000_EPSCR_TX_CLK_25; + ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data); + if(ret_val) + return ret_val; - if (hw->phy_revision < M88E1011_I_REV_4) { - /* Configure Master and Slave downshift values */ - phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | - M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK); - phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | - M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X); - ret_val = e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, - phy_data); - if(ret_val) - return ret_val; - } + /* load defaults for future use */ + hw->original_master_slave = (phy_data & CR_1000T_MS_ENABLE) ? + ((phy_data & CR_1000T_MS_VALUE) ? + e1000_ms_force_master : + e1000_ms_force_slave) : + e1000_ms_auto; - /* SW Reset the PHY so all changes take effect */ - ret_val = e1000_phy_reset(hw); - if(ret_val) { - DEBUGOUT("Error Resetting the PHY\n"); - return ret_val; - } + switch (phy_ms_setting) { + case e1000_ms_force_master: + phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE); + break; + case e1000_ms_force_slave: + phy_data |= CR_1000T_MS_ENABLE; + phy_data &= ~(CR_1000T_MS_VALUE); + break; + case e1000_ms_auto: + phy_data &= ~CR_1000T_MS_ENABLE; + default: + break; + } + ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data); + if(ret_val) + return ret_val; } - /* Options: - * autoneg = 1 (default) - * PHY will advertise value(s) parsed from - * autoneg_advertised and fc - * autoneg = 0 - * PHY will be set to 10H, 10F, 100H, or 100F - * depending on value parsed from forced_speed_duplex. - */ + return E1000_SUCCESS; +} - /* Is autoneg enabled? This is enabled by default or by software - * override. If so, call e1000_phy_setup_autoneg routine to parse the - * autoneg_advertised and fc options. If autoneg is NOT enabled, then - * the user should have provided a speed/duplex override. If so, then - * call e1000_phy_force_speed_duplex to parse and set this up. - */ - if(hw->autoneg) { - /* Perform some bounds checking on the hw->autoneg_advertised - * parameter. If this variable is zero, then set it to the default. - */ - hw->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT; - /* If autoneg_advertised is zero, we assume it was not defaulted - * by the calling code so we set to advertise full capability. - */ - if(hw->autoneg_advertised == 0) - hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT; +/******************************************************************** +* Copper link setup for e1000_phy_m88 series. +* +* hw - Struct containing variables accessed by shared code +*********************************************************************/ +static int32_t +e1000_copper_link_mgp_setup(struct e1000_hw *hw) +{ + int32_t ret_val; + uint16_t phy_data; - DEBUGOUT("Reconfiguring auto-neg advertisement params\n"); - ret_val = e1000_phy_setup_autoneg(hw); - if(ret_val) { - DEBUGOUT("Error Setting up Auto-Negotiation\n"); - return ret_val; - } - DEBUGOUT("Restarting Auto-Neg\n"); + DEBUGFUNC("e1000_copper_link_mgp_setup"); - /* Restart auto-negotiation by setting the Auto Neg Enable bit and - * the Auto Neg Restart bit in the PHY control register. - */ - ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data); - if(ret_val) - return ret_val; + if(hw->phy_reset_disable) + return E1000_SUCCESS; + + /* Enable CRS on TX. This must be set for half-duplex operation. */ + ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + if(ret_val) + return ret_val; - phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); - ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data); - if(ret_val) - return ret_val; + phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; - /* Does the user want to wait for Auto-Neg to complete here, or - * check at a later time (for example, callback routine). - */ - if(hw->wait_autoneg_complete) { - ret_val = e1000_wait_autoneg(hw); - if(ret_val) { - DEBUGOUT("Error while waiting for autoneg to complete\n"); - return ret_val; - } - } - hw->get_link_status = TRUE; - } else { - DEBUGOUT("Forcing speed and duplex\n"); - ret_val = e1000_phy_force_speed_duplex(hw); - if(ret_val) { - DEBUGOUT("Error Forcing Speed and Duplex\n"); - return ret_val; - } - } - } /* !hw->phy_reset_disable */ + /* Options: + * MDI/MDI-X = 0 (default) + * 0 - Auto for all speeds + * 1 - MDI mode + * 2 - MDI-X mode + * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) + */ + phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; - /* Check link status. Wait up to 100 microseconds for link to become - * valid. + switch (hw->mdix) { + case 1: + phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE; + break; + case 2: + phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE; + break; + case 3: + phy_data |= M88E1000_PSCR_AUTO_X_1000T; + break; + case 0: + default: + phy_data |= M88E1000_PSCR_AUTO_X_MODE; + break; + } + + /* Options: + * disable_polarity_correction = 0 (default) + * Automatic Correction for Reversed Cable Polarity + * 0 - Disabled + * 1 - Enabled */ - for(i = 0; i < 10; i++) { - ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data); + phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; + if(hw->disable_polarity_correction == 1) + phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; + ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); if(ret_val) return ret_val; - ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data); + + /* Force TX_CLK in the Extended PHY Specific Control Register + * to 25MHz clock. + */ + ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); + if(ret_val) + return ret_val; + + phy_data |= M88E1000_EPSCR_TX_CLK_25; + + if (hw->phy_revision < M88E1011_I_REV_4) { + /* Configure Master and Slave downshift values */ + phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | + M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK); + phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | + M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X); + ret_val = e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); if(ret_val) return ret_val; + } - if(phy_data & MII_SR_LINK_STATUS) { - /* We have link, so we need to finish the config process: - * 1) Set up the MAC to the current PHY speed/duplex - * if we are on 82543. If we - * are on newer silicon, we only need to configure - * collision distance in the Transmit Control Register. - * 2) Set up flow control on the MAC to that established with - * the link partner. - */ - if(hw->mac_type >= e1000_82544) { - e1000_config_collision_dist(hw); - } else { - ret_val = e1000_config_mac_to_phy(hw); - if(ret_val) { - DEBUGOUT("Error configuring MAC to PHY settings\n"); - return ret_val; - } - } - ret_val = e1000_config_fc_after_link_up(hw); - if(ret_val) { - DEBUGOUT("Error Configuring Flow Control\n"); - return ret_val; - } - DEBUGOUT("Valid link established!!!\n"); - - if(hw->phy_type == e1000_phy_igp) { - ret_val = e1000_config_dsp_after_link_change(hw, TRUE); - if(ret_val) { - DEBUGOUT("Error Configuring DSP after link up\n"); - return ret_val; - } - } - DEBUGOUT("Valid link established!!!\n"); - return E1000_SUCCESS; - } - udelay(10); + /* SW Reset the PHY so all changes take effect */ + ret_val = e1000_phy_reset(hw); + if(ret_val) { + DEBUGOUT("Error Resetting the PHY\n"); + return ret_val; } - DEBUGOUT("Unable to establish link!!!\n"); - return E1000_SUCCESS; + return E1000_SUCCESS; } -/****************************************************************************** -* Configures PHY autoneg and flow control advertisement settings +/******************************************************************** +* Setup auto-negotiation and flow control advertisements, +* and then perform auto-negotiation. * * hw - Struct containing variables accessed by shared code -******************************************************************************/ -int32_t -e1000_phy_setup_autoneg(struct e1000_hw *hw) +*********************************************************************/ +static int32_t +e1000_copper_link_autoneg(struct e1000_hw *hw) { int32_t ret_val; - uint16_t mii_autoneg_adv_reg; - uint16_t mii_1000t_ctrl_reg; + uint16_t phy_data; - DEBUGFUNC("e1000_phy_setup_autoneg"); + DEBUGFUNC("e1000_copper_link_autoneg"); - /* Read the MII Auto-Neg Advertisement Register (Address 4). */ - ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg); + /* Perform some bounds checking on the hw->autoneg_advertised + * parameter. If this variable is zero, then set it to the default. + */ + hw->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT; + + /* If autoneg_advertised is zero, we assume it was not defaulted + * by the calling code so we set to advertise full capability. + */ + if(hw->autoneg_advertised == 0) + hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT; + + DEBUGOUT("Reconfiguring auto-neg advertisement params\n"); + ret_val = e1000_phy_setup_autoneg(hw); + if(ret_val) { + DEBUGOUT("Error Setting up Auto-Negotiation\n"); + return ret_val; + } + DEBUGOUT("Restarting Auto-Neg\n"); + + /* Restart auto-negotiation by setting the Auto Neg Enable bit and + * the Auto Neg Restart bit in the PHY control register. + */ + ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data); if(ret_val) return ret_val; - /* Read the MII 1000Base-T Control Register (Address 9). */ - ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg); + phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); + ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data); if(ret_val) return ret_val; - /* Need to parse both autoneg_advertised and fc and set up - * the appropriate PHY registers. First we will parse for + /* Does the user want to wait for Auto-Neg to complete here, or + * check at a later time (for example, callback routine). + */ + if(hw->wait_autoneg_complete) { + ret_val = e1000_wait_autoneg(hw); + if(ret_val) { + DEBUGOUT("Error while waiting for autoneg to complete\n"); + return ret_val; + } + } + + hw->get_link_status = TRUE; + + return E1000_SUCCESS; +} + + +/****************************************************************************** +* Config the MAC and the PHY after link is up. +* 1) Set up the MAC to the current PHY speed/duplex +* if we are on 82543. If we +* are on newer silicon, we only need to configure +* collision distance in the Transmit Control Register. +* 2) Set up flow control on the MAC to that established with +* the link partner. +* 3) Config DSP to improve Gigabit link quality for some PHY revisions. +* +* hw - Struct containing variables accessed by shared code +******************************************************************************/ +static int32_t +e1000_copper_link_postconfig(struct e1000_hw *hw) +{ + int32_t ret_val; + DEBUGFUNC("e1000_copper_link_postconfig"); + + if(hw->mac_type >= e1000_82544) { + e1000_config_collision_dist(hw); + } else { + ret_val = e1000_config_mac_to_phy(hw); + if(ret_val) { + DEBUGOUT("Error configuring MAC to PHY settings\n"); + return ret_val; + } + } + ret_val = e1000_config_fc_after_link_up(hw); + if(ret_val) { + DEBUGOUT("Error Configuring Flow Control\n"); + return ret_val; + } + + /* Config DSP to improve Giga link quality */ + if(hw->phy_type == e1000_phy_igp) { + ret_val = e1000_config_dsp_after_link_change(hw, TRUE); + if(ret_val) { + DEBUGOUT("Error Configuring DSP after link up\n"); + return ret_val; + } + } + + return E1000_SUCCESS; +} + +/****************************************************************************** +* Detects which PHY is present and setup the speed and duplex +* +* hw - Struct containing variables accessed by shared code +******************************************************************************/ +static int32_t +e1000_setup_copper_link(struct e1000_hw *hw) +{ + int32_t ret_val; + uint16_t i; + uint16_t phy_data; + + DEBUGFUNC("e1000_setup_copper_link"); + + /* Check if it is a valid PHY and set PHY mode if necessary. */ + ret_val = e1000_copper_link_preconfig(hw); + if(ret_val) + return ret_val; + + if (hw->phy_type == e1000_phy_igp || + hw->phy_type == e1000_phy_igp_2) { + ret_val = e1000_copper_link_igp_setup(hw); + if(ret_val) + return ret_val; + } else if (hw->phy_type == e1000_phy_m88) { + ret_val = e1000_copper_link_mgp_setup(hw); + if(ret_val) + return ret_val; + } + + if(hw->autoneg) { + /* Setup autoneg and flow control advertisement + * and perform autonegotiation */ + ret_val = e1000_copper_link_autoneg(hw); + if(ret_val) + return ret_val; + } else { + /* PHY will be set to 10H, 10F, 100H,or 100F + * depending on value from forced_speed_duplex. */ + DEBUGOUT("Forcing speed and duplex\n"); + ret_val = e1000_phy_force_speed_duplex(hw); + if(ret_val) { + DEBUGOUT("Error Forcing Speed and Duplex\n"); + return ret_val; + } + } + + /* Check link status. Wait up to 100 microseconds for link to become + * valid. + */ + for(i = 0; i < 10; i++) { + ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data); + if(ret_val) + return ret_val; + ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data); + if(ret_val) + return ret_val; + + if(phy_data & MII_SR_LINK_STATUS) { + /* Config the MAC and PHY after link is up */ + ret_val = e1000_copper_link_postconfig(hw); + if(ret_val) + return ret_val; + + DEBUGOUT("Valid link established!!!\n"); + return E1000_SUCCESS; + } + udelay(10); + } + + DEBUGOUT("Unable to establish link!!!\n"); + return E1000_SUCCESS; +} + +/****************************************************************************** +* Configures PHY autoneg and flow control advertisement settings +* +* hw - Struct containing variables accessed by shared code +******************************************************************************/ +int32_t +e1000_phy_setup_autoneg(struct e1000_hw *hw) +{ + int32_t ret_val; + uint16_t mii_autoneg_adv_reg; + uint16_t mii_1000t_ctrl_reg; + + DEBUGFUNC("e1000_phy_setup_autoneg"); + + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg); + if(ret_val) + return ret_val; + + /* Read the MII 1000Base-T Control Register (Address 9). */ + ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg); + if(ret_val) + return ret_val; + + /* Need to parse both autoneg_advertised and fc and set up + * the appropriate PHY registers. First we will parse for * autoneg_advertised software override. Since we can advertise * a plethora of combinations, we need to check each bit * individually. @@ -1417,7 +1602,7 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw) DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); - ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg); + ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg); if(ret_val) return ret_val; @@ -1678,6 +1863,11 @@ e1000_config_mac_to_phy(struct e1000_hw *hw) DEBUGFUNC("e1000_config_mac_to_phy"); + /* 82544 or newer MAC, Auto Speed Detection takes care of + * MAC speed/duplex configuration.*/ + if (hw->mac_type >= e1000_82544) + return E1000_SUCCESS; + /* Read the Device Control Register and set the bits to Force Speed * and Duplex. */ @@ -1688,45 +1878,25 @@ e1000_config_mac_to_phy(struct e1000_hw *hw) /* Set up duplex in the Device Control and Transmit Control * registers depending on negotiated values. */ - if (hw->phy_type == e1000_phy_igp) { - ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, - &phy_data); - if(ret_val) - return ret_val; - - if(phy_data & IGP01E1000_PSSR_FULL_DUPLEX) ctrl |= E1000_CTRL_FD; - else ctrl &= ~E1000_CTRL_FD; - - e1000_config_collision_dist(hw); + ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); + if(ret_val) + return ret_val; - /* Set up speed in the Device Control register depending on - * negotiated values. - */ - if((phy_data & IGP01E1000_PSSR_SPEED_MASK) == - IGP01E1000_PSSR_SPEED_1000MBPS) - ctrl |= E1000_CTRL_SPD_1000; - else if((phy_data & IGP01E1000_PSSR_SPEED_MASK) == - IGP01E1000_PSSR_SPEED_100MBPS) - ctrl |= E1000_CTRL_SPD_100; - } else { - ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, - &phy_data); - if(ret_val) - return ret_val; + if(phy_data & M88E1000_PSSR_DPLX) + ctrl |= E1000_CTRL_FD; + else + ctrl &= ~E1000_CTRL_FD; - if(phy_data & M88E1000_PSSR_DPLX) ctrl |= E1000_CTRL_FD; - else ctrl &= ~E1000_CTRL_FD; + e1000_config_collision_dist(hw); - e1000_config_collision_dist(hw); + /* Set up speed in the Device Control register depending on + * negotiated values. + */ + if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) + ctrl |= E1000_CTRL_SPD_1000; + else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS) + ctrl |= E1000_CTRL_SPD_100; - /* Set up speed in the Device Control register depending on - * negotiated values. - */ - if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) - ctrl |= E1000_CTRL_SPD_1000; - else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS) - ctrl |= E1000_CTRL_SPD_100; - } /* Write the configured values back to the Device Control Reg. */ E1000_WRITE_REG(hw, CTRL, ctrl); return E1000_SUCCESS; @@ -2494,8 +2664,8 @@ e1000_read_phy_reg(struct e1000_hw *hw, DEBUGFUNC("e1000_read_phy_reg"); - - if(hw->phy_type == e1000_phy_igp && + if((hw->phy_type == e1000_phy_igp || + hw->phy_type == e1000_phy_igp_2) && (reg_addr > MAX_PHY_MULTI_PAGE_REG)) { ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT, (uint16_t)reg_addr); @@ -2600,8 +2770,8 @@ e1000_write_phy_reg(struct e1000_hw *hw, DEBUGFUNC("e1000_write_phy_reg"); - - if(hw->phy_type == e1000_phy_igp && + if((hw->phy_type == e1000_phy_igp || + hw->phy_type == e1000_phy_igp_2) && (reg_addr > MAX_PHY_MULTI_PAGE_REG)) { ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT, (uint16_t)reg_addr); @@ -2679,19 +2849,27 @@ e1000_write_phy_reg_ex(struct e1000_hw *hw, return E1000_SUCCESS; } + /****************************************************************************** * Returns the PHY to the power-on reset state * * hw - Struct containing variables accessed by shared code ******************************************************************************/ -void +int32_t e1000_phy_hw_reset(struct e1000_hw *hw) { uint32_t ctrl, ctrl_ext; uint32_t led_ctrl; + int32_t ret_val; DEBUGFUNC("e1000_phy_hw_reset"); + /* In the case of the phy reset being blocked, it's not an error, we + * simply return success without performing the reset. */ + ret_val = e1000_check_phy_reset_block(hw); + if (ret_val) + return E1000_SUCCESS; + DEBUGOUT("Resetting Phy...\n"); if(hw->mac_type > e1000_82543) { @@ -2727,6 +2905,11 @@ e1000_phy_hw_reset(struct e1000_hw *hw) led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); E1000_WRITE_REG(hw, LEDCTL, led_ctrl); } + + /* Wait for FW to finish PHY configuration. */ + ret_val = e1000_get_phy_cfg_done(hw); + + return ret_val; } /****************************************************************************** @@ -2744,7 +2927,19 @@ e1000_phy_reset(struct e1000_hw *hw) DEBUGFUNC("e1000_phy_reset"); - if(hw->mac_type != e1000_82541_rev_2) { + /* In the case of the phy reset being blocked, it's not an error, we + * simply return success without performing the reset. */ + ret_val = e1000_check_phy_reset_block(hw); + if (ret_val) + return E1000_SUCCESS; + + switch (hw->mac_type) { + case e1000_82541_rev_2: + ret_val = e1000_phy_hw_reset(hw); + if(ret_val) + return ret_val; + break; + default: ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data); if(ret_val) return ret_val; @@ -2755,9 +2950,10 @@ e1000_phy_reset(struct e1000_hw *hw) return ret_val; udelay(1); - } else e1000_phy_hw_reset(hw); + break; + } - if(hw->phy_type == e1000_phy_igp) + if(hw->phy_type == e1000_phy_igp || hw->phy_type == e1000_phy_igp_2) e1000_phy_init_script(hw); return E1000_SUCCESS; @@ -2811,6 +3007,9 @@ e1000_detect_gig_phy(struct e1000_hw *hw) case e1000_82547_rev_2: if(hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE; break; + case e1000_82573: + if(hw->phy_id == M88E1111_I_PHY_ID) match = TRUE; + break; default: DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type); return -E1000_ERR_CONFIG; @@ -2866,7 +3065,7 @@ e1000_phy_igp_get_info(struct e1000_hw *hw, /* The downshift status is checked only once, after link is established, * and it stored in the hw->speed_downgraded parameter. */ - phy_info->downshift = hw->speed_downgraded; + phy_info->downshift = (e1000_downshift)hw->speed_downgraded; /* IGP01E1000 does not need to support it. */ phy_info->extended_10bt_distance = e1000_10bt_ext_dist_enable_normal; @@ -2905,7 +3104,7 @@ e1000_phy_igp_get_info(struct e1000_hw *hw, if(ret_val) return ret_val; - /* transalte to old method */ + /* Translate to old method */ average = (max_length + min_length) / 2; if(average <= e1000_igp_cable_length_50) @@ -2940,7 +3139,7 @@ e1000_phy_m88_get_info(struct e1000_hw *hw, /* The downshift status is checked only once, after link is established, * and it stored in the hw->speed_downgraded parameter. */ - phy_info->downshift = hw->speed_downgraded; + phy_info->downshift = (e1000_downshift)hw->speed_downgraded; ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); if(ret_val) @@ -3029,7 +3228,8 @@ e1000_phy_get_info(struct e1000_hw *hw, return -E1000_ERR_CONFIG; } - if(hw->phy_type == e1000_phy_igp) + if(hw->phy_type == e1000_phy_igp || + hw->phy_type == e1000_phy_igp_2) return e1000_phy_igp_get_info(hw, phy_info); else return e1000_phy_m88_get_info(hw, phy_info); @@ -3055,11 +3255,12 @@ e1000_validate_mdi_setting(struct e1000_hw *hw) * * hw - Struct containing variables accessed by shared code *****************************************************************************/ -void +int32_t e1000_init_eeprom_params(struct e1000_hw *hw) { struct e1000_eeprom_info *eeprom = &hw->eeprom; uint32_t eecd = E1000_READ_REG(hw, EECD); + int32_t ret_val = E1000_SUCCESS; uint16_t eeprom_size; DEBUGFUNC("e1000_init_eeprom_params"); @@ -3074,6 +3275,8 @@ e1000_init_eeprom_params(struct e1000_hw *hw) eeprom->opcode_bits = 3; eeprom->address_bits = 6; eeprom->delay_usec = 50; + eeprom->use_eerd = FALSE; + eeprom->use_eewr = FALSE; break; case e1000_82540: case e1000_82545: @@ -3090,6 +3293,8 @@ e1000_init_eeprom_params(struct e1000_hw *hw) eeprom->word_size = 64; eeprom->address_bits = 6; } + eeprom->use_eerd = FALSE; + eeprom->use_eewr = FALSE; break; case e1000_82541: case e1000_82541_rev_2: @@ -3118,42 +3323,60 @@ e1000_init_eeprom_params(struct e1000_hw *hw) eeprom->address_bits = 6; } } + eeprom->use_eerd = FALSE; + eeprom->use_eewr = FALSE; + break; + case e1000_82573: + eeprom->type = e1000_eeprom_spi; + eeprom->opcode_bits = 8; + eeprom->delay_usec = 1; + if (eecd & E1000_EECD_ADDR_BITS) { + eeprom->page_size = 32; + eeprom->address_bits = 16; + } else { + eeprom->page_size = 8; + eeprom->address_bits = 8; + } + eeprom->use_eerd = TRUE; + eeprom->use_eewr = TRUE; + if(e1000_is_onboard_nvm_eeprom(hw) == FALSE) { + eeprom->type = e1000_eeprom_flash; + eeprom->word_size = 2048; + + /* Ensure that the Autonomous FLASH update bit is cleared due to + * Flash update issue on parts which use a FLASH for NVM. */ + eecd &= ~E1000_EECD_AUPDEN; + E1000_WRITE_REG(hw, EECD, eecd); + } break; default: break; } if (eeprom->type == e1000_eeprom_spi) { - eeprom->word_size = 64; - if (e1000_read_eeprom(hw, EEPROM_CFG, 1, &eeprom_size) == 0) { - eeprom_size &= EEPROM_SIZE_MASK; - - switch (eeprom_size) { - case EEPROM_SIZE_16KB: - eeprom->word_size = 8192; - break; - case EEPROM_SIZE_8KB: - eeprom->word_size = 4096; - break; - case EEPROM_SIZE_4KB: - eeprom->word_size = 2048; - break; - case EEPROM_SIZE_2KB: - eeprom->word_size = 1024; - break; - case EEPROM_SIZE_1KB: - eeprom->word_size = 512; - break; - case EEPROM_SIZE_512B: - eeprom->word_size = 256; - break; - case EEPROM_SIZE_128B: - default: - eeprom->word_size = 64; - break; - } + /* eeprom_size will be an enum [0..8] that maps to eeprom sizes 128B to + * 32KB (incremented by powers of 2). + */ + if(hw->mac_type <= e1000_82547_rev_2) { + /* Set to default value for initial eeprom read. */ + eeprom->word_size = 64; + ret_val = e1000_read_eeprom(hw, EEPROM_CFG, 1, &eeprom_size); + if(ret_val) + return ret_val; + eeprom_size = (eeprom_size & EEPROM_SIZE_MASK) >> EEPROM_SIZE_SHIFT; + /* 256B eeprom size was not supported in earlier hardware, so we + * bump eeprom_size up one to ensure that "1" (which maps to 256B) + * is never the result used in the shifting logic below. */ + if(eeprom_size) + eeprom_size++; + } else { + eeprom_size = (uint16_t)((eecd & E1000_EECD_SIZE_EX_MASK) >> + E1000_EECD_SIZE_EX_SHIFT); } + + eeprom->word_size = 1 << (eeprom_size + EEPROM_WORD_SIZE_SHIFT); } + return ret_val; } /****************************************************************************** @@ -3306,8 +3529,12 @@ e1000_acquire_eeprom(struct e1000_hw *hw) DEBUGFUNC("e1000_acquire_eeprom"); + if(e1000_get_hw_eeprom_semaphore(hw)) + return -E1000_ERR_EEPROM; + eecd = E1000_READ_REG(hw, EECD); + if (hw->mac_type != e1000_82573) { /* Request EEPROM Access */ if(hw->mac_type > e1000_82544) { eecd |= E1000_EECD_REQ; @@ -3326,6 +3553,7 @@ e1000_acquire_eeprom(struct e1000_hw *hw) return -E1000_ERR_EEPROM; } } + } /* Setup EEPROM for Read/Write */ @@ -3443,6 +3671,8 @@ e1000_release_eeprom(struct e1000_hw *hw) eecd &= ~E1000_EECD_REQ; E1000_WRITE_REG(hw, EECD, eecd); } + + e1000_put_hw_eeprom_semaphore(hw); } /****************************************************************************** @@ -3504,8 +3734,10 @@ e1000_read_eeprom(struct e1000_hw *hw, { struct e1000_eeprom_info *eeprom = &hw->eeprom; uint32_t i = 0; + int32_t ret_val; DEBUGFUNC("e1000_read_eeprom"); + /* A check for invalid values: offset too large, too many words, and not * enough words. */ @@ -3515,9 +3747,23 @@ e1000_read_eeprom(struct e1000_hw *hw, return -E1000_ERR_EEPROM; } - /* Prepare the EEPROM for reading */ - if(e1000_acquire_eeprom(hw) != E1000_SUCCESS) - return -E1000_ERR_EEPROM; + /* FLASH reads without acquiring the semaphore are safe in 82573-based + * controllers. + */ + if ((e1000_is_onboard_nvm_eeprom(hw) == TRUE) || + (hw->mac_type != e1000_82573)) { + /* Prepare the EEPROM for reading */ + if(e1000_acquire_eeprom(hw) != E1000_SUCCESS) + return -E1000_ERR_EEPROM; + } + + if(eeprom->use_eerd == TRUE) { + ret_val = e1000_read_eeprom_eerd(hw, offset, words, data); + if ((e1000_is_onboard_nvm_eeprom(hw) == TRUE) || + (hw->mac_type != e1000_82573)) + e1000_release_eeprom(hw); + return ret_val; + } if(eeprom->type == e1000_eeprom_spi) { uint16_t word_in; @@ -3569,65 +3815,212 @@ e1000_read_eeprom(struct e1000_hw *hw, } /****************************************************************************** - * Verifies that the EEPROM has a valid checksum + * Reads a 16 bit word from the EEPROM using the EERD register. * * hw - Struct containing variables accessed by shared code - * - * Reads the first 64 16 bit words of the EEPROM and sums the values read. - * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is - * valid. + * offset - offset of word in the EEPROM to read + * data - word read from the EEPROM + * words - number of words to read *****************************************************************************/ int32_t -e1000_validate_eeprom_checksum(struct e1000_hw *hw) +e1000_read_eeprom_eerd(struct e1000_hw *hw, + uint16_t offset, + uint16_t words, + uint16_t *data) { - uint16_t checksum = 0; - uint16_t i, eeprom_data; + uint32_t i, eerd = 0; + int32_t error = 0; - DEBUGFUNC("e1000_validate_eeprom_checksum"); + for (i = 0; i < words; i++) { + eerd = ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) + + E1000_EEPROM_RW_REG_START; - for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) { - if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) { - DEBUGOUT("EEPROM Read Error\n"); - return -E1000_ERR_EEPROM; + E1000_WRITE_REG(hw, EERD, eerd); + error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_READ); + + if(error) { + break; } - checksum += eeprom_data; - } - - if(checksum == (uint16_t) EEPROM_SUM) - return E1000_SUCCESS; - else { - DEBUGOUT("EEPROM Checksum Invalid\n"); - return -E1000_ERR_EEPROM; + data[i] = (E1000_READ_REG(hw, EERD) >> E1000_EEPROM_RW_REG_DATA); + } + + return error; } /****************************************************************************** - * Calculates the EEPROM checksum and writes it to the EEPROM + * Writes a 16 bit word from the EEPROM using the EEWR register. * * hw - Struct containing variables accessed by shared code - * - * Sums the first 63 16 bit words of the EEPROM. Subtracts the sum from 0xBABA. - * Writes the difference to word offset 63 of the EEPROM. + * offset - offset of word in the EEPROM to read + * data - word read from the EEPROM + * words - number of words to read *****************************************************************************/ int32_t -e1000_update_eeprom_checksum(struct e1000_hw *hw) +e1000_write_eeprom_eewr(struct e1000_hw *hw, + uint16_t offset, + uint16_t words, + uint16_t *data) { - uint16_t checksum = 0; - uint16_t i, eeprom_data; + uint32_t register_value = 0; + uint32_t i = 0; + int32_t error = 0; - DEBUGFUNC("e1000_update_eeprom_checksum"); + for (i = 0; i < words; i++) { + register_value = (data[i] << E1000_EEPROM_RW_REG_DATA) | + ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) | + E1000_EEPROM_RW_REG_START; - for(i = 0; i < EEPROM_CHECKSUM_REG; i++) { - if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) { - DEBUGOUT("EEPROM Read Error\n"); - return -E1000_ERR_EEPROM; - } - checksum += eeprom_data; - } - checksum = (uint16_t) EEPROM_SUM - checksum; + error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_WRITE); + if(error) { + break; + } + + E1000_WRITE_REG(hw, EEWR, register_value); + + error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_WRITE); + + if(error) { + break; + } + } + + return error; +} + +/****************************************************************************** + * Polls the status bit (bit 1) of the EERD to determine when the read is done. + * + * hw - Struct containing variables accessed by shared code + *****************************************************************************/ +int32_t +e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int eerd) +{ + uint32_t attempts = 100000; + uint32_t i, reg = 0; + int32_t done = E1000_ERR_EEPROM; + + for(i = 0; i < attempts; i++) { + if(eerd == E1000_EEPROM_POLL_READ) + reg = E1000_READ_REG(hw, EERD); + else + reg = E1000_READ_REG(hw, EEWR); + + if(reg & E1000_EEPROM_RW_REG_DONE) { + done = E1000_SUCCESS; + break; + } + udelay(5); + } + + return done; +} + +/*************************************************************************** +* Description: Determines if the onboard NVM is FLASH or EEPROM. +* +* hw - Struct containing variables accessed by shared code +****************************************************************************/ +boolean_t +e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw) +{ + uint32_t eecd = 0; + + if(hw->mac_type == e1000_82573) { + eecd = E1000_READ_REG(hw, EECD); + + /* Isolate bits 15 & 16 */ + eecd = ((eecd >> 15) & 0x03); + + /* If both bits are set, device is Flash type */ + if(eecd == 0x03) { + return FALSE; + } + } + return TRUE; +} + +/****************************************************************************** + * Verifies that the EEPROM has a valid checksum + * + * hw - Struct containing variables accessed by shared code + * + * Reads the first 64 16 bit words of the EEPROM and sums the values read. + * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is + * valid. + *****************************************************************************/ +int32_t +e1000_validate_eeprom_checksum(struct e1000_hw *hw) +{ + uint16_t checksum = 0; + uint16_t i, eeprom_data; + + DEBUGFUNC("e1000_validate_eeprom_checksum"); + + if ((hw->mac_type == e1000_82573) && + (e1000_is_onboard_nvm_eeprom(hw) == FALSE)) { + /* Check bit 4 of word 10h. If it is 0, firmware is done updating + * 10h-12h. Checksum may need to be fixed. */ + e1000_read_eeprom(hw, 0x10, 1, &eeprom_data); + if ((eeprom_data & 0x10) == 0) { + /* Read 0x23 and check bit 15. This bit is a 1 when the checksum + * has already been fixed. If the checksum is still wrong and this + * bit is a 1, we need to return bad checksum. Otherwise, we need + * to set this bit to a 1 and update the checksum. */ + e1000_read_eeprom(hw, 0x23, 1, &eeprom_data); + if ((eeprom_data & 0x8000) == 0) { + eeprom_data |= 0x8000; + e1000_write_eeprom(hw, 0x23, 1, &eeprom_data); + e1000_update_eeprom_checksum(hw); + } + } + } + + for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) { + if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) { + DEBUGOUT("EEPROM Read Error\n"); + return -E1000_ERR_EEPROM; + } + checksum += eeprom_data; + } + + if(checksum == (uint16_t) EEPROM_SUM) + return E1000_SUCCESS; + else { + DEBUGOUT("EEPROM Checksum Invalid\n"); + return -E1000_ERR_EEPROM; + } +} + +/****************************************************************************** + * Calculates the EEPROM checksum and writes it to the EEPROM + * + * hw - Struct containing variables accessed by shared code + * + * Sums the first 63 16 bit words of the EEPROM. Subtracts the sum from 0xBABA. + * Writes the difference to word offset 63 of the EEPROM. + *****************************************************************************/ +int32_t +e1000_update_eeprom_checksum(struct e1000_hw *hw) +{ + uint16_t checksum = 0; + uint16_t i, eeprom_data; + + DEBUGFUNC("e1000_update_eeprom_checksum"); + + for(i = 0; i < EEPROM_CHECKSUM_REG; i++) { + if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) { + DEBUGOUT("EEPROM Read Error\n"); + return -E1000_ERR_EEPROM; + } + checksum += eeprom_data; + } + checksum = (uint16_t) EEPROM_SUM - checksum; if(e1000_write_eeprom(hw, EEPROM_CHECKSUM_REG, 1, &checksum) < 0) { DEBUGOUT("EEPROM Write Error\n"); return -E1000_ERR_EEPROM; + } else if (hw->eeprom.type == e1000_eeprom_flash) { + e1000_commit_shadow_ram(hw); } return E1000_SUCCESS; } @@ -3663,6 +4056,10 @@ e1000_write_eeprom(struct e1000_hw *hw, return -E1000_ERR_EEPROM; } + /* 82573 reads only through eerd */ + if(eeprom->use_eewr == TRUE) + return e1000_write_eeprom_eewr(hw, offset, words, data); + /* Prepare the EEPROM for writing */ if (e1000_acquire_eeprom(hw) != E1000_SUCCESS) return -E1000_ERR_EEPROM; @@ -3832,6 +4229,65 @@ e1000_write_eeprom_microwire(struct e1000_hw *hw, return E1000_SUCCESS; } +/****************************************************************************** + * Flushes the cached eeprom to NVM. This is done by saving the modified values + * in the eeprom cache and the non modified values in the currently active bank + * to the new bank. + * + * hw - Struct containing variables accessed by shared code + * offset - offset of word in the EEPROM to read + * data - word read from the EEPROM + * words - number of words to read + *****************************************************************************/ +int32_t +e1000_commit_shadow_ram(struct e1000_hw *hw) +{ + uint32_t attempts = 100000; + uint32_t eecd = 0; + uint32_t flop = 0; + uint32_t i = 0; + int32_t error = E1000_SUCCESS; + + /* The flop register will be used to determine if flash type is STM */ + flop = E1000_READ_REG(hw, FLOP); + + if (hw->mac_type == e1000_82573) { + for (i=0; i < attempts; i++) { + eecd = E1000_READ_REG(hw, EECD); + if ((eecd & E1000_EECD_FLUPD) == 0) { + break; + } + udelay(5); + } + + if (i == attempts) { + return -E1000_ERR_EEPROM; + } + + /* If STM opcode located in bits 15:8 of flop, reset firmware */ + if ((flop & 0xFF00) == E1000_STM_OPCODE) { + E1000_WRITE_REG(hw, HICR, E1000_HICR_FW_RESET); + } + + /* Perform the flash update */ + E1000_WRITE_REG(hw, EECD, eecd | E1000_EECD_FLUPD); + + for (i=0; i < attempts; i++) { + eecd = E1000_READ_REG(hw, EECD); + if ((eecd & E1000_EECD_FLUPD) == 0) { + break; + } + udelay(5); + } + + if (i == attempts) { + return -E1000_ERR_EEPROM; + } + } + + return error; +} + /****************************************************************************** * Reads the adapter's part number from the EEPROM * @@ -3911,6 +4367,7 @@ void e1000_init_rx_addrs(struct e1000_hw *hw) { uint32_t i; + uint32_t rar_num; DEBUGFUNC("e1000_init_rx_addrs"); @@ -3919,9 +4376,10 @@ e1000_init_rx_addrs(struct e1000_hw *hw) e1000_rar_set(hw, hw->mac_addr, 0); + rar_num = E1000_RAR_ENTRIES; /* Zero out the other 15 receive addresses. */ DEBUGOUT("Clearing RAR[1-15]\n"); - for(i = 1; i < E1000_RAR_ENTRIES; i++) { + for(i = 1; i < rar_num; i++) { E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0); E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0); } @@ -3950,7 +4408,9 @@ e1000_mc_addr_list_update(struct e1000_hw *hw, { uint32_t hash_value; uint32_t i; - + uint32_t num_rar_entry; + uint32_t num_mta_entry; + DEBUGFUNC("e1000_mc_addr_list_update"); /* Set the new number of MC addresses that we are being requested to use. */ @@ -3958,14 +4418,16 @@ e1000_mc_addr_list_update(struct e1000_hw *hw, /* Clear RAR[1-15] */ DEBUGOUT(" Clearing RAR[1-15]\n"); - for(i = rar_used_count; i < E1000_RAR_ENTRIES; i++) { + num_rar_entry = E1000_RAR_ENTRIES; + for(i = rar_used_count; i < num_rar_entry; i++) { E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0); E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0); } /* Clear the MTA */ DEBUGOUT(" Clearing MTA\n"); - for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) { + num_mta_entry = E1000_NUM_MTA_REGISTERS; + for(i = 0; i < num_mta_entry; i++) { E1000_WRITE_REG_ARRAY(hw, MTA, i, 0); } @@ -3989,7 +4451,7 @@ e1000_mc_addr_list_update(struct e1000_hw *hw, /* Place this multicast address in the RAR if there is room, * * else put it in the MTA */ - if(rar_used_count < E1000_RAR_ENTRIES) { + if (rar_used_count < num_rar_entry) { e1000_rar_set(hw, mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)), rar_used_count); @@ -4040,6 +4502,7 @@ e1000_hash_mc_addr(struct e1000_hw *hw, } hash_value &= 0xFFF; + return hash_value; } @@ -4144,12 +4607,33 @@ void e1000_clear_vfta(struct e1000_hw *hw) { uint32_t offset; - - for(offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) - E1000_WRITE_REG_ARRAY(hw, VFTA, offset, 0); + uint32_t vfta_value = 0; + uint32_t vfta_offset = 0; + uint32_t vfta_bit_in_reg = 0; + + if (hw->mac_type == e1000_82573) { + if (hw->mng_cookie.vlan_id != 0) { + /* The VFTA is a 4096b bit-field, each identifying a single VLAN + * ID. The following operations determine which 32b entry + * (i.e. offset) into the array we want to set the VLAN ID + * (i.e. bit) of the manageability unit. */ + vfta_offset = (hw->mng_cookie.vlan_id >> + E1000_VFTA_ENTRY_SHIFT) & + E1000_VFTA_ENTRY_MASK; + vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id & + E1000_VFTA_ENTRY_BIT_SHIFT_MASK); + } + } + for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) { + /* If the offset we want to clear is the same offset of the + * manageability VLAN ID, then clear all bits except that of the + * manageability unit */ + vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0; + E1000_WRITE_REG_ARRAY(hw, VFTA, offset, vfta_value); + } } -static int32_t +int32_t e1000_id_led_init(struct e1000_hw * hw) { uint32_t ledctl; @@ -4480,6 +4964,19 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw) temp = E1000_READ_REG(hw, MGTPRC); temp = E1000_READ_REG(hw, MGTPDC); temp = E1000_READ_REG(hw, MGTPTC); + + if(hw->mac_type <= e1000_82547_rev_2) return; + + temp = E1000_READ_REG(hw, IAC); + temp = E1000_READ_REG(hw, ICRXOC); + temp = E1000_READ_REG(hw, ICRXPTC); + temp = E1000_READ_REG(hw, ICRXATC); + temp = E1000_READ_REG(hw, ICTXPTC); + temp = E1000_READ_REG(hw, ICTXATC); + temp = E1000_READ_REG(hw, ICTXQEC); + temp = E1000_READ_REG(hw, ICTXQMTC); + temp = E1000_READ_REG(hw, ICRXDMTC); + } /****************************************************************************** @@ -4646,6 +5143,11 @@ e1000_get_bus_info(struct e1000_hw *hw) hw->bus_speed = e1000_bus_speed_unknown; hw->bus_width = e1000_bus_width_unknown; break; + case e1000_82573: + hw->bus_type = e1000_bus_type_pci_express; + hw->bus_speed = e1000_bus_speed_2500; + hw->bus_width = e1000_bus_width_pciex_4; + break; default: status = E1000_READ_REG(hw, STATUS); hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ? @@ -4749,6 +5251,7 @@ e1000_get_cable_length(struct e1000_hw *hw, /* Use old method for Phy older than IGP */ if(hw->phy_type == e1000_phy_m88) { + ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); if(ret_val) @@ -4865,7 +5368,8 @@ e1000_check_polarity(struct e1000_hw *hw, return ret_val; *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >> M88E1000_PSSR_REV_POLARITY_SHIFT; - } else if(hw->phy_type == e1000_phy_igp) { + } else if(hw->phy_type == e1000_phy_igp || + hw->phy_type == e1000_phy_igp_2) { /* Read the Status register to check the speed */ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data); @@ -4917,7 +5421,8 @@ e1000_check_downshift(struct e1000_hw *hw) DEBUGFUNC("e1000_check_downshift"); - if(hw->phy_type == e1000_phy_igp) { + if(hw->phy_type == e1000_phy_igp || + hw->phy_type == e1000_phy_igp_2) { ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH, &phy_data); if(ret_val) @@ -4933,6 +5438,7 @@ e1000_check_downshift(struct e1000_hw *hw) hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >> M88E1000_PSSR_DOWNSHIFT_SHIFT; } + return E1000_SUCCESS; } @@ -5047,7 +5553,7 @@ e1000_config_dsp_after_link_change(struct e1000_hw *hw, if(ret_val) return ret_val; - msec_delay(20); + msec_delay_irq(20); ret_val = e1000_write_phy_reg(hw, 0x0000, IGP01E1000_IEEE_FORCE_GIGA); @@ -5071,7 +5577,7 @@ e1000_config_dsp_after_link_change(struct e1000_hw *hw, if(ret_val) return ret_val; - msec_delay(20); + msec_delay_irq(20); /* Now enable the transmitter */ ret_val = e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data); @@ -5096,7 +5602,7 @@ e1000_config_dsp_after_link_change(struct e1000_hw *hw, if(ret_val) return ret_val; - msec_delay(20); + msec_delay_irq(20); ret_val = e1000_write_phy_reg(hw, 0x0000, IGP01E1000_IEEE_FORCE_GIGA); @@ -5112,7 +5618,7 @@ e1000_config_dsp_after_link_change(struct e1000_hw *hw, if(ret_val) return ret_val; - msec_delay(20); + msec_delay_irq(20); /* Now enable the transmitter */ ret_val = e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data); @@ -5187,22 +5693,36 @@ e1000_set_d3_lplu_state(struct e1000_hw *hw, uint16_t phy_data; DEBUGFUNC("e1000_set_d3_lplu_state"); - if(!((hw->mac_type == e1000_82541_rev_2) || - (hw->mac_type == e1000_82547_rev_2))) + if(hw->phy_type != e1000_phy_igp && hw->phy_type != e1000_phy_igp_2) return E1000_SUCCESS; /* During driver activity LPLU should not be used or it will attain link * from the lowest speeds starting from 10Mbps. The capability is used for * Dx transitions and states */ - ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &phy_data); - if(ret_val) - return ret_val; - - if(!active) { - phy_data &= ~IGP01E1000_GMII_FLEX_SPD; - ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data); + if(hw->mac_type == e1000_82541_rev_2 || hw->mac_type == e1000_82547_rev_2) { + ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &phy_data); + if(ret_val) + return ret_val; + } else { + ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data); if(ret_val) return ret_val; + } + + if(!active) { + if(hw->mac_type == e1000_82541_rev_2 || + hw->mac_type == e1000_82547_rev_2) { + phy_data &= ~IGP01E1000_GMII_FLEX_SPD; + ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data); + if(ret_val) + return ret_val; + } else { + phy_data &= ~IGP02E1000_PM_D3_LPLU; + ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, + phy_data); + if (ret_val) + return ret_val; + } /* LPLU and SmartSpeed are mutually exclusive. LPLU is used during * Dx states where the power conservation is most important. During @@ -5236,11 +5756,105 @@ e1000_set_d3_lplu_state(struct e1000_hw *hw, (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL ) || (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) { - phy_data |= IGP01E1000_GMII_FLEX_SPD; - ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data); + if(hw->mac_type == e1000_82541_rev_2 || + hw->mac_type == e1000_82547_rev_2) { + phy_data |= IGP01E1000_GMII_FLEX_SPD; + ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data); + if(ret_val) + return ret_val; + } else { + phy_data |= IGP02E1000_PM_D3_LPLU; + ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, + phy_data); + if (ret_val) + return ret_val; + } + + /* When LPLU is enabled we should disable SmartSpeed */ + ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data); + if(ret_val) + return ret_val; + + phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data); + if(ret_val) + return ret_val; + + } + return E1000_SUCCESS; +} + +/***************************************************************************** + * + * This function sets the lplu d0 state according to the active flag. When + * activating lplu this function also disables smart speed and vise versa. + * lplu will not be activated unless the device autonegotiation advertisment + * meets standards of either 10 or 10/100 or 10/100/1000 at all duplexes. + * hw: Struct containing variables accessed by shared code + * active - true to enable lplu false to disable lplu. + * + * returns: - E1000_ERR_PHY if fail to read/write the PHY + * E1000_SUCCESS at any other case. + * + ****************************************************************************/ + +int32_t +e1000_set_d0_lplu_state(struct e1000_hw *hw, + boolean_t active) +{ + int32_t ret_val; + uint16_t phy_data; + DEBUGFUNC("e1000_set_d0_lplu_state"); + + if(hw->mac_type <= e1000_82547_rev_2) + return E1000_SUCCESS; + + ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data); if(ret_val) return ret_val; + if (!active) { + phy_data &= ~IGP02E1000_PM_D0_LPLU; + ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data); + if (ret_val) + return ret_val; + + /* LPLU and SmartSpeed are mutually exclusive. LPLU is used during + * Dx states where the power conservation is most important. During + * driver activity we should enable SmartSpeed, so performance is + * maintained. */ + if (hw->smart_speed == e1000_smart_speed_on) { + ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, + &phy_data); + if(ret_val) + return ret_val; + + phy_data |= IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, + phy_data); + if(ret_val) + return ret_val; + } else if (hw->smart_speed == e1000_smart_speed_off) { + ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, + &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, + phy_data); + if(ret_val) + return ret_val; + } + + + } else { + + phy_data |= IGP02E1000_PM_D0_LPLU; + ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data); + if (ret_val) + return ret_val; + /* When LPLU is enabled we should disable SmartSpeed */ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data); if(ret_val) @@ -5318,18 +5932,350 @@ e1000_set_vco_speed(struct e1000_hw *hw) return E1000_SUCCESS; } -static int32_t -e1000_polarity_reversal_workaround(struct e1000_hw *hw) -{ - int32_t ret_val; - uint16_t mii_status_reg; - uint16_t i; - /* Polarity reversal workaround for forced 10F/10H links. */ +/***************************************************************************** + * This function reads the cookie from ARC ram. + * + * returns: - E1000_SUCCESS . + ****************************************************************************/ +int32_t +e1000_host_if_read_cookie(struct e1000_hw * hw, uint8_t *buffer) +{ + uint8_t i; + uint32_t offset = E1000_MNG_DHCP_COOKIE_OFFSET; + uint8_t length = E1000_MNG_DHCP_COOKIE_LENGTH; - /* Disable the transmitter on the PHY */ + length = (length >> 2); + offset = (offset >> 2); - ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019); + for (i = 0; i < length; i++) { + *((uint32_t *) buffer + i) = + E1000_READ_REG_ARRAY_DWORD(hw, HOST_IF, offset + i); + } + return E1000_SUCCESS; +} + + +/***************************************************************************** + * This function checks whether the HOST IF is enabled for command operaton + * and also checks whether the previous command is completed. + * It busy waits in case of previous command is not completed. + * + * returns: - E1000_ERR_HOST_INTERFACE_COMMAND in case if is not ready or + * timeout + * - E1000_SUCCESS for success. + ****************************************************************************/ +int32_t +e1000_mng_enable_host_if(struct e1000_hw * hw) +{ + uint32_t hicr; + uint8_t i; + + /* Check that the host interface is enabled. */ + hicr = E1000_READ_REG(hw, HICR); + if ((hicr & E1000_HICR_EN) == 0) { + DEBUGOUT("E1000_HOST_EN bit disabled.\n"); + return -E1000_ERR_HOST_INTERFACE_COMMAND; + } + /* check the previous command is completed */ + for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) { + hicr = E1000_READ_REG(hw, HICR); + if (!(hicr & E1000_HICR_C)) + break; + msec_delay_irq(1); + } + + if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) { + DEBUGOUT("Previous command timeout failed .\n"); + return -E1000_ERR_HOST_INTERFACE_COMMAND; + } + return E1000_SUCCESS; +} + +/***************************************************************************** + * This function writes the buffer content at the offset given on the host if. + * It also does alignment considerations to do the writes in most efficient way. + * Also fills up the sum of the buffer in *buffer parameter. + * + * returns - E1000_SUCCESS for success. + ****************************************************************************/ +int32_t +e1000_mng_host_if_write(struct e1000_hw * hw, uint8_t *buffer, + uint16_t length, uint16_t offset, uint8_t *sum) +{ + uint8_t *tmp; + uint8_t *bufptr = buffer; + uint32_t data; + uint16_t remaining, i, j, prev_bytes; + + /* sum = only sum of the data and it is not checksum */ + + if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) { + return -E1000_ERR_PARAM; + } + + tmp = (uint8_t *)&data; + prev_bytes = offset & 0x3; + offset &= 0xFFFC; + offset >>= 2; + + if (prev_bytes) { + data = E1000_READ_REG_ARRAY_DWORD(hw, HOST_IF, offset); + for (j = prev_bytes; j < sizeof(uint32_t); j++) { + *(tmp + j) = *bufptr++; + *sum += *(tmp + j); + } + E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset, data); + length -= j - prev_bytes; + offset++; + } + + remaining = length & 0x3; + length -= remaining; + + /* Calculate length in DWORDs */ + length >>= 2; + + /* The device driver writes the relevant command block into the + * ram area. */ + for (i = 0; i < length; i++) { + for (j = 0; j < sizeof(uint32_t); j++) { + *(tmp + j) = *bufptr++; + *sum += *(tmp + j); + } + + E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset + i, data); + } + if (remaining) { + for (j = 0; j < sizeof(uint32_t); j++) { + if (j < remaining) + *(tmp + j) = *bufptr++; + else + *(tmp + j) = 0; + + *sum += *(tmp + j); + } + E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, offset + i, data); + } + + return E1000_SUCCESS; +} + + +/***************************************************************************** + * This function writes the command header after does the checksum calculation. + * + * returns - E1000_SUCCESS for success. + ****************************************************************************/ +int32_t +e1000_mng_write_cmd_header(struct e1000_hw * hw, + struct e1000_host_mng_command_header * hdr) +{ + uint16_t i; + uint8_t sum; + uint8_t *buffer; + + /* Write the whole command header structure which includes sum of + * the buffer */ + + uint16_t length = sizeof(struct e1000_host_mng_command_header); + + sum = hdr->checksum; + hdr->checksum = 0; + + buffer = (uint8_t *) hdr; + i = length; + while(i--) + sum += buffer[i]; + + hdr->checksum = 0 - sum; + + length >>= 2; + /* The device driver writes the relevant command block into the ram area. */ + for (i = 0; i < length; i++) + E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, i, *((uint32_t *) hdr + i)); + + return E1000_SUCCESS; +} + + +/***************************************************************************** + * This function indicates to ARC that a new command is pending which completes + * one write operation by the driver. + * + * returns - E1000_SUCCESS for success. + ****************************************************************************/ +int32_t +e1000_mng_write_commit( + struct e1000_hw * hw) +{ + uint32_t hicr; + + hicr = E1000_READ_REG(hw, HICR); + /* Setting this bit tells the ARC that a new command is pending. */ + E1000_WRITE_REG(hw, HICR, hicr | E1000_HICR_C); + + return E1000_SUCCESS; +} + + +/***************************************************************************** + * This function checks the mode of the firmware. + * + * returns - TRUE when the mode is IAMT or FALSE. + ****************************************************************************/ +boolean_t +e1000_check_mng_mode( + struct e1000_hw *hw) +{ + uint32_t fwsm; + + fwsm = E1000_READ_REG(hw, FWSM); + + if((fwsm & E1000_FWSM_MODE_MASK) == + (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)) + return TRUE; + + return FALSE; +} + + +/***************************************************************************** + * This function writes the dhcp info . + ****************************************************************************/ +int32_t +e1000_mng_write_dhcp_info(struct e1000_hw * hw, uint8_t *buffer, + uint16_t length) +{ + int32_t ret_val; + struct e1000_host_mng_command_header hdr; + + hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD; + hdr.command_length = length; + hdr.reserved1 = 0; + hdr.reserved2 = 0; + hdr.checksum = 0; + + ret_val = e1000_mng_enable_host_if(hw); + if (ret_val == E1000_SUCCESS) { + ret_val = e1000_mng_host_if_write(hw, buffer, length, sizeof(hdr), + &(hdr.checksum)); + if (ret_val == E1000_SUCCESS) { + ret_val = e1000_mng_write_cmd_header(hw, &hdr); + if (ret_val == E1000_SUCCESS) + ret_val = e1000_mng_write_commit(hw); + } + } + return ret_val; +} + + +/***************************************************************************** + * This function calculates the checksum. + * + * returns - checksum of buffer contents. + ****************************************************************************/ +uint8_t +e1000_calculate_mng_checksum(char *buffer, uint32_t length) +{ + uint8_t sum = 0; + uint32_t i; + + if (!buffer) + return 0; + + for (i=0; i < length; i++) + sum += buffer[i]; + + return (uint8_t) (0 - sum); +} + +/***************************************************************************** + * This function checks whether tx pkt filtering needs to be enabled or not. + * + * returns - TRUE for packet filtering or FALSE. + ****************************************************************************/ +boolean_t +e1000_enable_tx_pkt_filtering(struct e1000_hw *hw) +{ + /* called in init as well as watchdog timer functions */ + + int32_t ret_val, checksum; + boolean_t tx_filter = FALSE; + struct e1000_host_mng_dhcp_cookie *hdr = &(hw->mng_cookie); + uint8_t *buffer = (uint8_t *) &(hw->mng_cookie); + + if (e1000_check_mng_mode(hw)) { + ret_val = e1000_mng_enable_host_if(hw); + if (ret_val == E1000_SUCCESS) { + ret_val = e1000_host_if_read_cookie(hw, buffer); + if (ret_val == E1000_SUCCESS) { + checksum = hdr->checksum; + hdr->checksum = 0; + if ((hdr->signature == E1000_IAMT_SIGNATURE) && + checksum == e1000_calculate_mng_checksum((char *)buffer, + E1000_MNG_DHCP_COOKIE_LENGTH)) { + if (hdr->status & + E1000_MNG_DHCP_COOKIE_STATUS_PARSING_SUPPORT) + tx_filter = TRUE; + } else + tx_filter = TRUE; + } else + tx_filter = TRUE; + } + } + + hw->tx_pkt_filtering = tx_filter; + return tx_filter; +} + +/****************************************************************************** + * Verifies the hardware needs to allow ARPs to be processed by the host + * + * hw - Struct containing variables accessed by shared code + * + * returns: - TRUE/FALSE + * + *****************************************************************************/ +uint32_t +e1000_enable_mng_pass_thru(struct e1000_hw *hw) +{ + uint32_t manc; + uint32_t fwsm, factps; + + if (hw->asf_firmware_present) { + manc = E1000_READ_REG(hw, MANC); + + if (!(manc & E1000_MANC_RCV_TCO_EN) || + !(manc & E1000_MANC_EN_MAC_ADDR_FILTER)) + return FALSE; + if (e1000_arc_subsystem_valid(hw) == TRUE) { + fwsm = E1000_READ_REG(hw, FWSM); + factps = E1000_READ_REG(hw, FACTPS); + + if (((fwsm & E1000_FWSM_MODE_MASK) == + (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT)) && + (factps & E1000_FACTPS_MNGCG)) + return TRUE; + } else + if ((manc & E1000_MANC_SMBUS_EN) && !(manc & E1000_MANC_ASF_EN)) + return TRUE; + } + return FALSE; +} + +static int32_t +e1000_polarity_reversal_workaround(struct e1000_hw *hw) +{ + int32_t ret_val; + uint16_t mii_status_reg; + uint16_t i; + + /* Polarity reversal workaround for forced 10F/10H links. */ + + /* Disable the transmitter on the PHY */ + + ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019); if(ret_val) return ret_val; ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFFF); @@ -5403,3 +6349,265 @@ e1000_polarity_reversal_workaround(struct e1000_hw *hw) return E1000_SUCCESS; } +/*************************************************************************** + * + * Disables PCI-Express master access. + * + * hw: Struct containing variables accessed by shared code + * + * returns: - none. + * + ***************************************************************************/ +void +e1000_set_pci_express_master_disable(struct e1000_hw *hw) +{ + uint32_t ctrl; + + DEBUGFUNC("e1000_set_pci_express_master_disable"); + + if (hw->bus_type != e1000_bus_type_pci_express) + return; + + ctrl = E1000_READ_REG(hw, CTRL); + ctrl |= E1000_CTRL_GIO_MASTER_DISABLE; + E1000_WRITE_REG(hw, CTRL, ctrl); +} + +/*************************************************************************** + * + * Enables PCI-Express master access. + * + * hw: Struct containing variables accessed by shared code + * + * returns: - none. + * + ***************************************************************************/ +void +e1000_enable_pciex_master(struct e1000_hw *hw) +{ + uint32_t ctrl; + + DEBUGFUNC("e1000_enable_pciex_master"); + + if (hw->bus_type != e1000_bus_type_pci_express) + return; + + ctrl = E1000_READ_REG(hw, CTRL); + ctrl &= ~E1000_CTRL_GIO_MASTER_DISABLE; + E1000_WRITE_REG(hw, CTRL, ctrl); +} + +/******************************************************************************* + * + * Disables PCI-Express master access and verifies there are no pending requests + * + * hw: Struct containing variables accessed by shared code + * + * returns: - E1000_ERR_MASTER_REQUESTS_PENDING if master disable bit hasn't + * caused the master requests to be disabled. + * E1000_SUCCESS master requests disabled. + * + ******************************************************************************/ +int32_t +e1000_disable_pciex_master(struct e1000_hw *hw) +{ + int32_t timeout = MASTER_DISABLE_TIMEOUT; /* 80ms */ + + DEBUGFUNC("e1000_disable_pciex_master"); + + if (hw->bus_type != e1000_bus_type_pci_express) + return E1000_SUCCESS; + + e1000_set_pci_express_master_disable(hw); + + while(timeout) { + if(!(E1000_READ_REG(hw, STATUS) & E1000_STATUS_GIO_MASTER_ENABLE)) + break; + else + udelay(100); + timeout--; + } + + if(!timeout) { + DEBUGOUT("Master requests are pending.\n"); + return -E1000_ERR_MASTER_REQUESTS_PENDING; + } + + return E1000_SUCCESS; +} + +/******************************************************************************* + * + * Check for EEPROM Auto Read bit done. + * + * hw: Struct containing variables accessed by shared code + * + * returns: - E1000_ERR_RESET if fail to reset MAC + * E1000_SUCCESS at any other case. + * + ******************************************************************************/ +int32_t +e1000_get_auto_rd_done(struct e1000_hw *hw) +{ + int32_t timeout = AUTO_READ_DONE_TIMEOUT; + + DEBUGFUNC("e1000_get_auto_rd_done"); + + switch (hw->mac_type) { + default: + msec_delay(5); + break; + case e1000_82573: + while(timeout) { + if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) break; + else msec_delay(1); + timeout--; + } + + if(!timeout) { + DEBUGOUT("Auto read by HW from EEPROM has not completed.\n"); + return -E1000_ERR_RESET; + } + break; + } + + return E1000_SUCCESS; +} + +/*************************************************************************** + * Checks if the PHY configuration is done + * + * hw: Struct containing variables accessed by shared code + * + * returns: - E1000_ERR_RESET if fail to reset MAC + * E1000_SUCCESS at any other case. + * + ***************************************************************************/ +int32_t +e1000_get_phy_cfg_done(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_get_phy_cfg_done"); + + /* Simply wait for 10ms */ + msec_delay(10); + + return E1000_SUCCESS; +} + +/*************************************************************************** + * + * Using the combination of SMBI and SWESMBI semaphore bits when resetting + * adapter or Eeprom access. + * + * hw: Struct containing variables accessed by shared code + * + * returns: - E1000_ERR_EEPROM if fail to access EEPROM. + * E1000_SUCCESS at any other case. + * + ***************************************************************************/ +int32_t +e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw) +{ + int32_t timeout; + uint32_t swsm; + + DEBUGFUNC("e1000_get_hw_eeprom_semaphore"); + + if(!hw->eeprom_semaphore_present) + return E1000_SUCCESS; + + + /* Get the FW semaphore. */ + timeout = hw->eeprom.word_size + 1; + while(timeout) { + swsm = E1000_READ_REG(hw, SWSM); + swsm |= E1000_SWSM_SWESMBI; + E1000_WRITE_REG(hw, SWSM, swsm); + /* if we managed to set the bit we got the semaphore. */ + swsm = E1000_READ_REG(hw, SWSM); + if(swsm & E1000_SWSM_SWESMBI) + break; + + udelay(50); + timeout--; + } + + if(!timeout) { + /* Release semaphores */ + e1000_put_hw_eeprom_semaphore(hw); + DEBUGOUT("Driver can't access the Eeprom - SWESMBI bit is set.\n"); + return -E1000_ERR_EEPROM; + } + + return E1000_SUCCESS; +} + +/*************************************************************************** + * This function clears HW semaphore bits. + * + * hw: Struct containing variables accessed by shared code + * + * returns: - None. + * + ***************************************************************************/ +void +e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw) +{ + uint32_t swsm; + + DEBUGFUNC("e1000_put_hw_eeprom_semaphore"); + + if(!hw->eeprom_semaphore_present) + return; + + swsm = E1000_READ_REG(hw, SWSM); + /* Release both semaphores. */ + swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); + E1000_WRITE_REG(hw, SWSM, swsm); +} + +/****************************************************************************** + * Checks if PHY reset is blocked due to SOL/IDER session, for example. + * Returning E1000_BLK_PHY_RESET isn't necessarily an error. But it's up to + * the caller to figure out how to deal with it. + * + * hw - Struct containing variables accessed by shared code + * + * returns: - E1000_BLK_PHY_RESET + * E1000_SUCCESS + * + *****************************************************************************/ +int32_t +e1000_check_phy_reset_block(struct e1000_hw *hw) +{ + uint32_t manc = 0; + if(hw->mac_type > e1000_82547_rev_2) + manc = E1000_READ_REG(hw, MANC); + return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ? + E1000_BLK_PHY_RESET : E1000_SUCCESS; +} + +uint8_t +e1000_arc_subsystem_valid(struct e1000_hw *hw) +{ + uint32_t fwsm; + + /* On 8257x silicon, registers in the range of 0x8800 - 0x8FFC + * may not be provided a DMA clock when no manageability features are + * enabled. We do not want to perform any reads/writes to these registers + * if this is the case. We read FWSM to determine the manageability mode. + */ + switch (hw->mac_type) { + case e1000_82573: + fwsm = E1000_READ_REG(hw, FWSM); + if((fwsm & E1000_FWSM_MODE_MASK) != 0) + return TRUE; + break; + default: + break; + } + return FALSE; +} + + + diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index f397e637a3c..1573f608fb6 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -57,6 +57,7 @@ typedef enum { e1000_82541_rev_2, e1000_82547, e1000_82547_rev_2, + e1000_82573, e1000_num_macs } e1000_mac_type; @@ -64,6 +65,7 @@ typedef enum { e1000_eeprom_uninitialized = 0, e1000_eeprom_spi, e1000_eeprom_microwire, + e1000_eeprom_flash, e1000_num_eeprom_types } e1000_eeprom_type; @@ -96,6 +98,7 @@ typedef enum { e1000_bus_type_unknown = 0, e1000_bus_type_pci, e1000_bus_type_pcix, + e1000_bus_type_pci_express, e1000_bus_type_reserved } e1000_bus_type; @@ -107,6 +110,7 @@ typedef enum { e1000_bus_speed_100, e1000_bus_speed_120, e1000_bus_speed_133, + e1000_bus_speed_2500, e1000_bus_speed_reserved } e1000_bus_speed; @@ -115,6 +119,8 @@ typedef enum { e1000_bus_width_unknown = 0, e1000_bus_width_32, e1000_bus_width_64, + e1000_bus_width_pciex_1, + e1000_bus_width_pciex_4, e1000_bus_width_reserved } e1000_bus_width; @@ -196,6 +202,7 @@ typedef enum { typedef enum { e1000_phy_m88 = 0, e1000_phy_igp, + e1000_phy_igp_2, e1000_phy_undefined = 0xFF } e1000_phy_type; @@ -242,8 +249,19 @@ struct e1000_eeprom_info { uint16_t address_bits; uint16_t delay_usec; uint16_t page_size; + boolean_t use_eerd; + boolean_t use_eewr; }; +/* Flex ASF Information */ +#define E1000_HOST_IF_MAX_SIZE 2048 + +typedef enum { + e1000_byte_align = 0, + e1000_word_align = 1, + e1000_dword_align = 2 +} e1000_align_type; + /* Error Codes */ @@ -254,11 +272,16 @@ struct e1000_eeprom_info { #define E1000_ERR_PARAM 4 #define E1000_ERR_MAC_TYPE 5 #define E1000_ERR_PHY_TYPE 6 +#define E1000_ERR_RESET 9 +#define E1000_ERR_MASTER_REQUESTS_PENDING 10 +#define E1000_ERR_HOST_INTERFACE_COMMAND 11 +#define E1000_BLK_PHY_RESET 12 /* Function prototypes */ /* Initialization */ int32_t e1000_reset_hw(struct e1000_hw *hw); int32_t e1000_init_hw(struct e1000_hw *hw); +int32_t e1000_id_led_init(struct e1000_hw * hw); int32_t e1000_set_mac_type(struct e1000_hw *hw); void e1000_set_media_type(struct e1000_hw *hw); @@ -275,7 +298,7 @@ int32_t e1000_force_mac_fc(struct e1000_hw *hw); /* PHY */ int32_t e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *phy_data); int32_t e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data); -void e1000_phy_hw_reset(struct e1000_hw *hw); +int32_t e1000_phy_hw_reset(struct e1000_hw *hw); int32_t e1000_phy_reset(struct e1000_hw *hw); int32_t e1000_detect_gig_phy(struct e1000_hw *hw); int32_t e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info); @@ -287,13 +310,86 @@ int32_t e1000_check_downshift(struct e1000_hw *hw); int32_t e1000_validate_mdi_setting(struct e1000_hw *hw); /* EEPROM Functions */ -void e1000_init_eeprom_params(struct e1000_hw *hw); +int32_t e1000_init_eeprom_params(struct e1000_hw *hw); +boolean_t e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw); +int32_t e1000_read_eeprom_eerd(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data); +int32_t e1000_write_eeprom_eewr(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data); +int32_t e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int eerd); + +/* MNG HOST IF functions */ +uint32_t e1000_enable_mng_pass_thru(struct e1000_hw *hw); + +#define E1000_MNG_DHCP_TX_PAYLOAD_CMD 64 +#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8 /* Host Interface data length */ + +#define E1000_MNG_DHCP_COMMAND_TIMEOUT 10 /* Time in ms to process MNG command */ +#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0 /* Cookie offset */ +#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10 /* Cookie length */ +#define E1000_MNG_IAMT_MODE 0x3 +#define E1000_IAMT_SIGNATURE 0x544D4149 /* Intel(R) Active Management Technology signature */ + +#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING_SUPPORT 0x1 /* DHCP parsing enabled */ +#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT 0x2 /* DHCP parsing enabled */ +#define E1000_VFTA_ENTRY_SHIFT 0x5 +#define E1000_VFTA_ENTRY_MASK 0x7F +#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F + +struct e1000_host_mng_command_header { + uint8_t command_id; + uint8_t checksum; + uint16_t reserved1; + uint16_t reserved2; + uint16_t command_length; +}; + +struct e1000_host_mng_command_info { + struct e1000_host_mng_command_header command_header; /* Command Head/Command Result Head has 4 bytes */ + uint8_t command_data[E1000_HI_MAX_MNG_DATA_LENGTH]; /* Command data can length 0..0x658*/ +}; +#ifdef __BIG_ENDIAN +struct e1000_host_mng_dhcp_cookie{ + uint32_t signature; + uint16_t vlan_id; + uint8_t reserved0; + uint8_t status; + uint32_t reserved1; + uint8_t checksum; + uint8_t reserved3; + uint16_t reserved2; +}; +#else +struct e1000_host_mng_dhcp_cookie{ + uint32_t signature; + uint8_t status; + uint8_t reserved0; + uint16_t vlan_id; + uint32_t reserved1; + uint16_t reserved2; + uint8_t reserved3; + uint8_t checksum; +}; +#endif + +int32_t e1000_mng_write_dhcp_info(struct e1000_hw *hw, uint8_t *buffer, + uint16_t length); +boolean_t e1000_check_mng_mode(struct e1000_hw *hw); +boolean_t e1000_enable_tx_pkt_filtering(struct e1000_hw *hw); +int32_t e1000_mng_enable_host_if(struct e1000_hw *hw); +int32_t e1000_mng_host_if_write(struct e1000_hw *hw, uint8_t *buffer, + uint16_t length, uint16_t offset, uint8_t *sum); +int32_t e1000_mng_write_cmd_header(struct e1000_hw* hw, + struct e1000_host_mng_command_header* hdr); + +int32_t e1000_mng_write_commit(struct e1000_hw *hw); + int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t words, uint16_t *data); int32_t e1000_validate_eeprom_checksum(struct e1000_hw *hw); int32_t e1000_update_eeprom_checksum(struct e1000_hw *hw); int32_t e1000_write_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t words, uint16_t *data); int32_t e1000_read_part_num(struct e1000_hw *hw, uint32_t * part_num); int32_t e1000_read_mac_addr(struct e1000_hw * hw); +int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask); +void e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask); /* Filters (multicast, vlan, receive) */ void e1000_init_rx_addrs(struct e1000_hw *hw); @@ -313,7 +409,6 @@ int32_t e1000_led_off(struct e1000_hw *hw); /* Adaptive IFS Functions */ /* Everything else */ -uint32_t e1000_enable_mng_pass_thru(struct e1000_hw *hw); void e1000_clear_hw_cntrs(struct e1000_hw *hw); void e1000_reset_adaptive(struct e1000_hw *hw); void e1000_update_adaptive(struct e1000_hw *hw); @@ -330,6 +425,19 @@ void e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value); void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value); int32_t e1000_config_dsp_after_link_change(struct e1000_hw *hw, boolean_t link_up); int32_t e1000_set_d3_lplu_state(struct e1000_hw *hw, boolean_t active); +int32_t e1000_set_d0_lplu_state(struct e1000_hw *hw, boolean_t active); +void e1000_set_pci_express_master_disable(struct e1000_hw *hw); +void e1000_enable_pciex_master(struct e1000_hw *hw); +int32_t e1000_disable_pciex_master(struct e1000_hw *hw); +int32_t e1000_get_auto_rd_done(struct e1000_hw *hw); +int32_t e1000_get_phy_cfg_done(struct e1000_hw *hw); +int32_t e1000_get_software_semaphore(struct e1000_hw *hw); +void e1000_release_software_semaphore(struct e1000_hw *hw); +int32_t e1000_check_phy_reset_block(struct e1000_hw *hw); +int32_t e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw); +void e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw); +int32_t e1000_commit_shadow_ram(struct e1000_hw *hw); +uint8_t e1000_arc_subsystem_valid(struct e1000_hw *hw); #define E1000_READ_REG_IO(a, reg) \ e1000_read_reg_io((a), E1000_##reg) @@ -369,6 +477,10 @@ int32_t e1000_set_d3_lplu_state(struct e1000_hw *hw, boolean_t active); #define E1000_DEV_ID_82546GB_SERDES 0x107B #define E1000_DEV_ID_82546GB_PCIE 0x108A #define E1000_DEV_ID_82547EI 0x1019 +#define E1000_DEV_ID_82573E 0x108B +#define E1000_DEV_ID_82573E_IAMT 0x108C + +#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099 #define NODE_ADDRESS_SIZE 6 #define ETH_LENGTH_OF_ADDRESS 6 @@ -381,6 +493,7 @@ int32_t e1000_set_d3_lplu_state(struct e1000_hw *hw, boolean_t active); #define E1000_REVISION_0 0 #define E1000_REVISION_1 1 #define E1000_REVISION_2 2 +#define E1000_REVISION_3 3 #define SPEED_10 10 #define SPEED_100 100 @@ -437,6 +550,7 @@ int32_t e1000_set_d3_lplu_state(struct e1000_hw *hw, boolean_t active); E1000_IMS_RXSEQ | \ E1000_IMS_LSC) + /* Number of high/low register pairs in the RAR. The RAR (Receive Address * Registers) holds the directed and multicast addresses that we monitor. We * reserve one of these spots for our directed address, allowing us room for @@ -457,14 +571,74 @@ struct e1000_rx_desc { uint16_t special; }; +/* Receive Descriptor - Extended */ +union e1000_rx_desc_extended { + struct { + uint64_t buffer_addr; + uint64_t reserved; + } read; + struct { + struct { + uint32_t mrq; /* Multiple Rx Queues */ + union { + uint32_t rss; /* RSS Hash */ + struct { + uint16_t ip_id; /* IP id */ + uint16_t csum; /* Packet Checksum */ + } csum_ip; + } hi_dword; + } lower; + struct { + uint32_t status_error; /* ext status/error */ + uint16_t length; + uint16_t vlan; /* VLAN tag */ + } upper; + } wb; /* writeback */ +}; + +#define MAX_PS_BUFFERS 4 +/* Receive Descriptor - Packet Split */ +union e1000_rx_desc_packet_split { + struct { + /* one buffer for protocol header(s), three data buffers */ + uint64_t buffer_addr[MAX_PS_BUFFERS]; + } read; + struct { + struct { + uint32_t mrq; /* Multiple Rx Queues */ + union { + uint32_t rss; /* RSS Hash */ + struct { + uint16_t ip_id; /* IP id */ + uint16_t csum; /* Packet Checksum */ + } csum_ip; + } hi_dword; + } lower; + struct { + uint32_t status_error; /* ext status/error */ + uint16_t length0; /* length of buffer 0 */ + uint16_t vlan; /* VLAN tag */ + } middle; + struct { + uint16_t header_status; + uint16_t length[3]; /* length of buffers 1-3 */ + } upper; + uint64_t reserved; + } wb; /* writeback */ +}; + /* Receive Decriptor bit definitions */ #define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ #define E1000_RXD_STAT_EOP 0x02 /* End of Packet */ #define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */ #define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ +#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum caculated */ #define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */ #define E1000_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ #define E1000_RXD_STAT_PIF 0x80 /* passed in-exact filter */ +#define E1000_RXD_STAT_IPIDV 0x200 /* IP identification valid */ +#define E1000_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */ +#define E1000_RXD_STAT_ACK 0x8000 /* ACK Packet indication */ #define E1000_RXD_ERR_CE 0x01 /* CRC Error */ #define E1000_RXD_ERR_SE 0x02 /* Symbol Error */ #define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */ @@ -474,9 +648,20 @@ struct e1000_rx_desc { #define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */ #define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ #define E1000_RXD_SPC_PRI_MASK 0xE000 /* Priority is in upper 3 bits */ -#define E1000_RXD_SPC_PRI_SHIFT 0x000D /* Priority is in upper 3 of 16 */ +#define E1000_RXD_SPC_PRI_SHIFT 13 #define E1000_RXD_SPC_CFI_MASK 0x1000 /* CFI is bit 12 */ -#define E1000_RXD_SPC_CFI_SHIFT 0x000C /* CFI is bit 12 */ +#define E1000_RXD_SPC_CFI_SHIFT 12 + +#define E1000_RXDEXT_STATERR_CE 0x01000000 +#define E1000_RXDEXT_STATERR_SE 0x02000000 +#define E1000_RXDEXT_STATERR_SEQ 0x04000000 +#define E1000_RXDEXT_STATERR_CXE 0x10000000 +#define E1000_RXDEXT_STATERR_TCPE 0x20000000 +#define E1000_RXDEXT_STATERR_IPE 0x40000000 +#define E1000_RXDEXT_STATERR_RXE 0x80000000 + +#define E1000_RXDPS_HDRSTAT_HDRSP 0x00008000 +#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF /* mask to determine if packets should be dropped due to frame errors */ #define E1000_RXD_ERR_FRAME_ERR_MASK ( \ @@ -486,6 +671,15 @@ struct e1000_rx_desc { E1000_RXD_ERR_CXE | \ E1000_RXD_ERR_RXE) + +/* Same mask, but for extended and packet split descriptors */ +#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \ + E1000_RXDEXT_STATERR_CE | \ + E1000_RXDEXT_STATERR_SE | \ + E1000_RXDEXT_STATERR_SEQ | \ + E1000_RXDEXT_STATERR_CXE | \ + E1000_RXDEXT_STATERR_RXE) + /* Transmit Descriptor */ struct e1000_tx_desc { uint64_t buffer_addr; /* Address of the descriptor's data buffer */ @@ -667,6 +861,7 @@ struct e1000_ffvt_entry { #define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */ #define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */ #define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ +#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */ #define E1000_RCTL 0x00100 /* RX Control - RW */ #define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ #define E1000_TXCW 0x00178 /* TX Configuration Word - RW */ @@ -676,9 +871,23 @@ struct e1000_ffvt_entry { #define E1000_TBT 0x00448 /* TX Burst Timer - RW */ #define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */ #define E1000_LEDCTL 0x00E00 /* LED Control - RW */ +#define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */ +#define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */ #define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */ +#define E1000_PBS 0x01008 /* Packet Buffer Size */ +#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */ +#define E1000_FLASH_UPDATES 1000 +#define E1000_EEARBC 0x01024 /* EEPROM Auto Read Bus Control */ +#define E1000_FLASHT 0x01028 /* FLASH Timer Register */ +#define E1000_EEWR 0x0102C /* EEPROM Write Register - RW */ +#define E1000_FLSWCTL 0x01030 /* FLASH control register */ +#define E1000_FLSWDATA 0x01034 /* FLASH data register */ +#define E1000_FLSWCNT 0x01038 /* FLASH Access Counter */ +#define E1000_FLOP 0x0103C /* FLASH Opcode Register */ +#define E1000_ERT 0x02008 /* Early Rx Threshold - RW */ #define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */ #define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */ +#define E1000_PSRCTL 0x02170 /* Packet Split Receive Control - RW */ #define E1000_RDBAL 0x02800 /* RX Descriptor Base Address Low - RW */ #define E1000_RDBAH 0x02804 /* RX Descriptor Base Address High - RW */ #define E1000_RDLEN 0x02808 /* RX Descriptor Length - RW */ @@ -688,6 +897,7 @@ struct e1000_ffvt_entry { #define E1000_RXDCTL 0x02828 /* RX Descriptor Control - RW */ #define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */ #define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */ +#define E1000_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */ #define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */ #define E1000_TDFH 0x03410 /* TX Data FIFO Head - RW */ #define E1000_TDFT 0x03418 /* TX Data FIFO Tail - RW */ @@ -703,6 +913,14 @@ struct e1000_ffvt_entry { #define E1000_TXDCTL 0x03828 /* TX Descriptor Control - RW */ #define E1000_TADV 0x0382C /* TX Interrupt Absolute Delay Val - RW */ #define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */ +#define E1000_TARC0 0x03840 /* TX Arbitration Count (0) */ +#define E1000_TDBAL1 0x03900 /* TX Desc Base Address Low (1) - RW */ +#define E1000_TDBAH1 0x03904 /* TX Desc Base Address High (1) - RW */ +#define E1000_TDLEN1 0x03908 /* TX Desc Length (1) - RW */ +#define E1000_TDH1 0x03910 /* TX Desc Head (1) - RW */ +#define E1000_TDT1 0x03918 /* TX Desc Tail (1) - RW */ +#define E1000_TXDCTL1 0x03928 /* TX Descriptor Control (1) - RW */ +#define E1000_TARC1 0x03940 /* TX Arbitration Count (1) */ #define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */ #define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */ #define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */ @@ -761,7 +979,17 @@ struct e1000_ffvt_entry { #define E1000_BPTC 0x040F4 /* Broadcast Packets TX Count - R/clr */ #define E1000_TSCTC 0x040F8 /* TCP Segmentation Context TX - R/clr */ #define E1000_TSCTFC 0x040FC /* TCP Segmentation Context TX Fail - R/clr */ +#define E1000_IAC 0x4100 /* Interrupt Assertion Count */ +#define E1000_ICRXPTC 0x4104 /* Interrupt Cause Rx Packet Timer Expire Count */ +#define E1000_ICRXATC 0x4108 /* Interrupt Cause Rx Absolute Timer Expire Count */ +#define E1000_ICTXPTC 0x410C /* Interrupt Cause Tx Packet Timer Expire Count */ +#define E1000_ICTXATC 0x4110 /* Interrupt Cause Tx Absolute Timer Expire Count */ +#define E1000_ICTXQEC 0x4118 /* Interrupt Cause Tx Queue Empty Count */ +#define E1000_ICTXQMTC 0x411C /* Interrupt Cause Tx Queue Minimum Threshold Count */ +#define E1000_ICRXDMTC 0x4120 /* Interrupt Cause Rx Descriptor Minimum Threshold Count */ +#define E1000_ICRXOC 0x4124 /* Interrupt Cause Receiver Overrun Count */ #define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */ +#define E1000_RFCTL 0x05008 /* Receive Filter Control*/ #define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ #define E1000_RA 0x05400 /* Receive Address - RW Array */ #define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */ @@ -779,6 +1007,16 @@ struct e1000_ffvt_entry { #define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */ #define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */ +#define E1000_GCR 0x05B00 /* PCI-Ex Control */ +#define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */ +#define E1000_GSCL_2 0x05B14 /* PCI-Ex Statistic Control #2 */ +#define E1000_GSCL_3 0x05B18 /* PCI-Ex Statistic Control #3 */ +#define E1000_GSCL_4 0x05B1C /* PCI-Ex Statistic Control #4 */ +#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */ +#define E1000_SWSM 0x05B50 /* SW Semaphore */ +#define E1000_FWSM 0x05B54 /* FW Semaphore */ +#define E1000_FFLT_DBG 0x05F04 /* Debug Register */ +#define E1000_HICR 0x08F00 /* Host Inteface Control */ /* Register Set (82542) * * Some of the 82542 registers are located at different offsets than they are @@ -829,6 +1067,18 @@ struct e1000_ffvt_entry { #define E1000_82542_VFTA 0x00600 #define E1000_82542_LEDCTL E1000_LEDCTL #define E1000_82542_PBA E1000_PBA +#define E1000_82542_PBS E1000_PBS +#define E1000_82542_EEMNGCTL E1000_EEMNGCTL +#define E1000_82542_EEARBC E1000_EEARBC +#define E1000_82542_FLASHT E1000_FLASHT +#define E1000_82542_EEWR E1000_EEWR +#define E1000_82542_FLSWCTL E1000_FLSWCTL +#define E1000_82542_FLSWDATA E1000_FLSWDATA +#define E1000_82542_FLSWCNT E1000_FLSWCNT +#define E1000_82542_FLOP E1000_FLOP +#define E1000_82542_EXTCNF_CTRL E1000_EXTCNF_CTRL +#define E1000_82542_EXTCNF_SIZE E1000_EXTCNF_SIZE +#define E1000_82542_ERT E1000_ERT #define E1000_82542_RXDCTL E1000_RXDCTL #define E1000_82542_RADV E1000_RADV #define E1000_82542_RSRPD E1000_RSRPD @@ -913,6 +1163,38 @@ struct e1000_ffvt_entry { #define E1000_82542_FFMT E1000_FFMT #define E1000_82542_FFVT E1000_FFVT #define E1000_82542_HOST_IF E1000_HOST_IF +#define E1000_82542_IAM E1000_IAM +#define E1000_82542_EEMNGCTL E1000_EEMNGCTL +#define E1000_82542_PSRCTL E1000_PSRCTL +#define E1000_82542_RAID E1000_RAID +#define E1000_82542_TARC0 E1000_TARC0 +#define E1000_82542_TDBAL1 E1000_TDBAL1 +#define E1000_82542_TDBAH1 E1000_TDBAH1 +#define E1000_82542_TDLEN1 E1000_TDLEN1 +#define E1000_82542_TDH1 E1000_TDH1 +#define E1000_82542_TDT1 E1000_TDT1 +#define E1000_82542_TXDCTL1 E1000_TXDCTL1 +#define E1000_82542_TARC1 E1000_TARC1 +#define E1000_82542_RFCTL E1000_RFCTL +#define E1000_82542_GCR E1000_GCR +#define E1000_82542_GSCL_1 E1000_GSCL_1 +#define E1000_82542_GSCL_2 E1000_GSCL_2 +#define E1000_82542_GSCL_3 E1000_GSCL_3 +#define E1000_82542_GSCL_4 E1000_GSCL_4 +#define E1000_82542_FACTPS E1000_FACTPS +#define E1000_82542_SWSM E1000_SWSM +#define E1000_82542_FWSM E1000_FWSM +#define E1000_82542_FFLT_DBG E1000_FFLT_DBG +#define E1000_82542_IAC E1000_IAC +#define E1000_82542_ICRXPTC E1000_ICRXPTC +#define E1000_82542_ICRXATC E1000_ICRXATC +#define E1000_82542_ICTXPTC E1000_ICTXPTC +#define E1000_82542_ICTXATC E1000_ICTXATC +#define E1000_82542_ICTXQEC E1000_ICTXQEC +#define E1000_82542_ICTXQMTC E1000_ICTXQMTC +#define E1000_82542_ICRXDMTC E1000_ICRXDMTC +#define E1000_82542_ICRXOC E1000_ICRXOC +#define E1000_82542_HICR E1000_HICR /* Statistics counters collected by the MAC */ struct e1000_hw_stats { @@ -974,11 +1256,21 @@ struct e1000_hw_stats { uint64_t bptc; uint64_t tsctc; uint64_t tsctfc; + uint64_t iac; + uint64_t icrxptc; + uint64_t icrxatc; + uint64_t ictxptc; + uint64_t ictxatc; + uint64_t ictxqec; + uint64_t ictxqmtc; + uint64_t icrxdmtc; + uint64_t icrxoc; }; /* Structure containing variables used by the shared code (e1000_hw.c) */ struct e1000_hw { - uint8_t __iomem *hw_addr; + uint8_t *hw_addr; + uint8_t *flash_address; e1000_mac_type mac_type; e1000_phy_type phy_type; uint32_t phy_init_script; @@ -993,6 +1285,7 @@ struct e1000_hw { e1000_ms_type original_master_slave; e1000_ffe_config ffe_config_state; uint32_t asf_firmware_present; + uint32_t eeprom_semaphore_present; unsigned long io_base; uint32_t phy_id; uint32_t phy_revision; @@ -1009,6 +1302,8 @@ struct e1000_hw { uint32_t ledctl_default; uint32_t ledctl_mode1; uint32_t ledctl_mode2; + boolean_t tx_pkt_filtering; + struct e1000_host_mng_dhcp_cookie mng_cookie; uint16_t phy_spd_default; uint16_t autoneg_advertised; uint16_t pci_cmd_word; @@ -1047,16 +1342,24 @@ struct e1000_hw { boolean_t adaptive_ifs; boolean_t ifs_params_forced; boolean_t in_ifs_mode; + boolean_t mng_reg_access_disabled; }; #define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */ #define E1000_EEPROM_LED_LOGIC 0x0020 /* Led Logic Word */ +#define E1000_EEPROM_RW_REG_DATA 16 /* Offset to data in EEPROM read/write registers */ +#define E1000_EEPROM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */ +#define E1000_EEPROM_RW_REG_START 1 /* First bit for telling part to start operation */ +#define E1000_EEPROM_RW_ADDR_SHIFT 2 /* Shift to the address bits */ +#define E1000_EEPROM_POLL_WRITE 1 /* Flag for polling for write complete */ +#define E1000_EEPROM_POLL_READ 0 /* Flag for polling for read complete */ /* Register Bit Masks */ /* Device Control */ #define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ #define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */ #define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */ +#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */ #define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */ #define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */ #define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */ @@ -1070,6 +1373,7 @@ struct e1000_hw { #define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */ #define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ #define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ +#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */ #define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ #define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ #define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */ @@ -1089,6 +1393,7 @@ struct e1000_hw { #define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ #define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */ #define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */ +#define E1000_STATUS_FUNC_SHIFT 2 #define E1000_STATUS_FUNC_0 0x00000000 /* Function 0 */ #define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */ #define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */ @@ -1098,6 +1403,8 @@ struct e1000_hw { #define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ #define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ #define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */ +#define E1000_STATUS_DOCK_CI 0x00000800 /* Change in Dock/Undock state. Clear on write '0'. */ +#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */ #define E1000_STATUS_MTXCKOK 0x00000400 /* MTX clock running OK */ #define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */ #define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */ @@ -1128,6 +1435,18 @@ struct e1000_hw { #ifndef E1000_EEPROM_GRANT_ATTEMPTS #define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */ #endif +#define E1000_EECD_AUTO_RD 0x00000200 /* EEPROM Auto Read done */ +#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* EEprom Size */ +#define E1000_EECD_SIZE_EX_SHIFT 11 +#define E1000_EECD_NVADDS 0x00018000 /* NVM Address Size */ +#define E1000_EECD_SELSHAD 0x00020000 /* Select Shadow RAM */ +#define E1000_EECD_INITSRAM 0x00040000 /* Initialize Shadow RAM */ +#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */ +#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */ +#define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */ +#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */ +#define E1000_STM_OPCODE 0xDB00 +#define E1000_HICR_FW_RESET 0xC0 /* EEPROM Read */ #define E1000_EERD_START 0x00000001 /* Start Read */ @@ -1171,6 +1490,8 @@ struct e1000_hw { #define E1000_CTRL_EXT_WR_WMARK_320 0x01000000 #define E1000_CTRL_EXT_WR_WMARK_384 0x02000000 #define E1000_CTRL_EXT_WR_WMARK_448 0x03000000 +#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */ +#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */ /* MDI Control */ #define E1000_MDIC_DATA_MASK 0x0000FFFF @@ -1187,14 +1508,17 @@ struct e1000_hw { /* LED Control */ #define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F #define E1000_LEDCTL_LED0_MODE_SHIFT 0 +#define E1000_LEDCTL_LED0_BLINK_RATE 0x0000020 #define E1000_LEDCTL_LED0_IVRT 0x00000040 #define E1000_LEDCTL_LED0_BLINK 0x00000080 #define E1000_LEDCTL_LED1_MODE_MASK 0x00000F00 #define E1000_LEDCTL_LED1_MODE_SHIFT 8 +#define E1000_LEDCTL_LED1_BLINK_RATE 0x0002000 #define E1000_LEDCTL_LED1_IVRT 0x00004000 #define E1000_LEDCTL_LED1_BLINK 0x00008000 #define E1000_LEDCTL_LED2_MODE_MASK 0x000F0000 #define E1000_LEDCTL_LED2_MODE_SHIFT 16 +#define E1000_LEDCTL_LED2_BLINK_RATE 0x00200000 #define E1000_LEDCTL_LED2_IVRT 0x00400000 #define E1000_LEDCTL_LED2_BLINK 0x00800000 #define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000 @@ -1238,6 +1562,10 @@ struct e1000_hw { #define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */ #define E1000_ICR_TXD_LOW 0x00008000 #define E1000_ICR_SRPD 0x00010000 +#define E1000_ICR_ACK 0x00020000 /* Receive Ack frame */ +#define E1000_ICR_MNG 0x00040000 /* Manageability event */ +#define E1000_ICR_DOCK 0x00080000 /* Dock/Undock */ +#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */ /* Interrupt Cause Set */ #define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ @@ -1255,6 +1583,9 @@ struct e1000_hw { #define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ #define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW #define E1000_ICS_SRPD E1000_ICR_SRPD +#define E1000_ICS_ACK E1000_ICR_ACK /* Receive Ack frame */ +#define E1000_ICS_MNG E1000_ICR_MNG /* Manageability event */ +#define E1000_ICS_DOCK E1000_ICR_DOCK /* Dock/Undock */ /* Interrupt Mask Set */ #define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ @@ -1272,6 +1603,9 @@ struct e1000_hw { #define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ #define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW #define E1000_IMS_SRPD E1000_ICR_SRPD +#define E1000_IMS_ACK E1000_ICR_ACK /* Receive Ack frame */ +#define E1000_IMS_MNG E1000_ICR_MNG /* Manageability event */ +#define E1000_IMS_DOCK E1000_ICR_DOCK /* Dock/Undock */ /* Interrupt Mask Clear */ #define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back */ @@ -1289,6 +1623,9 @@ struct e1000_hw { #define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ #define E1000_IMC_TXD_LOW E1000_ICR_TXD_LOW #define E1000_IMC_SRPD E1000_ICR_SRPD +#define E1000_IMC_ACK E1000_ICR_ACK /* Receive Ack frame */ +#define E1000_IMC_MNG E1000_ICR_MNG /* Manageability event */ +#define E1000_IMC_DOCK E1000_ICR_DOCK /* Dock/Undock */ /* Receive Control */ #define E1000_RCTL_RST 0x00000001 /* Software reset */ @@ -1301,6 +1638,8 @@ struct e1000_hw { #define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ #define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */ #define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ +#define E1000_RCTL_DTYP_MASK 0x00000C00 /* Descriptor type mask */ +#define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */ #define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */ #define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min threshold size */ #define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min threshold size */ @@ -1327,6 +1666,34 @@ struct e1000_hw { #define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ #define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ #define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ +#define E1000_RCTL_FLXBUF_MASK 0x78000000 /* Flexible buffer size */ +#define E1000_RCTL_FLXBUF_SHIFT 27 /* Flexible buffer shift */ + +/* Use byte values for the following shift parameters + * Usage: + * psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) & + * E1000_PSRCTL_BSIZE0_MASK) | + * ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) & + * E1000_PSRCTL_BSIZE1_MASK) | + * ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) & + * E1000_PSRCTL_BSIZE2_MASK) | + * ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |; + * E1000_PSRCTL_BSIZE3_MASK)) + * where value0 = [128..16256], default=256 + * value1 = [1024..64512], default=4096 + * value2 = [0..64512], default=4096 + * value3 = [0..64512], default=0 + */ + +#define E1000_PSRCTL_BSIZE0_MASK 0x0000007F +#define E1000_PSRCTL_BSIZE1_MASK 0x00003F00 +#define E1000_PSRCTL_BSIZE2_MASK 0x003F0000 +#define E1000_PSRCTL_BSIZE3_MASK 0x3F000000 + +#define E1000_PSRCTL_BSIZE0_SHIFT 7 /* Shift _right_ 7 */ +#define E1000_PSRCTL_BSIZE1_SHIFT 2 /* Shift _right_ 2 */ +#define E1000_PSRCTL_BSIZE2_SHIFT 6 /* Shift _left_ 6 */ +#define E1000_PSRCTL_BSIZE3_SHIFT 14 /* Shift _left_ 14 */ /* Receive Descriptor */ #define E1000_RDT_DELAY 0x0000ffff /* Delay timer (1=1024us) */ @@ -1341,6 +1708,23 @@ struct e1000_hw { #define E1000_FCRTL_RTL 0x0000FFF8 /* Mask Bits[15:3] for RTL */ #define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */ +/* Header split receive */ +#define E1000_RFCTL_ISCSI_DIS 0x00000001 +#define E1000_RFCTL_ISCSI_DWC_MASK 0x0000003E +#define E1000_RFCTL_ISCSI_DWC_SHIFT 1 +#define E1000_RFCTL_NFSW_DIS 0x00000040 +#define E1000_RFCTL_NFSR_DIS 0x00000080 +#define E1000_RFCTL_NFS_VER_MASK 0x00000300 +#define E1000_RFCTL_NFS_VER_SHIFT 8 +#define E1000_RFCTL_IPV6_DIS 0x00000400 +#define E1000_RFCTL_IPV6_XSUM_DIS 0x00000800 +#define E1000_RFCTL_ACK_DIS 0x00001000 +#define E1000_RFCTL_ACKD_DIS 0x00002000 +#define E1000_RFCTL_IPFRSP_DIS 0x00004000 +#define E1000_RFCTL_EXTEN 0x00008000 +#define E1000_RFCTL_IPV6_EX_DIS 0x00010000 +#define E1000_RFCTL_NEW_IPV6_EXT_DIS 0x00020000 + /* Receive Descriptor Control */ #define E1000_RXDCTL_PTHRESH 0x0000003F /* RXDCTL Prefetch Threshold */ #define E1000_RXDCTL_HTHRESH 0x00003F00 /* RXDCTL Host Threshold */ @@ -1354,6 +1738,8 @@ struct e1000_hw { #define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */ #define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */ #define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */ +#define E1000_TXDCTL_COUNT_DESC 0x00400000 /* Enable the counting of desc. + still to be processed. */ /* Transmit Configuration Word */ #define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */ @@ -1387,12 +1773,16 @@ struct e1000_hw { #define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */ #define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ #define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */ +#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */ /* Receive Checksum Control */ #define E1000_RXCSUM_PCSS_MASK 0x000000FF /* Packet Checksum Start */ #define E1000_RXCSUM_IPOFL 0x00000100 /* IPv4 checksum offload */ #define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */ #define E1000_RXCSUM_IPV6OFL 0x00000400 /* IPv6 checksum offload */ +#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ +#define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */ + /* Definitions for power management and wakeup registers */ /* Wake Up Control */ @@ -1411,6 +1801,7 @@ struct e1000_hw { #define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */ #define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */ #define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */ +#define E1000_WUFC_IGNORE_TCO 0x00008000 /* Ignore WakeOn TCO packets */ #define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */ #define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */ #define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */ @@ -1446,13 +1837,19 @@ struct e1000_hw { #define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */ #define E1000_MANC_NEIGHBOR_EN 0x00004000 /* Enable Neighbor Discovery * Filtering */ +#define E1000_MANC_ARP_RES_EN 0x00008000 /* Enable ARP response Filtering */ #define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */ #define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ #define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */ +#define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */ #define E1000_MANC_EN_MAC_ADDR_FILTER 0x00100000 /* Enable MAC address * filtering */ #define E1000_MANC_EN_MNG2HOST 0x00200000 /* Enable MNG packets to host * memory */ +#define E1000_MANC_EN_IP_ADDR_FILTER 0x00400000 /* Enable IP address + * filtering */ +#define E1000_MANC_EN_XSUM_FILTER 0x00800000 /* Enable checksum filtering */ +#define E1000_MANC_BR_EN 0x01000000 /* Enable broadcast filtering */ #define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */ #define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */ #define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */ @@ -1463,11 +1860,97 @@ struct e1000_hw { #define E1000_MANC_SMB_DATA_OUT_SHIFT 28 /* SMBus Data Out Shift */ #define E1000_MANC_SMB_CLK_OUT_SHIFT 29 /* SMBus Clock Out Shift */ +/* SW Semaphore Register */ +#define E1000_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ +#define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ +#define E1000_SWSM_WMNG 0x00000004 /* Wake MNG Clock */ +#define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */ + +/* FW Semaphore Register */ +#define E1000_FWSM_MODE_MASK 0x0000000E /* FW mode */ +#define E1000_FWSM_MODE_SHIFT 1 +#define E1000_FWSM_FW_VALID 0x00008000 /* FW established a valid mode */ + +/* FFLT Debug Register */ +#define E1000_FFLT_DBG_INVC 0x00100000 /* Invalid /C/ code handling */ + +typedef enum { + e1000_mng_mode_none = 0, + e1000_mng_mode_asf, + e1000_mng_mode_pt, + e1000_mng_mode_ipmi, + e1000_mng_mode_host_interface_only +} e1000_mng_mode; + +/* Host Inteface Control Register */ +#define E1000_HICR_EN 0x00000001 /* Enable Bit - RO */ +#define E1000_HICR_C 0x00000002 /* Driver sets this bit when done + * to put command in RAM */ +#define E1000_HICR_SV 0x00000004 /* Status Validity */ +#define E1000_HICR_FWR 0x00000080 /* FW reset. Set by the Host */ + +/* Host Interface Command Interface - Address range 0x8800-0x8EFF */ +#define E1000_HI_MAX_DATA_LENGTH 252 /* Host Interface data length */ +#define E1000_HI_MAX_BLOCK_BYTE_LENGTH 1792 /* Number of bytes in range */ +#define E1000_HI_MAX_BLOCK_DWORD_LENGTH 448 /* Number of dwords in range */ +#define E1000_HI_COMMAND_TIMEOUT 500 /* Time in ms to process HI command */ + +struct e1000_host_command_header { + uint8_t command_id; + uint8_t command_length; + uint8_t command_options; /* I/F bits for command, status for return */ + uint8_t checksum; +}; +struct e1000_host_command_info { + struct e1000_host_command_header command_header; /* Command Head/Command Result Head has 4 bytes */ + uint8_t command_data[E1000_HI_MAX_DATA_LENGTH]; /* Command data can length 0..252 */ +}; + +/* Host SMB register #0 */ +#define E1000_HSMC0R_CLKIN 0x00000001 /* SMB Clock in */ +#define E1000_HSMC0R_DATAIN 0x00000002 /* SMB Data in */ +#define E1000_HSMC0R_DATAOUT 0x00000004 /* SMB Data out */ +#define E1000_HSMC0R_CLKOUT 0x00000008 /* SMB Clock out */ + +/* Host SMB register #1 */ +#define E1000_HSMC1R_CLKIN E1000_HSMC0R_CLKIN +#define E1000_HSMC1R_DATAIN E1000_HSMC0R_DATAIN +#define E1000_HSMC1R_DATAOUT E1000_HSMC0R_DATAOUT +#define E1000_HSMC1R_CLKOUT E1000_HSMC0R_CLKOUT + +/* FW Status Register */ +#define E1000_FWSTS_FWS_MASK 0x000000FF /* FW Status */ + /* Wake Up Packet Length */ #define E1000_WUPL_LENGTH_MASK 0x0FFF /* Only the lower 12 bits are valid */ #define E1000_MDALIGN 4096 +#define E1000_GCR_BEM32 0x00400000 +/* Function Active and Power State to MNG */ +#define E1000_FACTPS_FUNC0_POWER_STATE_MASK 0x00000003 +#define E1000_FACTPS_LAN0_VALID 0x00000004 +#define E1000_FACTPS_FUNC0_AUX_EN 0x00000008 +#define E1000_FACTPS_FUNC1_POWER_STATE_MASK 0x000000C0 +#define E1000_FACTPS_FUNC1_POWER_STATE_SHIFT 6 +#define E1000_FACTPS_LAN1_VALID 0x00000100 +#define E1000_FACTPS_FUNC1_AUX_EN 0x00000200 +#define E1000_FACTPS_FUNC2_POWER_STATE_MASK 0x00003000 +#define E1000_FACTPS_FUNC2_POWER_STATE_SHIFT 12 +#define E1000_FACTPS_IDE_ENABLE 0x00004000 +#define E1000_FACTPS_FUNC2_AUX_EN 0x00008000 +#define E1000_FACTPS_FUNC3_POWER_STATE_MASK 0x000C0000 +#define E1000_FACTPS_FUNC3_POWER_STATE_SHIFT 18 +#define E1000_FACTPS_SP_ENABLE 0x00100000 +#define E1000_FACTPS_FUNC3_AUX_EN 0x00200000 +#define E1000_FACTPS_FUNC4_POWER_STATE_MASK 0x03000000 +#define E1000_FACTPS_FUNC4_POWER_STATE_SHIFT 24 +#define E1000_FACTPS_IPMI_ENABLE 0x04000000 +#define E1000_FACTPS_FUNC4_AUX_EN 0x08000000 +#define E1000_FACTPS_MNGCG 0x20000000 +#define E1000_FACTPS_LAN_FUNC_SEL 0x40000000 +#define E1000_FACTPS_PM_STATE_CHANGED 0x80000000 + /* EEPROM Commands - Microwire */ #define EEPROM_READ_OPCODE_MICROWIRE 0x6 /* EEPROM read opcode */ #define EEPROM_WRITE_OPCODE_MICROWIRE 0x5 /* EEPROM write opcode */ @@ -1477,22 +1960,20 @@ struct e1000_hw { /* EEPROM Commands - SPI */ #define EEPROM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */ -#define EEPROM_READ_OPCODE_SPI 0x3 /* EEPROM read opcode */ -#define EEPROM_WRITE_OPCODE_SPI 0x2 /* EEPROM write opcode */ -#define EEPROM_A8_OPCODE_SPI 0x8 /* opcode bit-3 = address bit-8 */ -#define EEPROM_WREN_OPCODE_SPI 0x6 /* EEPROM set Write Enable latch */ -#define EEPROM_WRDI_OPCODE_SPI 0x4 /* EEPROM reset Write Enable latch */ -#define EEPROM_RDSR_OPCODE_SPI 0x5 /* EEPROM read Status register */ -#define EEPROM_WRSR_OPCODE_SPI 0x1 /* EEPROM write Status register */ +#define EEPROM_READ_OPCODE_SPI 0x03 /* EEPROM read opcode */ +#define EEPROM_WRITE_OPCODE_SPI 0x02 /* EEPROM write opcode */ +#define EEPROM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = address bit-8 */ +#define EEPROM_WREN_OPCODE_SPI 0x06 /* EEPROM set Write Enable latch */ +#define EEPROM_WRDI_OPCODE_SPI 0x04 /* EEPROM reset Write Enable latch */ +#define EEPROM_RDSR_OPCODE_SPI 0x05 /* EEPROM read Status register */ +#define EEPROM_WRSR_OPCODE_SPI 0x01 /* EEPROM write Status register */ +#define EEPROM_ERASE4K_OPCODE_SPI 0x20 /* EEPROM ERASE 4KB */ +#define EEPROM_ERASE64K_OPCODE_SPI 0xD8 /* EEPROM ERASE 64KB */ +#define EEPROM_ERASE256_OPCODE_SPI 0xDB /* EEPROM ERASE 256B */ /* EEPROM Size definitions */ -#define EEPROM_SIZE_16KB 0x1800 -#define EEPROM_SIZE_8KB 0x1400 -#define EEPROM_SIZE_4KB 0x1000 -#define EEPROM_SIZE_2KB 0x0C00 -#define EEPROM_SIZE_1KB 0x0800 -#define EEPROM_SIZE_512B 0x0400 -#define EEPROM_SIZE_128B 0x0000 +#define EEPROM_WORD_SIZE_SHIFT 6 +#define EEPROM_SIZE_SHIFT 10 #define EEPROM_SIZE_MASK 0x1C00 /* EEPROM Word Offsets */ @@ -1606,7 +2087,22 @@ struct e1000_hw { #define IFS_MIN 40 #define IFS_RATIO 4 +/* Extended Configuration Control and Size */ +#define E1000_EXTCNF_CTRL_PCIE_WRITE_ENABLE 0x00000001 +#define E1000_EXTCNF_CTRL_PHY_WRITE_ENABLE 0x00000002 +#define E1000_EXTCNF_CTRL_D_UD_ENABLE 0x00000004 +#define E1000_EXTCNF_CTRL_D_UD_LATENCY 0x00000008 +#define E1000_EXTCNF_CTRL_D_UD_OWNER 0x00000010 +#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020 +#define E1000_EXTCNF_CTRL_MDIO_HW_OWNERSHIP 0x00000040 +#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER 0x1FFF0000 + +#define E1000_EXTCNF_SIZE_EXT_PHY_LENGTH 0x000000FF +#define E1000_EXTCNF_SIZE_EXT_DOCK_LENGTH 0x0000FF00 +#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH 0x00FF0000 + /* PBA constants */ +#define E1000_PBA_12K 0x000C /* 12KB, default Rx allocation */ #define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */ #define E1000_PBA_22K 0x0016 #define E1000_PBA_24K 0x0018 @@ -1663,6 +2159,13 @@ struct e1000_hw { /* Number of milliseconds we wait for auto-negotiation to complete */ #define LINK_UP_TIMEOUT 500 +/* Number of 100 microseconds we wait for PCI Express master disable */ +#define MASTER_DISABLE_TIMEOUT 800 +/* Number of milliseconds we wait for Eeprom auto read bit done after MAC reset */ +#define AUTO_READ_DONE_TIMEOUT 10 +/* Number of milliseconds we wait for PHY configuration done after MAC reset */ +#define PHY_CFG_TIMEOUT 40 + #define E1000_TX_BUFFER_SIZE ((uint32_t)1514) /* The carrier extension symbol, as received by the NIC. */ @@ -1763,6 +2266,7 @@ struct e1000_hw { #define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health Register */ #define IGP01E1000_GMII_FIFO 0x14 /* GMII FIFO Register */ #define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality Register */ +#define IGP02E1000_PHY_POWER_MGMT 0x19 #define IGP01E1000_PHY_PAGE_SELECT 0x1F /* PHY Page Select Core Register */ /* IGP01E1000 AGC Registers - stores the cable length values*/ @@ -1771,12 +2275,20 @@ struct e1000_hw { #define IGP01E1000_PHY_AGC_C 0x1472 #define IGP01E1000_PHY_AGC_D 0x1872 +/* IGP02E1000 AGC Registers for cable length values */ +#define IGP02E1000_PHY_AGC_A 0x11B1 +#define IGP02E1000_PHY_AGC_B 0x12B1 +#define IGP02E1000_PHY_AGC_C 0x14B1 +#define IGP02E1000_PHY_AGC_D 0x18B1 + /* IGP01E1000 DSP Reset Register */ #define IGP01E1000_PHY_DSP_RESET 0x1F33 #define IGP01E1000_PHY_DSP_SET 0x1F71 #define IGP01E1000_PHY_DSP_FFE 0x1F35 #define IGP01E1000_PHY_CHANNEL_NUM 4 +#define IGP02E1000_PHY_CHANNEL_NUM 4 + #define IGP01E1000_PHY_AGC_PARAM_A 0x1171 #define IGP01E1000_PHY_AGC_PARAM_B 0x1271 #define IGP01E1000_PHY_AGC_PARAM_C 0x1471 @@ -2060,20 +2572,30 @@ struct e1000_hw { #define IGP01E1000_MSE_CHANNEL_B 0x0F00 #define IGP01E1000_MSE_CHANNEL_A 0xF000 +#define IGP02E1000_PM_SPD 0x0001 /* Smart Power Down */ +#define IGP02E1000_PM_D3_LPLU 0x0004 /* Enable LPLU in non-D0a modes */ +#define IGP02E1000_PM_D0_LPLU 0x0002 /* Enable LPLU in D0a mode */ + /* IGP01E1000 DSP reset macros */ #define DSP_RESET_ENABLE 0x0 #define DSP_RESET_DISABLE 0x2 #define E1000_MAX_DSP_RESETS 10 -/* IGP01E1000 AGC Registers */ +/* IGP01E1000 & IGP02E1000 AGC Registers */ #define IGP01E1000_AGC_LENGTH_SHIFT 7 /* Coarse - 13:11, Fine - 10:7 */ +#define IGP02E1000_AGC_LENGTH_SHIFT 9 /* Coarse - 15:13, Fine - 12:9 */ + +/* IGP02E1000 AGC Register Length 9-bit mask */ +#define IGP02E1000_AGC_LENGTH_MASK 0x7F /* 7 bits (3 Coarse + 4 Fine) --> 128 optional values */ #define IGP01E1000_AGC_LENGTH_TABLE_SIZE 128 +#define IGP02E1000_AGC_LENGTH_TABLE_SIZE 128 -/* The precision of the length is +/- 10 meters */ +/* The precision error of the cable length is +/- 10 meters */ #define IGP01E1000_AGC_RANGE 10 +#define IGP02E1000_AGC_RANGE 10 /* IGP01E1000 PCS Initialization register */ /* bits 3:6 in the PCS registers stores the channels polarity */ @@ -2113,6 +2635,8 @@ struct e1000_hw { #define M88E1000_12_PHY_ID M88E1000_E_PHY_ID #define M88E1000_14_PHY_ID M88E1000_E_PHY_ID #define M88E1011_I_REV_4 0x04 +#define M88E1111_I_PHY_ID 0x01410CC0 +#define L1LXT971A_PHY_ID 0x001378E0 /* Miscellaneous PHY bit definitions. */ #define PHY_PREAMBLE 0xFFFFFFFF diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 4cdf371961e..5e6e1f7fd77 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -155,10 +155,14 @@ static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter); static int e1000_clean(struct net_device *netdev, int *budget); static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter, int *work_done, int work_to_do); +static boolean_t e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, + int *work_done, int work_to_do); #else static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter); +static boolean_t e1000_clean_rx_irq_ps(struct e1000_adapter *adapter); #endif static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter); +static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter); static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); @@ -286,7 +290,29 @@ e1000_irq_enable(struct e1000_adapter *adapter) E1000_WRITE_FLUSH(&adapter->hw); } } - +void +e1000_update_mng_vlan(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + uint16_t vid = adapter->hw.mng_cookie.vlan_id; + uint16_t old_vid = adapter->mng_vlan_id; + if(adapter->vlgrp) { + if(!adapter->vlgrp->vlan_devices[vid]) { + if(adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) { + e1000_vlan_rx_add_vid(netdev, vid); + adapter->mng_vlan_id = vid; + } else + adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; + + if((old_vid != (uint16_t)E1000_MNG_VLAN_NONE) && + (vid != old_vid) && + !adapter->vlgrp->vlan_devices[old_vid]) + e1000_vlan_rx_kill_vid(netdev, old_vid); + } + } +} + int e1000_up(struct e1000_adapter *adapter) { @@ -310,7 +336,7 @@ e1000_up(struct e1000_adapter *adapter) e1000_configure_tx(adapter); e1000_setup_rctl(adapter); e1000_configure_rx(adapter); - e1000_alloc_rx_buffers(adapter); + adapter->alloc_rx_buf(adapter); #ifdef CONFIG_PCI_MSI if(adapter->hw.mac_type > e1000_82547_rev_2) { @@ -366,8 +392,12 @@ e1000_down(struct e1000_adapter *adapter) e1000_clean_rx_ring(adapter); /* If WoL is not enabled + * and management mode is not IAMT * Power down the PHY so no link is implied when interface is down */ - if(!adapter->wol && adapter->hw.media_type == e1000_media_type_copper) { + if(!adapter->wol && adapter->hw.mac_type >= e1000_82540 && + adapter->hw.media_type == e1000_media_type_copper && + !e1000_check_mng_mode(&adapter->hw) && + !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN)) { uint16_t mii_reg; e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg); mii_reg |= MII_CR_POWER_DOWN; @@ -379,28 +409,34 @@ e1000_down(struct e1000_adapter *adapter) void e1000_reset(struct e1000_adapter *adapter) { - uint32_t pba; + uint32_t pba, manc; /* Repartition Pba for greater than 9k mtu * To take effect CTRL.RST is required. */ - if(adapter->hw.mac_type < e1000_82547) { - if(adapter->rx_buffer_len > E1000_RXBUFFER_8192) - pba = E1000_PBA_40K; - else - pba = E1000_PBA_48K; - } else { - if(adapter->rx_buffer_len > E1000_RXBUFFER_8192) - pba = E1000_PBA_22K; - else - pba = E1000_PBA_30K; + switch (adapter->hw.mac_type) { + case e1000_82547: + pba = E1000_PBA_30K; + break; + case e1000_82573: + pba = E1000_PBA_12K; + break; + default: + pba = E1000_PBA_48K; + break; + } + + + + if(adapter->hw.mac_type == e1000_82547) { adapter->tx_fifo_head = 0; adapter->tx_head_addr = pba << E1000_TX_HEAD_ADDR_SHIFT; adapter->tx_fifo_size = (E1000_PBA_40K - pba) << E1000_PBA_BYTES_SHIFT; atomic_set(&adapter->tx_fifo_stall, 0); } + E1000_WRITE_REG(&adapter->hw, PBA, pba); /* flow control settings */ @@ -412,17 +448,23 @@ e1000_reset(struct e1000_adapter *adapter) adapter->hw.fc_send_xon = 1; adapter->hw.fc = adapter->hw.original_fc; + /* Allow time for pending master requests to run */ e1000_reset_hw(&adapter->hw); if(adapter->hw.mac_type >= e1000_82544) E1000_WRITE_REG(&adapter->hw, WUC, 0); if(e1000_init_hw(&adapter->hw)) DPRINTK(PROBE, ERR, "Hardware Error\n"); - + e1000_update_mng_vlan(adapter); /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */ E1000_WRITE_REG(&adapter->hw, VET, ETHERNET_IEEE_VLAN_TYPE); e1000_reset_adaptive(&adapter->hw); e1000_phy_get_info(&adapter->hw, &adapter->phy_info); + if (adapter->en_mng_pt) { + manc = E1000_READ_REG(&adapter->hw, MANC); + manc |= (E1000_MANC_ARP_EN | E1000_MANC_EN_MNG2HOST); + E1000_WRITE_REG(&adapter->hw, MANC, manc); + } } /** @@ -443,15 +485,13 @@ e1000_probe(struct pci_dev *pdev, { struct net_device *netdev; struct e1000_adapter *adapter; + unsigned long mmio_start, mmio_len; + uint32_t swsm; + static int cards_found = 0; - unsigned long mmio_start; - int mmio_len; - int pci_using_dac; - int i; - int err; + int i, err, pci_using_dac; uint16_t eeprom_data; uint16_t eeprom_apme_mask = E1000_EEPROM_APME; - if((err = pci_enable_device(pdev))) return err; @@ -538,6 +578,9 @@ e1000_probe(struct pci_dev *pdev, if((err = e1000_sw_init(adapter))) goto err_sw_init; + if((err = e1000_check_phy_reset_block(&adapter->hw))) + DPRINTK(PROBE, INFO, "PHY reset is blocked due to SOL/IDER session.\n"); + if(adapter->hw.mac_type >= e1000_82543) { netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | @@ -550,6 +593,11 @@ e1000_probe(struct pci_dev *pdev, if((adapter->hw.mac_type >= e1000_82544) && (adapter->hw.mac_type != e1000_82547)) netdev->features |= NETIF_F_TSO; + +#ifdef NETIF_F_TSO_IPV6 + if(adapter->hw.mac_type > e1000_82547_rev_2) + netdev->features |= NETIF_F_TSO_IPV6; +#endif #endif if(pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; @@ -557,6 +605,8 @@ e1000_probe(struct pci_dev *pdev, /* hard_start_xmit is safe against parallel locking */ netdev->features |= NETIF_F_LLTX; + adapter->en_mng_pt = e1000_enable_mng_pass_thru(&adapter->hw); + /* before reading the EEPROM, reset the controller to * put the device in a known good starting state */ @@ -646,6 +696,17 @@ e1000_probe(struct pci_dev *pdev, /* reset the hardware with the new settings */ e1000_reset(adapter); + /* Let firmware know the driver has taken over */ + switch(adapter->hw.mac_type) { + case e1000_82573: + swsm = E1000_READ_REG(&adapter->hw, SWSM); + E1000_WRITE_REG(&adapter->hw, SWSM, + swsm | E1000_SWSM_DRV_LOAD); + break; + default: + break; + } + strcpy(netdev->name, "eth%d"); if((err = register_netdev(netdev))) goto err_register; @@ -681,7 +742,7 @@ e1000_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev->priv; - uint32_t manc; + uint32_t manc, swsm; flush_scheduled_work(); @@ -694,9 +755,21 @@ e1000_remove(struct pci_dev *pdev) } } + switch(adapter->hw.mac_type) { + case e1000_82573: + swsm = E1000_READ_REG(&adapter->hw, SWSM); + E1000_WRITE_REG(&adapter->hw, SWSM, + swsm & ~E1000_SWSM_DRV_LOAD); + break; + + default: + break; + } + unregister_netdev(netdev); - e1000_phy_hw_reset(&adapter->hw); + if(!e1000_check_phy_reset_block(&adapter->hw)) + e1000_phy_hw_reset(&adapter->hw); iounmap(adapter->hw.hw_addr); pci_release_regions(pdev); @@ -734,6 +807,7 @@ e1000_sw_init(struct e1000_adapter *adapter) pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word); adapter->rx_buffer_len = E1000_RXBUFFER_2048; + adapter->rx_ps_bsize0 = E1000_RXBUFFER_256; hw->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE; hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE; @@ -747,7 +821,10 @@ e1000_sw_init(struct e1000_adapter *adapter) /* initialize eeprom parameters */ - e1000_init_eeprom_params(hw); + if(e1000_init_eeprom_params(hw)) { + E1000_ERR("EEPROM initialization failed\n"); + return -EIO; + } switch(hw->mac_type) { default: @@ -812,6 +889,11 @@ e1000_open(struct net_device *netdev) if((err = e1000_up(adapter))) goto err_up; + adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; + if((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) { + e1000_update_mng_vlan(adapter); + } return E1000_SUCCESS; @@ -847,14 +929,18 @@ e1000_close(struct net_device *netdev) e1000_free_tx_resources(adapter); e1000_free_rx_resources(adapter); + if((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) { + e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); + } return 0; } /** * e1000_check_64k_bound - check that memory doesn't cross 64kB boundary * @adapter: address of board private structure - * @begin: address of beginning of memory - * @end: address of end of memory + * @start: address of beginning of memory + * @len: length of memory **/ static inline boolean_t e1000_check_64k_bound(struct e1000_adapter *adapter, @@ -1039,7 +1125,7 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter) { struct e1000_desc_ring *rxdr = &adapter->rx_ring; struct pci_dev *pdev = adapter->pdev; - int size; + int size, desc_len; size = sizeof(struct e1000_buffer) * rxdr->count; rxdr->buffer_info = vmalloc(size); @@ -1050,9 +1136,35 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter) } memset(rxdr->buffer_info, 0, size); + size = sizeof(struct e1000_ps_page) * rxdr->count; + rxdr->ps_page = kmalloc(size, GFP_KERNEL); + if(!rxdr->ps_page) { + vfree(rxdr->buffer_info); + DPRINTK(PROBE, ERR, + "Unable to allocate memory for the receive descriptor ring\n"); + return -ENOMEM; + } + memset(rxdr->ps_page, 0, size); + + size = sizeof(struct e1000_ps_page_dma) * rxdr->count; + rxdr->ps_page_dma = kmalloc(size, GFP_KERNEL); + if(!rxdr->ps_page_dma) { + vfree(rxdr->buffer_info); + kfree(rxdr->ps_page); + DPRINTK(PROBE, ERR, + "Unable to allocate memory for the receive descriptor ring\n"); + return -ENOMEM; + } + memset(rxdr->ps_page_dma, 0, size); + + if(adapter->hw.mac_type <= e1000_82547_rev_2) + desc_len = sizeof(struct e1000_rx_desc); + else + desc_len = sizeof(union e1000_rx_desc_packet_split); + /* Round up to nearest 4K */ - rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc); + rxdr->size = rxdr->count * desc_len; E1000_ROUNDUP(rxdr->size, 4096); rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); @@ -1062,6 +1174,8 @@ setup_rx_desc_die: DPRINTK(PROBE, ERR, "Unble to Allocate Memory for the Recieve descriptor ring\n"); vfree(rxdr->buffer_info); + kfree(rxdr->ps_page); + kfree(rxdr->ps_page_dma); return -ENOMEM; } @@ -1089,6 +1203,8 @@ setup_rx_desc_die: "Unable to Allocate aligned Memory for the" " Receive descriptor ring\n"); vfree(rxdr->buffer_info); + kfree(rxdr->ps_page); + kfree(rxdr->ps_page_dma); return -ENOMEM; } else { /* free old, move on with the new one since its okay */ @@ -1111,7 +1227,8 @@ setup_rx_desc_die: static void e1000_setup_rctl(struct e1000_adapter *adapter) { - uint32_t rctl; + uint32_t rctl, rfctl; + uint32_t psrctl = 0; rctl = E1000_READ_REG(&adapter->hw, RCTL); @@ -1126,24 +1243,69 @@ e1000_setup_rctl(struct e1000_adapter *adapter) else rctl &= ~E1000_RCTL_SBP; + if (adapter->netdev->mtu <= ETH_DATA_LEN) + rctl &= ~E1000_RCTL_LPE; + else + rctl |= E1000_RCTL_LPE; + /* Setup buffer sizes */ - rctl &= ~(E1000_RCTL_SZ_4096); - rctl |= (E1000_RCTL_BSEX | E1000_RCTL_LPE); - switch (adapter->rx_buffer_len) { - case E1000_RXBUFFER_2048: - default: - rctl |= E1000_RCTL_SZ_2048; - rctl &= ~(E1000_RCTL_BSEX | E1000_RCTL_LPE); - break; - case E1000_RXBUFFER_4096: - rctl |= E1000_RCTL_SZ_4096; - break; - case E1000_RXBUFFER_8192: - rctl |= E1000_RCTL_SZ_8192; - break; - case E1000_RXBUFFER_16384: - rctl |= E1000_RCTL_SZ_16384; - break; + if(adapter->hw.mac_type == e1000_82573) { + /* We can now specify buffers in 1K increments. + * BSIZE and BSEX are ignored in this case. */ + rctl |= adapter->rx_buffer_len << 0x11; + } else { + rctl &= ~E1000_RCTL_SZ_4096; + rctl |= E1000_RCTL_BSEX; + switch (adapter->rx_buffer_len) { + case E1000_RXBUFFER_2048: + default: + rctl |= E1000_RCTL_SZ_2048; + rctl &= ~E1000_RCTL_BSEX; + break; + case E1000_RXBUFFER_4096: + rctl |= E1000_RCTL_SZ_4096; + break; + case E1000_RXBUFFER_8192: + rctl |= E1000_RCTL_SZ_8192; + break; + case E1000_RXBUFFER_16384: + rctl |= E1000_RCTL_SZ_16384; + break; + } + } + +#ifdef CONFIG_E1000_PACKET_SPLIT + /* 82571 and greater support packet-split where the protocol + * header is placed in skb->data and the packet data is + * placed in pages hanging off of skb_shinfo(skb)->nr_frags. + * In the case of a non-split, skb->data is linearly filled, + * followed by the page buffers. Therefore, skb->data is + * sized to hold the largest protocol header. + */ + adapter->rx_ps = (adapter->hw.mac_type > e1000_82547_rev_2) + && (adapter->netdev->mtu + < ((3 * PAGE_SIZE) + adapter->rx_ps_bsize0)); +#endif + if(adapter->rx_ps) { + /* Configure extra packet-split registers */ + rfctl = E1000_READ_REG(&adapter->hw, RFCTL); + rfctl |= E1000_RFCTL_EXTEN; + /* disable IPv6 packet split support */ + rfctl |= E1000_RFCTL_IPV6_DIS; + E1000_WRITE_REG(&adapter->hw, RFCTL, rfctl); + + rctl |= E1000_RCTL_DTYP_PS | E1000_RCTL_SECRC; + + psrctl |= adapter->rx_ps_bsize0 >> + E1000_PSRCTL_BSIZE0_SHIFT; + psrctl |= PAGE_SIZE >> + E1000_PSRCTL_BSIZE1_SHIFT; + psrctl |= PAGE_SIZE << + E1000_PSRCTL_BSIZE2_SHIFT; + psrctl |= PAGE_SIZE << + E1000_PSRCTL_BSIZE3_SHIFT; + + E1000_WRITE_REG(&adapter->hw, PSRCTL, psrctl); } E1000_WRITE_REG(&adapter->hw, RCTL, rctl); @@ -1160,9 +1322,18 @@ static void e1000_configure_rx(struct e1000_adapter *adapter) { uint64_t rdba = adapter->rx_ring.dma; - uint32_t rdlen = adapter->rx_ring.count * sizeof(struct e1000_rx_desc); - uint32_t rctl; - uint32_t rxcsum; + uint32_t rdlen, rctl, rxcsum; + + if(adapter->rx_ps) { + rdlen = adapter->rx_ring.count * + sizeof(union e1000_rx_desc_packet_split); + adapter->clean_rx = e1000_clean_rx_irq_ps; + adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps; + } else { + rdlen = adapter->rx_ring.count * sizeof(struct e1000_rx_desc); + adapter->clean_rx = e1000_clean_rx_irq; + adapter->alloc_rx_buf = e1000_alloc_rx_buffers; + } /* disable receives while setting up the descriptors */ rctl = E1000_READ_REG(&adapter->hw, RCTL); @@ -1189,13 +1360,27 @@ e1000_configure_rx(struct e1000_adapter *adapter) E1000_WRITE_REG(&adapter->hw, RDT, 0); /* Enable 82543 Receive Checksum Offload for TCP and UDP */ - if((adapter->hw.mac_type >= e1000_82543) && - (adapter->rx_csum == TRUE)) { + if(adapter->hw.mac_type >= e1000_82543) { rxcsum = E1000_READ_REG(&adapter->hw, RXCSUM); - rxcsum |= E1000_RXCSUM_TUOFL; + if(adapter->rx_csum == TRUE) { + rxcsum |= E1000_RXCSUM_TUOFL; + + /* Enable 82573 IPv4 payload checksum for UDP fragments + * Must be used in conjunction with packet-split. */ + if((adapter->hw.mac_type > e1000_82547_rev_2) && + (adapter->rx_ps)) { + rxcsum |= E1000_RXCSUM_IPPCSE; + } + } else { + rxcsum &= ~E1000_RXCSUM_TUOFL; + /* don't need to clear IPPCSE as it defaults to 0 */ + } E1000_WRITE_REG(&adapter->hw, RXCSUM, rxcsum); } + if (adapter->hw.mac_type == e1000_82573) + E1000_WRITE_REG(&adapter->hw, ERT, 0x0100); + /* Enable Receives */ E1000_WRITE_REG(&adapter->hw, RCTL, rctl); } @@ -1298,6 +1483,10 @@ e1000_free_rx_resources(struct e1000_adapter *adapter) vfree(rx_ring->buffer_info); rx_ring->buffer_info = NULL; + kfree(rx_ring->ps_page); + rx_ring->ps_page = NULL; + kfree(rx_ring->ps_page_dma); + rx_ring->ps_page_dma = NULL; pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma); @@ -1314,16 +1503,19 @@ e1000_clean_rx_ring(struct e1000_adapter *adapter) { struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct e1000_buffer *buffer_info; + struct e1000_ps_page *ps_page; + struct e1000_ps_page_dma *ps_page_dma; struct pci_dev *pdev = adapter->pdev; unsigned long size; - unsigned int i; + unsigned int i, j; /* Free all the Rx ring sk_buffs */ for(i = 0; i < rx_ring->count; i++) { buffer_info = &rx_ring->buffer_info[i]; if(buffer_info->skb) { - + ps_page = &rx_ring->ps_page[i]; + ps_page_dma = &rx_ring->ps_page_dma[i]; pci_unmap_single(pdev, buffer_info->dma, buffer_info->length, @@ -1331,11 +1523,25 @@ e1000_clean_rx_ring(struct e1000_adapter *adapter) dev_kfree_skb(buffer_info->skb); buffer_info->skb = NULL; + + for(j = 0; j < PS_PAGE_BUFFERS; j++) { + if(!ps_page->ps_page[j]) break; + pci_unmap_single(pdev, + ps_page_dma->ps_page_dma[j], + PAGE_SIZE, PCI_DMA_FROMDEVICE); + ps_page_dma->ps_page_dma[j] = 0; + put_page(ps_page->ps_page[j]); + ps_page->ps_page[j] = NULL; + } } } size = sizeof(struct e1000_buffer) * rx_ring->count; memset(rx_ring->buffer_info, 0, size); + size = sizeof(struct e1000_ps_page) * rx_ring->count; + memset(rx_ring->ps_page, 0, size); + size = sizeof(struct e1000_ps_page_dma) * rx_ring->count; + memset(rx_ring->ps_page_dma, 0, size); /* Zero out the descriptor ring */ @@ -1573,6 +1779,11 @@ e1000_watchdog_task(struct e1000_adapter *adapter) uint32_t link; e1000_check_for_link(&adapter->hw); + if (adapter->hw.mac_type == e1000_82573) { + e1000_enable_tx_pkt_filtering(&adapter->hw); + if(adapter->mng_vlan_id != adapter->hw.mng_cookie.vlan_id) + e1000_update_mng_vlan(adapter); + } if((adapter->hw.media_type == e1000_media_type_internal_serdes) && !(E1000_READ_REG(&adapter->hw, TXCW) & E1000_TXCW_ANE)) @@ -1659,6 +1870,7 @@ e1000_watchdog_task(struct e1000_adapter *adapter) #define E1000_TX_FLAGS_CSUM 0x00000001 #define E1000_TX_FLAGS_VLAN 0x00000002 #define E1000_TX_FLAGS_TSO 0x00000004 +#define E1000_TX_FLAGS_IPV4 0x00000008 #define E1000_TX_FLAGS_VLAN_MASK 0xffff0000 #define E1000_TX_FLAGS_VLAN_SHIFT 16 @@ -1669,7 +1881,7 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb) struct e1000_context_desc *context_desc; unsigned int i; uint32_t cmd_length = 0; - uint16_t ipcse, tucse, mss; + uint16_t ipcse = 0, tucse, mss; uint8_t ipcss, ipcso, tucss, tucso, hdr_len; int err; @@ -1682,23 +1894,37 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb) hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); mss = skb_shinfo(skb)->tso_size; - skb->nh.iph->tot_len = 0; - skb->nh.iph->check = 0; - skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr, - skb->nh.iph->daddr, - 0, - IPPROTO_TCP, - 0); + if(skb->protocol == ntohs(ETH_P_IP)) { + skb->nh.iph->tot_len = 0; + skb->nh.iph->check = 0; + skb->h.th->check = + ~csum_tcpudp_magic(skb->nh.iph->saddr, + skb->nh.iph->daddr, + 0, + IPPROTO_TCP, + 0); + cmd_length = E1000_TXD_CMD_IP; + ipcse = skb->h.raw - skb->data - 1; +#ifdef NETIF_F_TSO_IPV6 + } else if(skb->protocol == ntohs(ETH_P_IPV6)) { + skb->nh.ipv6h->payload_len = 0; + skb->h.th->check = + ~csum_ipv6_magic(&skb->nh.ipv6h->saddr, + &skb->nh.ipv6h->daddr, + 0, + IPPROTO_TCP, + 0); + ipcse = 0; +#endif + } ipcss = skb->nh.raw - skb->data; ipcso = (void *)&(skb->nh.iph->check) - (void *)skb->data; - ipcse = skb->h.raw - skb->data - 1; tucss = skb->h.raw - skb->data; tucso = (void *)&(skb->h.th->check) - (void *)skb->data; tucse = 0; cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE | - E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP | - (skb->len - (hdr_len))); + E1000_TXD_CMD_TCP | (skb->len - (hdr_len))); i = adapter->tx_ring.next_to_use; context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i); @@ -1866,7 +2092,10 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags) if(likely(tx_flags & E1000_TX_FLAGS_TSO)) { txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D | E1000_TXD_CMD_TSE; - txd_upper |= (E1000_TXD_POPTS_IXSM | E1000_TXD_POPTS_TXSM) << 8; + txd_upper |= E1000_TXD_POPTS_TXSM << 8; + + if(likely(tx_flags & E1000_TX_FLAGS_IPV4)) + txd_upper |= E1000_TXD_POPTS_IXSM << 8; } if(likely(tx_flags & E1000_TX_FLAGS_CSUM)) { @@ -1941,6 +2170,53 @@ no_fifo_stall_required: return 0; } +#define MINIMUM_DHCP_PACKET_SIZE 282 +static inline int +e1000_transfer_dhcp_info(struct e1000_adapter *adapter, struct sk_buff *skb) +{ + struct e1000_hw *hw = &adapter->hw; + uint16_t length, offset; + if(vlan_tx_tag_present(skb)) { + if(!((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) && + ( adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) ) + return 0; + } + if(htons(ETH_P_IP) == skb->protocol) { + const struct iphdr *ip = skb->nh.iph; + if(IPPROTO_UDP == ip->protocol) { + struct udphdr *udp = (struct udphdr *)(skb->h.uh); + if(ntohs(udp->dest) == 67) { + offset = (uint8_t *)udp + 8 - skb->data; + length = skb->len - offset; + + return e1000_mng_write_dhcp_info(hw, + (uint8_t *)udp + 8, length); + } + } + } else if((skb->len > MINIMUM_DHCP_PACKET_SIZE) && (!skb->protocol)) { + struct ethhdr *eth = (struct ethhdr *) skb->data; + if((htons(ETH_P_IP) == eth->h_proto)) { + const struct iphdr *ip = + (struct iphdr *)((uint8_t *)skb->data+14); + if(IPPROTO_UDP == ip->protocol) { + struct udphdr *udp = + (struct udphdr *)((uint8_t *)ip + + (ip->ihl << 2)); + if(ntohs(udp->dest) == 67) { + offset = (uint8_t *)udp + 8 - skb->data; + length = skb->len - offset; + + return e1000_mng_write_dhcp_info(hw, + (uint8_t *)udp + 8, + length); + } + } + } + } + return 0; +} + #define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 ) static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) @@ -2008,6 +2284,9 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) local_irq_restore(flags); return NETDEV_TX_LOCKED; } + if(adapter->hw.tx_pkt_filtering && (adapter->hw.mac_type == e1000_82573) ) + e1000_transfer_dhcp_info(adapter, skb); + /* need: count + 2 desc gap to keep tail from touching * head, otherwise try next time */ @@ -2044,6 +2323,12 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) else if(likely(e1000_tx_csum(adapter, skb))) tx_flags |= E1000_TX_FLAGS_CSUM; + /* Old method was to assume IPv4 packet by default if TSO was enabled. + * 82573 hardware supports TSO capabilities for IPv6 as well... + * no longer assume, we must. */ + if(likely(skb->protocol == ntohs(ETH_P_IP))) + tx_flags |= E1000_TX_FLAGS_IPV4; + e1000_tx_queue(adapter, e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss), tx_flags); @@ -2110,7 +2395,6 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) { struct e1000_adapter *adapter = netdev->priv; - int old_mtu = adapter->rx_buffer_len; int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE; if((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) || @@ -2119,29 +2403,45 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu) return -EINVAL; } - if(max_frame <= MAXIMUM_ETHERNET_FRAME_SIZE) { - adapter->rx_buffer_len = E1000_RXBUFFER_2048; - - } else if(adapter->hw.mac_type < e1000_82543) { - DPRINTK(PROBE, ERR, "Jumbo Frames not supported on 82542\n"); +#define MAX_STD_JUMBO_FRAME_SIZE 9216 + /* might want this to be bigger enum check... */ + if (adapter->hw.mac_type == e1000_82573 && + max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) { + DPRINTK(PROBE, ERR, "Jumbo Frames not supported " + "on 82573\n"); return -EINVAL; + } - } else if(max_frame <= E1000_RXBUFFER_4096) { - adapter->rx_buffer_len = E1000_RXBUFFER_4096; - - } else if(max_frame <= E1000_RXBUFFER_8192) { - adapter->rx_buffer_len = E1000_RXBUFFER_8192; - + if(adapter->hw.mac_type > e1000_82547_rev_2) { + adapter->rx_buffer_len = max_frame; + E1000_ROUNDUP(adapter->rx_buffer_len, 1024); } else { - adapter->rx_buffer_len = E1000_RXBUFFER_16384; + if(unlikely((adapter->hw.mac_type < e1000_82543) && + (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE))) { + DPRINTK(PROBE, ERR, "Jumbo Frames not supported " + "on 82542\n"); + return -EINVAL; + + } else { + if(max_frame <= E1000_RXBUFFER_2048) { + adapter->rx_buffer_len = E1000_RXBUFFER_2048; + } else if(max_frame <= E1000_RXBUFFER_4096) { + adapter->rx_buffer_len = E1000_RXBUFFER_4096; + } else if(max_frame <= E1000_RXBUFFER_8192) { + adapter->rx_buffer_len = E1000_RXBUFFER_8192; + } else if(max_frame <= E1000_RXBUFFER_16384) { + adapter->rx_buffer_len = E1000_RXBUFFER_16384; + } + } } - if(old_mtu != adapter->rx_buffer_len && netif_running(netdev)) { + netdev->mtu = new_mtu; + + if(netif_running(netdev)) { e1000_down(adapter); e1000_up(adapter); } - netdev->mtu = new_mtu; adapter->hw.max_frame_size = max_frame; return 0; @@ -2232,6 +2532,17 @@ e1000_update_stats(struct e1000_adapter *adapter) adapter->stats.tsctc += E1000_READ_REG(hw, TSCTC); adapter->stats.tsctfc += E1000_READ_REG(hw, TSCTFC); } + if(hw->mac_type > e1000_82547_rev_2) { + adapter->stats.iac += E1000_READ_REG(hw, IAC); + adapter->stats.icrxoc += E1000_READ_REG(hw, ICRXOC); + adapter->stats.icrxptc += E1000_READ_REG(hw, ICRXPTC); + adapter->stats.icrxatc += E1000_READ_REG(hw, ICRXATC); + adapter->stats.ictxptc += E1000_READ_REG(hw, ICTXPTC); + adapter->stats.ictxatc += E1000_READ_REG(hw, ICTXATC); + adapter->stats.ictxqec += E1000_READ_REG(hw, ICTXQEC); + adapter->stats.ictxqmtc += E1000_READ_REG(hw, ICTXQMTC); + adapter->stats.icrxdmtc += E1000_READ_REG(hw, ICRXDMTC); + } /* Fill out the OS statistics structure */ @@ -2337,7 +2648,7 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) } for(i = 0; i < E1000_MAX_INTR; i++) - if(unlikely(!e1000_clean_rx_irq(adapter) & + if(unlikely(!adapter->clean_rx(adapter) & !e1000_clean_tx_irq(adapter))) break; @@ -2363,7 +2674,7 @@ e1000_clean(struct net_device *netdev, int *budget) int work_done = 0; tx_cleaned = e1000_clean_tx_irq(adapter); - e1000_clean_rx_irq(adapter, &work_done, work_to_do); + adapter->clean_rx(adapter, &work_done, work_to_do); *budget -= work_done; netdev->quota -= work_done; @@ -2501,41 +2812,57 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) /** * e1000_rx_checksum - Receive Checksum Offload for 82543 - * @adapter: board private structure - * @rx_desc: receive descriptor - * @sk_buff: socket buffer with received data + * @adapter: board private structure + * @status_err: receive descriptor status and error fields + * @csum: receive descriptor csum field + * @sk_buff: socket buffer with received data **/ static inline void e1000_rx_checksum(struct e1000_adapter *adapter, - struct e1000_rx_desc *rx_desc, - struct sk_buff *skb) + uint32_t status_err, uint32_t csum, + struct sk_buff *skb) { + uint16_t status = (uint16_t)status_err; + uint8_t errors = (uint8_t)(status_err >> 24); + skb->ip_summed = CHECKSUM_NONE; + /* 82543 or newer only */ - if(unlikely((adapter->hw.mac_type < e1000_82543) || + if(unlikely(adapter->hw.mac_type < e1000_82543)) return; /* Ignore Checksum bit is set */ - (rx_desc->status & E1000_RXD_STAT_IXSM) || - /* TCP Checksum has not been calculated */ - (!(rx_desc->status & E1000_RXD_STAT_TCPCS)))) { - skb->ip_summed = CHECKSUM_NONE; - return; - } - - /* At this point we know the hardware did the TCP checksum */ - /* now look at the TCP checksum error bit */ - if(rx_desc->errors & E1000_RXD_ERR_TCPE) { + if(unlikely(status & E1000_RXD_STAT_IXSM)) return; + /* TCP/UDP checksum error bit is set */ + if(unlikely(errors & E1000_RXD_ERR_TCPE)) { /* let the stack verify checksum errors */ - skb->ip_summed = CHECKSUM_NONE; adapter->hw_csum_err++; + return; + } + /* TCP/UDP Checksum has not been calculated */ + if(adapter->hw.mac_type <= e1000_82547_rev_2) { + if(!(status & E1000_RXD_STAT_TCPCS)) + return; } else { + if(!(status & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS))) + return; + } + /* It must be a TCP or UDP packet with a valid checksum */ + if (likely(status & E1000_RXD_STAT_TCPCS)) { /* TCP checksum is good */ skb->ip_summed = CHECKSUM_UNNECESSARY; - adapter->hw_csum_good++; + } else if (adapter->hw.mac_type > e1000_82547_rev_2) { + /* IP fragment with UDP payload */ + /* Hardware complements the payload checksum, so we undo it + * and then put the value in host order for further stack use. + */ + csum = ntohl(csum ^ 0xFFFF); + skb->csum = csum; + skb->ip_summed = CHECKSUM_HW; } + adapter->hw_csum_good++; } /** - * e1000_clean_rx_irq - Send received data up the network stack + * e1000_clean_rx_irq - Send received data up the network stack; legacy * @adapter: board private structure **/ @@ -2608,15 +2935,17 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) skb_put(skb, length - ETHERNET_FCS_SIZE); /* Receive Checksum Offload */ - e1000_rx_checksum(adapter, rx_desc, skb); - + e1000_rx_checksum(adapter, + (uint32_t)(rx_desc->status) | + ((uint32_t)(rx_desc->errors) << 24), + rx_desc->csum, skb); skb->protocol = eth_type_trans(skb, netdev); #ifdef CONFIG_E1000_NAPI if(unlikely(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP))) { vlan_hwaccel_receive_skb(skb, adapter->vlgrp, - le16_to_cpu(rx_desc->special) & - E1000_RXD_SPC_VLAN_MASK); + le16_to_cpu(rx_desc->special) & + E1000_RXD_SPC_VLAN_MASK); } else { netif_receive_skb(skb); } @@ -2639,16 +2968,142 @@ next_desc: rx_desc = E1000_RX_DESC(*rx_ring, i); } - rx_ring->next_to_clean = i; + adapter->alloc_rx_buf(adapter); + + return cleaned; +} + +/** + * e1000_clean_rx_irq_ps - Send received data up the network stack; packet split + * @adapter: board private structure + **/ + +static boolean_t +#ifdef CONFIG_E1000_NAPI +e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, int *work_done, + int work_to_do) +#else +e1000_clean_rx_irq_ps(struct e1000_adapter *adapter) +#endif +{ + struct e1000_desc_ring *rx_ring = &adapter->rx_ring; + union e1000_rx_desc_packet_split *rx_desc; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_buffer *buffer_info; + struct e1000_ps_page *ps_page; + struct e1000_ps_page_dma *ps_page_dma; + struct sk_buff *skb; + unsigned int i, j; + uint32_t length, staterr; + boolean_t cleaned = FALSE; + + i = rx_ring->next_to_clean; + rx_desc = E1000_RX_DESC_PS(*rx_ring, i); + staterr = rx_desc->wb.middle.status_error; + + while(staterr & E1000_RXD_STAT_DD) { + buffer_info = &rx_ring->buffer_info[i]; + ps_page = &rx_ring->ps_page[i]; + ps_page_dma = &rx_ring->ps_page_dma[i]; +#ifdef CONFIG_E1000_NAPI + if(unlikely(*work_done >= work_to_do)) + break; + (*work_done)++; +#endif + cleaned = TRUE; + pci_unmap_single(pdev, buffer_info->dma, + buffer_info->length, + PCI_DMA_FROMDEVICE); + + skb = buffer_info->skb; + + if(unlikely(!(staterr & E1000_RXD_STAT_EOP))) { + E1000_DBG("%s: Packet Split buffers didn't pick up" + " the full packet\n", netdev->name); + dev_kfree_skb_irq(skb); + goto next_desc; + } - e1000_alloc_rx_buffers(adapter); + if(unlikely(staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK)) { + dev_kfree_skb_irq(skb); + goto next_desc; + } + + length = le16_to_cpu(rx_desc->wb.middle.length0); + + if(unlikely(!length)) { + E1000_DBG("%s: Last part of the packet spanning" + " multiple descriptors\n", netdev->name); + dev_kfree_skb_irq(skb); + goto next_desc; + } + + /* Good Receive */ + skb_put(skb, length); + + for(j = 0; j < PS_PAGE_BUFFERS; j++) { + if(!(length = le16_to_cpu(rx_desc->wb.upper.length[j]))) + break; + + pci_unmap_page(pdev, ps_page_dma->ps_page_dma[j], + PAGE_SIZE, PCI_DMA_FROMDEVICE); + ps_page_dma->ps_page_dma[j] = 0; + skb_shinfo(skb)->frags[j].page = + ps_page->ps_page[j]; + ps_page->ps_page[j] = NULL; + skb_shinfo(skb)->frags[j].page_offset = 0; + skb_shinfo(skb)->frags[j].size = length; + skb_shinfo(skb)->nr_frags++; + skb->len += length; + skb->data_len += length; + } + + e1000_rx_checksum(adapter, staterr, + rx_desc->wb.lower.hi_dword.csum_ip.csum, skb); + skb->protocol = eth_type_trans(skb, netdev); + +#ifdef HAVE_RX_ZERO_COPY + if(likely(rx_desc->wb.upper.header_status & + E1000_RXDPS_HDRSTAT_HDRSP)) + skb_shinfo(skb)->zero_copy = TRUE; +#endif +#ifdef CONFIG_E1000_NAPI + if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) { + vlan_hwaccel_receive_skb(skb, adapter->vlgrp, + le16_to_cpu(rx_desc->wb.middle.vlan & + E1000_RXD_SPC_VLAN_MASK)); + } else { + netif_receive_skb(skb); + } +#else /* CONFIG_E1000_NAPI */ + if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) { + vlan_hwaccel_rx(skb, adapter->vlgrp, + le16_to_cpu(rx_desc->wb.middle.vlan & + E1000_RXD_SPC_VLAN_MASK)); + } else { + netif_rx(skb); + } +#endif /* CONFIG_E1000_NAPI */ + netdev->last_rx = jiffies; + +next_desc: + rx_desc->wb.middle.status_error &= ~0xFF; + buffer_info->skb = NULL; + if(unlikely(++i == rx_ring->count)) i = 0; + + rx_desc = E1000_RX_DESC_PS(*rx_ring, i); + staterr = rx_desc->wb.middle.status_error; + } + rx_ring->next_to_clean = i; + adapter->alloc_rx_buf(adapter); return cleaned; } /** - * e1000_alloc_rx_buffers - Replace used receive buffers + * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended * @adapter: address of board private structure **/ @@ -2752,6 +3207,95 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter) rx_ring->next_to_use = i; } +/** + * e1000_alloc_rx_buffers_ps - Replace used receive buffers; packet split + * @adapter: address of board private structure + **/ + +static void +e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter) +{ + struct e1000_desc_ring *rx_ring = &adapter->rx_ring; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + union e1000_rx_desc_packet_split *rx_desc; + struct e1000_buffer *buffer_info; + struct e1000_ps_page *ps_page; + struct e1000_ps_page_dma *ps_page_dma; + struct sk_buff *skb; + unsigned int i, j; + + i = rx_ring->next_to_use; + buffer_info = &rx_ring->buffer_info[i]; + ps_page = &rx_ring->ps_page[i]; + ps_page_dma = &rx_ring->ps_page_dma[i]; + + while(!buffer_info->skb) { + rx_desc = E1000_RX_DESC_PS(*rx_ring, i); + + for(j = 0; j < PS_PAGE_BUFFERS; j++) { + if(unlikely(!ps_page->ps_page[j])) { + ps_page->ps_page[j] = + alloc_page(GFP_ATOMIC); + if(unlikely(!ps_page->ps_page[j])) + goto no_buffers; + ps_page_dma->ps_page_dma[j] = + pci_map_page(pdev, + ps_page->ps_page[j], + 0, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + } + /* Refresh the desc even if buffer_addrs didn't + * change because each write-back erases this info. + */ + rx_desc->read.buffer_addr[j+1] = + cpu_to_le64(ps_page_dma->ps_page_dma[j]); + } + + skb = dev_alloc_skb(adapter->rx_ps_bsize0 + NET_IP_ALIGN); + + if(unlikely(!skb)) + break; + + /* Make buffer alignment 2 beyond a 16 byte boundary + * this will result in a 16 byte aligned IP header after + * the 14 byte MAC header is removed + */ + skb_reserve(skb, NET_IP_ALIGN); + + skb->dev = netdev; + + buffer_info->skb = skb; + buffer_info->length = adapter->rx_ps_bsize0; + buffer_info->dma = pci_map_single(pdev, skb->data, + adapter->rx_ps_bsize0, + PCI_DMA_FROMDEVICE); + + rx_desc->read.buffer_addr[0] = cpu_to_le64(buffer_info->dma); + + if(unlikely((i & ~(E1000_RX_BUFFER_WRITE - 1)) == i)) { + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). */ + wmb(); + /* Hardware increments by 16 bytes, but packet split + * descriptors are 32 bytes...so we increment tail + * twice as much. + */ + E1000_WRITE_REG(&adapter->hw, RDT, i<<1); + } + + if(unlikely(++i == rx_ring->count)) i = 0; + buffer_info = &rx_ring->buffer_info[i]; + ps_page = &rx_ring->ps_page[i]; + ps_page_dma = &rx_ring->ps_page_dma[i]; + } + +no_buffers: + rx_ring->next_to_use = i; +} + /** * e1000_smartspeed - Workaround for SmartSpeed on 82541 and 82547 controllers. * @adapter: @@ -2986,6 +3530,7 @@ e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) rctl |= E1000_RCTL_VFE; rctl &= ~E1000_RCTL_CFIEN; E1000_WRITE_REG(&adapter->hw, RCTL, rctl); + e1000_update_mng_vlan(adapter); } else { /* disable VLAN tag insert/strip */ ctrl = E1000_READ_REG(&adapter->hw, CTRL); @@ -2996,6 +3541,10 @@ e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) rctl = E1000_READ_REG(&adapter->hw, RCTL); rctl &= ~E1000_RCTL_VFE; E1000_WRITE_REG(&adapter->hw, RCTL, rctl); + if(adapter->mng_vlan_id != (uint16_t)E1000_MNG_VLAN_NONE) { + e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); + adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; + } } e1000_irq_enable(adapter); @@ -3006,7 +3555,10 @@ e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid) { struct e1000_adapter *adapter = netdev->priv; uint32_t vfta, index; - + if((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) && + (vid == adapter->mng_vlan_id)) + return; /* add VID to filter table */ index = (vid >> 5) & 0x7F; vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index); @@ -3027,6 +3579,10 @@ e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid) e1000_irq_enable(adapter); + if((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) && + (vid == adapter->mng_vlan_id)) + return; /* remove VID from filter table */ index = (vid >> 5) & 0x7F; vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index); @@ -3102,7 +3658,7 @@ e1000_suspend(struct pci_dev *pdev, uint32_t state) { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev->priv; - uint32_t ctrl, ctrl_ext, rctl, manc, status; + uint32_t ctrl, ctrl_ext, rctl, manc, status, swsm; uint32_t wufc = adapter->wol; netif_device_detach(netdev); @@ -3144,6 +3700,9 @@ e1000_suspend(struct pci_dev *pdev, uint32_t state) E1000_WRITE_REG(&adapter->hw, CTRL_EXT, ctrl_ext); } + /* Allow time for pending master requests to run */ + e1000_disable_pciex_master(&adapter->hw); + E1000_WRITE_REG(&adapter->hw, WUC, E1000_WUC_PME_EN); E1000_WRITE_REG(&adapter->hw, WUFC, wufc); pci_enable_wake(pdev, 3, 1); @@ -3168,6 +3727,16 @@ e1000_suspend(struct pci_dev *pdev, uint32_t state) } } + switch(adapter->hw.mac_type) { + case e1000_82573: + swsm = E1000_READ_REG(&adapter->hw, SWSM); + E1000_WRITE_REG(&adapter->hw, SWSM, + swsm & ~E1000_SWSM_DRV_LOAD); + break; + default: + break; + } + pci_disable_device(pdev); state = (state > 0) ? 3 : 0; @@ -3182,7 +3751,7 @@ e1000_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev->priv; - uint32_t manc, ret; + uint32_t manc, ret, swsm; pci_set_power_state(pdev, 0); pci_restore_state(pdev); @@ -3207,10 +3776,19 @@ e1000_resume(struct pci_dev *pdev) E1000_WRITE_REG(&adapter->hw, MANC, manc); } + switch(adapter->hw.mac_type) { + case e1000_82573: + swsm = E1000_READ_REG(&adapter->hw, SWSM); + E1000_WRITE_REG(&adapter->hw, SWSM, + swsm | E1000_SWSM_DRV_LOAD); + break; + default: + break; + } + return 0; } #endif - #ifdef CONFIG_NET_POLL_CONTROLLER /* * Polling 'interrupt' - used by things like netconsole to send skbs diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h index 2efa3b1b64d..b1915e8eb56 100644 --- a/drivers/net/e1000/e1000_osdep.h +++ b/drivers/net/e1000/e1000_osdep.h @@ -101,6 +101,29 @@ typedef enum { (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \ ((offset) << 2))) +#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY +#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY + +#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) ( \ + writew((value), ((a)->hw_addr + \ + (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \ + ((offset) << 1)))) + +#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \ + readw((a)->hw_addr + \ + (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \ + ((offset) << 1))) + +#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \ + writeb((value), ((a)->hw_addr + \ + (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \ + (offset)))) + +#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \ + readb((a)->hw_addr + \ + (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \ + (offset))) + #define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS) #endif /* _E1000_OSDEP_H_ */ -- cgit v1.2.3 From 0e6ef3e02b6f07e37ba1c1abc059f8bee4e0847f Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:44:14 -0700 Subject: [PATCH] e1000:Fix Packet Buffer Allocation logic for 82547_rev_2 Fix Packet Buffer Allocation logic for 82547_rev_2 controller Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/e1000/e1000_main.c net-drivers-2.6/drivers/net/e1000.new/e1000_main.c --- drivers/net/e1000/e1000_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 5e6e1f7fd77..13bde909053 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -417,6 +417,7 @@ e1000_reset(struct e1000_adapter *adapter) switch (adapter->hw.mac_type) { case e1000_82547: + case e1000_82547_rev_2: pba = E1000_PBA_30K; break; case e1000_82573: -- cgit v1.2.3 From 1125ecbc0a89db07bb4eb1ba892a23367c3bdeb5 Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:44:25 -0700 Subject: [PATCH] e1000:Adjust flow control watermarks for Jumbo Frames Adjust flow control watermarks for Jumbo Frames Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/e1000/e1000_main.c net-drivers-2.6/drivers/net/e1000.new/e1000_main.c --- drivers/net/e1000/e1000_main.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 13bde909053..24d96c02b50 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -409,7 +409,10 @@ e1000_down(struct e1000_adapter *adapter) void e1000_reset(struct e1000_adapter *adapter) { + struct net_device *netdev = adapter->netdev; uint32_t pba, manc; + uint16_t fc_high_water_mark = E1000_FC_HIGH_DIFF; + uint16_t fc_low_water_mark = E1000_FC_LOW_DIFF; /* Repartition Pba for greater than 9k mtu * To take effect CTRL.RST is required. @@ -428,6 +431,16 @@ e1000_reset(struct e1000_adapter *adapter) break; } + if((adapter->hw.mac_type != e1000_82573) && + (adapter->rx_buffer_len > E1000_RXBUFFER_8192)) { + pba -= 8; /* allocate more FIFO for Tx */ + /* send an XOFF when there is enough space in the + * Rx FIFO to hold one extra full size Rx packet + */ + fc_high_water_mark = netdev->mtu + ENET_HEADER_SIZE + + ETHERNET_FCS_SIZE + 1; + fc_low_water_mark = fc_high_water_mark + 8; + } if(adapter->hw.mac_type == e1000_82547) { @@ -442,9 +455,9 @@ e1000_reset(struct e1000_adapter *adapter) /* flow control settings */ adapter->hw.fc_high_water = (pba << E1000_PBA_BYTES_SHIFT) - - E1000_FC_HIGH_DIFF; + fc_high_water_mark; adapter->hw.fc_low_water = (pba << E1000_PBA_BYTES_SHIFT) - - E1000_FC_LOW_DIFF; + fc_low_water_mark; adapter->hw.fc_pause_time = E1000_FC_PAUSE_TIME; adapter->hw.fc_send_xon = 1; adapter->hw.fc = adapter->hw.original_fc; -- cgit v1.2.3 From 2648345fcbadfae8e7113112ff9402e465a184dc Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:44:46 -0700 Subject: [PATCH] e1000:Driver version,white space,comments,device id Driver version, white space, comments, device id & other Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/e1000/e1000_ethtool.c net-drivers-2.6/drivers/net/e1000.new/e1000_ethtool.c --- drivers/net/e1000/e1000.h | 8 +- drivers/net/e1000/e1000_ethtool.c | 24 +++-- drivers/net/e1000/e1000_hw.c | 3 +- drivers/net/e1000/e1000_hw.h | 2 +- drivers/net/e1000/e1000_main.c | 199 +++++++++++++++++--------------------- drivers/net/e1000/e1000_osdep.h | 2 +- drivers/net/e1000/e1000_param.c | 3 +- 7 files changed, 106 insertions(+), 135 deletions(-) diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 19858c26753..af1e82c5b80 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -139,9 +139,9 @@ struct e1000_adapter; /* How many Rx Buffers do we bundle into one write to the hardware ? */ #define E1000_RX_BUFFER_WRITE 16 /* Must be power of 2 */ -#define AUTO_ALL_MODES 0 -#define E1000_EEPROM_82544_APM 0x0004 -#define E1000_EEPROM_APME 0x0400 +#define AUTO_ALL_MODES 0 +#define E1000_EEPROM_82544_APM 0x0400 +#define E1000_EEPROM_APME 0x0400 #ifndef E1000_MASTER_SLAVE /* Switch to override PHY master/slave setting */ diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index fae58545346..237247f74df 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -69,6 +69,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = { { "rx_crc_errors", E1000_STAT(net_stats.rx_crc_errors) }, { "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) }, { "rx_fifo_errors", E1000_STAT(net_stats.rx_fifo_errors) }, + { "rx_no_buffer_count", E1000_STAT(stats.rnbc) }, { "rx_missed_errors", E1000_STAT(net_stats.rx_missed_errors) }, { "tx_aborted_errors", E1000_STAT(net_stats.tx_aborted_errors) }, { "tx_carrier_errors", E1000_STAT(net_stats.tx_carrier_errors) }, @@ -593,7 +594,7 @@ e1000_set_ringparam(struct net_device *netdev, tx_old = adapter->tx_ring; rx_old = adapter->rx_ring; - if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) + if((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; if(netif_running(adapter->netdev)) @@ -784,8 +785,8 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data) /* Hook up test interrupt handler just for this test */ if(!request_irq(irq, &e1000_test_intr, 0, netdev->name, netdev)) { shared_int = FALSE; - } else if(request_irq(irq, &e1000_test_intr, SA_SHIRQ, - netdev->name, netdev)){ + } else if(request_irq(irq, &e1000_test_intr, SA_SHIRQ, + netdev->name, netdev)){ *data = 1; return -1; } @@ -842,10 +843,8 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data) * test failed. */ adapter->test_icr = 0; - E1000_WRITE_REG(&adapter->hw, IMC, - (~mask & 0x00007FFF)); - E1000_WRITE_REG(&adapter->hw, ICS, - (~mask & 0x00007FFF)); + E1000_WRITE_REG(&adapter->hw, IMC, ~mask & 0x00007FFF); + E1000_WRITE_REG(&adapter->hw, ICS, ~mask & 0x00007FFF); msec_delay(10); if(adapter->test_icr) { @@ -1010,7 +1009,7 @@ e1000_setup_desc_rings(struct e1000_adapter *adapter) struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rxdr, i); struct sk_buff *skb; - if(!(skb = alloc_skb(E1000_RXBUFFER_2048 + NET_IP_ALIGN, + if(!(skb = alloc_skb(E1000_RXBUFFER_2048 + NET_IP_ALIGN, GFP_KERNEL))) { ret_val = 6; goto err_nomem; @@ -1387,13 +1386,12 @@ static int e1000_link_test(struct e1000_adapter *adapter, uint64_t *data) { *data = 0; - if (adapter->hw.media_type == e1000_media_type_internal_serdes) { int i = 0; adapter->hw.serdes_link_down = TRUE; - /* on some blade server designs link establishment */ - /* could take as long as 2-3 minutes. */ + /* On some blade server designs, link establishment + * could take as long as 2-3 minutes */ do { e1000_check_for_link(&adapter->hw); if (adapter->hw.serdes_link_down == FALSE) @@ -1401,7 +1399,7 @@ e1000_link_test(struct e1000_adapter *adapter, uint64_t *data) msec_delay(20); } while (i++ < 3750); - *data = 1; + *data = 1; } else { e1000_check_for_link(&adapter->hw); if(adapter->hw.autoneg) /* if auto_neg is set wait for it */ diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index b7a7ceb67f4..723589b28be 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -144,7 +144,6 @@ e1000_phy_init_script(struct e1000_hw *hw) DEBUGFUNC("e1000_phy_init_script"); - if(hw->phy_init_script) { msec_delay(20); diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 1573f608fb6..a0263ee96c6 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 24d96c02b50..325495b8b60 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -29,33 +29,9 @@ #include "e1000.h" /* Change Log - * 5.3.12 6/7/04 - * - kcompat NETIF_MSG for older kernels (2.4.9) - * - if_mii support and associated kcompat for older kernels - * - More errlogging support from Jon Mason - * - Fix TSO issues on PPC64 machines -- Jon Mason - * - * 5.7.1 12/16/04 - * - Resurrect 82547EI/GI related fix in e1000_intr to avoid deadlocks. This - * fix was removed as it caused system instability. The suspected cause of - * this is the called to e1000_irq_disable in e1000_intr. Inlined the - * required piece of e1000_irq_disable into e1000_intr - Anton Blanchard - * 5.7.0 12/10/04 - * - include fix to the condition that determines when to quit NAPI - Robert Olsson - * - use netif_poll_{disable/enable} to synchronize between NAPI and i/f up/down - * 5.6.5 11/01/04 - * - Enabling NETIF_F_SG without checksum offload is illegal - - John Mason - * 5.6.3 10/26/04 - * - Remove redundant initialization - Jamal Hadi - * - Reset buffer_info->dma in tx resource cleanup logic - * 5.6.2 10/12/04 - * - Avoid filling tx_ring completely - shemminger@osdl.org - * - Replace schedule_timeout() with msleep()/msleep_interruptible() - - * nacc@us.ibm.com - * - Sparse cleanup - shemminger@osdl.org - * - Fix tx resource cleanup logic - * - LLTX support - ak@suse.de and hadi@cyberus.ca + * 6.0.44+ 2/15/05 + * o applied Anton's patch to resolve tx hang in hardware + * o Applied Andrew Mortons patch - e1000 stops working after resume */ char e1000_driver_name[] = "e1000"; @@ -65,7 +41,7 @@ char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; #else #define DRIVERNAPI "-NAPI" #endif -#define DRV_VERSION "5.7.6-k2"DRIVERNAPI +#define DRV_VERSION "6.0.54-k2"DRIVERNAPI char e1000_driver_version[] = DRV_VERSION; char e1000_copyright[] = "Copyright (c) 1999-2004 Intel Corporation."; @@ -96,6 +72,7 @@ static struct pci_device_id e1000_pci_tbl[] = { INTEL_E1000_ETHERNET_DEVICE(0x1017), INTEL_E1000_ETHERNET_DEVICE(0x1018), INTEL_E1000_ETHERNET_DEVICE(0x1019), + INTEL_E1000_ETHERNET_DEVICE(0x101A), INTEL_E1000_ETHERNET_DEVICE(0x101D), INTEL_E1000_ETHERNET_DEVICE(0x101E), INTEL_E1000_ETHERNET_DEVICE(0x1026), @@ -110,6 +87,9 @@ static struct pci_device_id e1000_pci_tbl[] = { INTEL_E1000_ETHERNET_DEVICE(0x107B), INTEL_E1000_ETHERNET_DEVICE(0x107C), INTEL_E1000_ETHERNET_DEVICE(0x108A), + INTEL_E1000_ETHERNET_DEVICE(0x108B), + INTEL_E1000_ETHERNET_DEVICE(0x108C), + INTEL_E1000_ETHERNET_DEVICE(0x1099), /* required last entry */ {0,} }; @@ -350,8 +330,11 @@ e1000_up(struct e1000_adapter *adapter) #endif if((err = request_irq(adapter->pdev->irq, &e1000_intr, SA_SHIRQ | SA_SAMPLE_RANDOM, - netdev->name, netdev))) + netdev->name, netdev))) { + DPRINTK(PROBE, ERR, + "Unable to allocate interrupt Error: %d\n", err); return err; + } mod_timer(&adapter->watchdog_timer, jiffies); @@ -636,7 +619,7 @@ e1000_probe(struct pci_dev *pdev, /* copy the MAC address out of the EEPROM */ - if (e1000_read_mac_addr(&adapter->hw)) + if(e1000_read_mac_addr(&adapter->hw)) DPRINTK(PROBE, ERR, "EEPROM Read Error\n"); memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); @@ -963,12 +946,10 @@ e1000_check_64k_bound(struct e1000_adapter *adapter, unsigned long begin = (unsigned long) start; unsigned long end = begin + len; - /* first rev 82545 and 82546 need to not allow any memory - * write location to cross a 64k boundary due to errata 23 */ + /* First rev 82545 and 82546 need to not allow any memory + * write location to cross 64k boundary due to errata 23 */ if (adapter->hw.mac_type == e1000_82545 || - adapter->hw.mac_type == e1000_82546 ) { - - /* check buffer doesn't cross 64kB */ + adapter->hw.mac_type == e1000_82546) { return ((begin ^ (end - 1)) >> 16) != 0 ? FALSE : TRUE; } @@ -992,8 +973,8 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter) size = sizeof(struct e1000_buffer) * txdr->count; txdr->buffer_info = vmalloc(size); if(!txdr->buffer_info) { - DPRINTK(PROBE, ERR, - "Unable to Allocate Memory for the Transmit descriptor ring\n"); + DPRINTK(PROBE, ERR, + "Unable to allocate memory for the transmit descriptor ring\n"); return -ENOMEM; } memset(txdr->buffer_info, 0, size); @@ -1006,38 +987,38 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter) txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); if(!txdr->desc) { setup_tx_desc_die: - DPRINTK(PROBE, ERR, - "Unable to Allocate Memory for the Transmit descriptor ring\n"); vfree(txdr->buffer_info); + DPRINTK(PROBE, ERR, + "Unable to allocate memory for the transmit descriptor ring\n"); return -ENOMEM; } - /* fix for errata 23, cant cross 64kB boundary */ + /* Fix for errata 23, can't cross 64kB boundary */ if (!e1000_check_64k_bound(adapter, txdr->desc, txdr->size)) { void *olddesc = txdr->desc; dma_addr_t olddma = txdr->dma; - DPRINTK(TX_ERR,ERR,"txdr align check failed: %u bytes at %p\n", - txdr->size, txdr->desc); - /* try again, without freeing the previous */ + DPRINTK(TX_ERR, ERR, "txdr align check failed: %u bytes " + "at %p\n", txdr->size, txdr->desc); + /* Try again, without freeing the previous */ txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); - /* failed allocation, critial failure */ if(!txdr->desc) { + /* Failed allocation, critical failure */ pci_free_consistent(pdev, txdr->size, olddesc, olddma); goto setup_tx_desc_die; } if (!e1000_check_64k_bound(adapter, txdr->desc, txdr->size)) { /* give up */ - pci_free_consistent(pdev, txdr->size, - txdr->desc, txdr->dma); + pci_free_consistent(pdev, txdr->size, txdr->desc, + txdr->dma); pci_free_consistent(pdev, txdr->size, olddesc, olddma); DPRINTK(PROBE, ERR, - "Unable to Allocate aligned Memory for the Transmit" - " descriptor ring\n"); + "Unable to allocate aligned memory " + "for the transmit descriptor ring\n"); vfree(txdr->buffer_info); return -ENOMEM; } else { - /* free old, move on with the new one since its okay */ + /* Free old allocation, new allocation was successful */ pci_free_consistent(pdev, txdr->size, olddesc, olddma); } } @@ -1144,8 +1125,8 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter) size = sizeof(struct e1000_buffer) * rxdr->count; rxdr->buffer_info = vmalloc(size); if(!rxdr->buffer_info) { - DPRINTK(PROBE, ERR, - "Unable to Allocate Memory for the Recieve descriptor ring\n"); + DPRINTK(PROBE, ERR, + "Unable to allocate memory for the receive descriptor ring\n"); return -ENOMEM; } memset(rxdr->buffer_info, 0, size); @@ -1185,43 +1166,42 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter) if(!rxdr->desc) { setup_rx_desc_die: - DPRINTK(PROBE, ERR, - "Unble to Allocate Memory for the Recieve descriptor ring\n"); vfree(rxdr->buffer_info); kfree(rxdr->ps_page); kfree(rxdr->ps_page_dma); + DPRINTK(PROBE, ERR, + "Unable to allocate memory for the receive descriptor ring\n"); return -ENOMEM; } - /* fix for errata 23, cant cross 64kB boundary */ + /* Fix for errata 23, can't cross 64kB boundary */ if (!e1000_check_64k_bound(adapter, rxdr->desc, rxdr->size)) { void *olddesc = rxdr->desc; dma_addr_t olddma = rxdr->dma; - DPRINTK(RX_ERR,ERR, - "rxdr align check failed: %u bytes at %p\n", - rxdr->size, rxdr->desc); - /* try again, without freeing the previous */ + DPRINTK(RX_ERR, ERR, "rxdr align check failed: %u bytes " + "at %p\n", rxdr->size, rxdr->desc); + /* Try again, without freeing the previous */ rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); - /* failed allocation, critial failure */ if(!rxdr->desc) { + /* Failed allocation, critical failure */ pci_free_consistent(pdev, rxdr->size, olddesc, olddma); goto setup_rx_desc_die; } if (!e1000_check_64k_bound(adapter, rxdr->desc, rxdr->size)) { /* give up */ - pci_free_consistent(pdev, rxdr->size, - rxdr->desc, rxdr->dma); + pci_free_consistent(pdev, rxdr->size, rxdr->desc, + rxdr->dma); pci_free_consistent(pdev, rxdr->size, olddesc, olddma); - DPRINTK(PROBE, ERR, - "Unable to Allocate aligned Memory for the" - " Receive descriptor ring\n"); + DPRINTK(PROBE, ERR, + "Unable to allocate aligned memory " + "for the receive descriptor ring\n"); vfree(rxdr->buffer_info); kfree(rxdr->ps_page); kfree(rxdr->ps_page_dma); return -ENOMEM; } else { - /* free old, move on with the new one since its okay */ + /* Free old allocation, new allocation was successful */ pci_free_consistent(pdev, rxdr->size, olddesc, olddma); } } @@ -1234,7 +1214,7 @@ setup_rx_desc_die: } /** - * e1000_setup_rctl - configure the receive control register + * e1000_setup_rctl - configure the receive control registers * @adapter: Board private structure **/ @@ -1426,13 +1406,11 @@ static inline void e1000_unmap_and_free_tx_resource(struct e1000_adapter *adapter, struct e1000_buffer *buffer_info) { - struct pci_dev *pdev = adapter->pdev; - if(buffer_info->dma) { - pci_unmap_page(pdev, - buffer_info->dma, - buffer_info->length, - PCI_DMA_TODEVICE); + pci_unmap_page(adapter->pdev, + buffer_info->dma, + buffer_info->length, + PCI_DMA_TODEVICE); buffer_info->dma = 0; } if(buffer_info->skb) { @@ -1457,7 +1435,7 @@ e1000_clean_tx_ring(struct e1000_adapter *adapter) /* Free all the Tx ring sk_buffs */ if (likely(adapter->previous_buffer_info.skb != NULL)) { - e1000_unmap_and_free_tx_resource(adapter, + e1000_unmap_and_free_tx_resource(adapter, &adapter->previous_buffer_info); } @@ -1659,15 +1637,15 @@ e1000_set_multi(struct net_device *netdev) struct e1000_adapter *adapter = netdev->priv; struct e1000_hw *hw = &adapter->hw; struct dev_mc_list *mc_ptr; + unsigned long flags; uint32_t rctl; uint32_t hash_value; int i; - unsigned long flags; - - /* Check for Promiscuous and All Multicast modes */ spin_lock_irqsave(&adapter->tx_lock, flags); + /* Check for Promiscuous and All Multicast modes */ + rctl = E1000_READ_REG(hw, RCTL); if(netdev->flags & IFF_PROMISC) { @@ -1874,7 +1852,7 @@ e1000_watchdog_task(struct e1000_adapter *adapter) /* Cause software interrupt to ensure rx ring is cleaned */ E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_RXDMT0); - /* Force detection of hung controller every watchdog period*/ + /* Force detection of hung controller every watchdog period */ adapter->detect_tx_hung = TRUE; /* Reset the timer */ @@ -2255,7 +2233,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) #ifdef NETIF_F_TSO mss = skb_shinfo(skb)->tso_size; - /* The controller does a simple calculation to + /* The controller does a simple calculation to * make sure there is enough room in the FIFO before * initiating the DMA for each buffer. The calc is: * 4 = ceil(buffer len/mss). To make sure we don't @@ -2268,7 +2246,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if((mss) || (skb->ip_summed == CHECKSUM_HW)) count++; - count++; /* for sentinel desc */ + count++; #else if(skb->ip_summed == CHECKSUM_HW) count++; @@ -2658,7 +2636,7 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) */ if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2){ atomic_inc(&adapter->irq_sem); - E1000_WRITE_REG(&adapter->hw, IMC, ~0); + E1000_WRITE_REG(hw, IMC, ~0); } for(i = 0; i < E1000_MAX_INTR; i++) @@ -2686,7 +2664,7 @@ e1000_clean(struct net_device *netdev, int *budget) int work_to_do = min(*budget, netdev->quota); int tx_cleaned; int work_done = 0; - + tx_cleaned = e1000_clean_tx_irq(adapter); adapter->clean_rx(adapter, &work_done, work_to_do); @@ -2776,9 +2754,9 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) netif_wake_queue(netdev); spin_unlock(&adapter->tx_lock); - if(adapter->detect_tx_hung) { - /* detect a transmit hang in hardware, this serializes the + + /* Detect a transmit hang in hardware, this serializes the * check with the clearing of time_stamp and movement of i */ adapter->detect_tx_hung = FALSE; if (tx_ring->buffer_info[i].dma && @@ -2923,7 +2901,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) if(unlikely(!(rx_desc->status & E1000_RXD_STAT_EOP))) { /* All receives must fit into a single buffer */ E1000_DBG("%s: Receive packet consumed multiple" - " buffers\n", netdev->name); + " buffers\n", netdev->name); dev_kfree_skb_irq(skb); goto next_desc; } @@ -3130,43 +3108,43 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter) struct e1000_rx_desc *rx_desc; struct e1000_buffer *buffer_info; struct sk_buff *skb; - unsigned int i, bufsz; + unsigned int i; + unsigned int bufsz = adapter->rx_buffer_len + NET_IP_ALIGN; i = rx_ring->next_to_use; buffer_info = &rx_ring->buffer_info[i]; while(!buffer_info->skb) { - bufsz = adapter->rx_buffer_len + NET_IP_ALIGN; - skb = dev_alloc_skb(bufsz); + if(unlikely(!skb)) { /* Better luck next round */ break; } - /* fix for errata 23, cant cross 64kB boundary */ + /* Fix for errata 23, can't cross 64kB boundary */ if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) { struct sk_buff *oldskb = skb; - DPRINTK(RX_ERR,ERR, - "skb align check failed: %u bytes at %p\n", - bufsz, skb->data); - /* try again, without freeing the previous */ + DPRINTK(RX_ERR, ERR, "skb align check failed: %u bytes " + "at %p\n", bufsz, skb->data); + /* Try again, without freeing the previous */ skb = dev_alloc_skb(bufsz); + /* Failed allocation, critical failure */ if (!skb) { dev_kfree_skb(oldskb); break; } + if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) { /* give up */ dev_kfree_skb(skb); dev_kfree_skb(oldskb); break; /* while !buffer_info->skb */ } else { - /* move on with the new one */ + /* Use new allocation */ dev_kfree_skb(oldskb); } } - /* Make buffer alignment 2 beyond a 16 byte boundary * this will result in a 16 byte aligned IP header after * the 14 byte MAC header is removed @@ -3182,25 +3160,23 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter) adapter->rx_buffer_len, PCI_DMA_FROMDEVICE); - /* fix for errata 23, cant cross 64kB boundary */ - if(!e1000_check_64k_bound(adapter, - (void *)(unsigned long)buffer_info->dma, - adapter->rx_buffer_len)) { - DPRINTK(RX_ERR,ERR, - "dma align check failed: %u bytes at %ld\n", - adapter->rx_buffer_len, (unsigned long)buffer_info->dma); - + /* Fix for errata 23, can't cross 64kB boundary */ + if (!e1000_check_64k_bound(adapter, + (void *)(unsigned long)buffer_info->dma, + adapter->rx_buffer_len)) { + DPRINTK(RX_ERR, ERR, + "dma align check failed: %u bytes at %p\n", + adapter->rx_buffer_len, + (void *)(unsigned long)buffer_info->dma); dev_kfree_skb(skb); buffer_info->skb = NULL; - pci_unmap_single(pdev, - buffer_info->dma, + pci_unmap_single(pdev, buffer_info->dma, adapter->rx_buffer_len, PCI_DMA_FROMDEVICE); break; /* while !buffer_info->skb */ } - rx_desc = E1000_RX_DESC(*rx_ring, i); rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); @@ -3210,7 +3186,6 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter) * applicable for weak-ordered memory model archs, * such as IA-64). */ wmb(); - E1000_WRITE_REG(&adapter->hw, RDT, i); } @@ -3483,9 +3458,10 @@ void e1000_pci_set_mwi(struct e1000_hw *hw) { struct e1000_adapter *adapter = hw->back; + int ret_val = pci_set_mwi(adapter->pdev); - int ret; - ret = pci_set_mwi(adapter->pdev); + if(ret_val) + DPRINTK(PROBE, ERR, "Error in setting MWI\n"); } void @@ -3643,8 +3619,7 @@ e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx) break; case SPEED_1000 + DUPLEX_HALF: /* not supported */ default: - DPRINTK(PROBE, ERR, - "Unsupported Speed/Duplexity configuration\n"); + DPRINTK(PROBE, ERR, "Unsupported Speed/Duplex configuration\n"); return -EINVAL; } return 0; @@ -3810,7 +3785,7 @@ e1000_resume(struct pci_dev *pdev) * the interrupt routine is executing. */ static void -e1000_netpoll (struct net_device *netdev) +e1000_netpoll(struct net_device *netdev) { struct e1000_adapter *adapter = netdev->priv; disable_irq(adapter->pdev->irq); diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h index b1915e8eb56..aac64de6143 100644 --- a/drivers/net/e1000/e1000_osdep.h +++ b/drivers/net/e1000/e1000_osdep.h @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index e914d09fe6f..676247f9f1c 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -478,7 +478,6 @@ e1000_check_options(struct e1000_adapter *adapter) DPRINTK(PROBE, INFO, "%s set to dynamic mode\n", opt.name); break; - case -1: default: e1000_validate_option(&adapter->itr, &opt, adapter); -- cgit v1.2.3 From 5633684d008b777ab169e8efcef39a898482f531 Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 18:45:50 -0700 Subject: [PATCH] ixgb: Fix multi-cast packet count in statistics Fix multi-cast packet count in statistics Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/ixgb/ixgb_main.c net-drivers-2.6/drivers/net/ixgb.new/ixgb_main.c --- drivers/net/ixgb/ixgb_main.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 7d26623d859..1498b4e4246 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1526,14 +1526,33 @@ ixgb_change_mtu(struct net_device *netdev, int new_mtu) void ixgb_update_stats(struct ixgb_adapter *adapter) { + struct net_device *netdev = adapter->netdev; + + if((netdev->flags & IFF_PROMISC) || (netdev->flags & IFF_ALLMULTI) || + (netdev->mc_count > IXGB_MAX_NUM_MULTICAST_ADDRESSES)) { + u64 multi = IXGB_READ_REG(&adapter->hw, MPRCL); + u32 bcast_l = IXGB_READ_REG(&adapter->hw, BPRCL); + u32 bcast_h = IXGB_READ_REG(&adapter->hw, BPRCH); + u64 bcast = ((u64)bcast_h << 32) | bcast_l; + + multi |= ((u64)IXGB_READ_REG(&adapter->hw, MPRCH) << 32); + /* fix up multicast stats by removing broadcasts */ + multi -= bcast; + + adapter->stats.mprcl += (multi & 0xFFFFFFFF); + adapter->stats.mprch += (multi >> 32); + adapter->stats.bprcl += bcast_l; + adapter->stats.bprch += bcast_h; + } else { + adapter->stats.mprcl += IXGB_READ_REG(&adapter->hw, MPRCL); + adapter->stats.mprch += IXGB_READ_REG(&adapter->hw, MPRCH); + adapter->stats.bprcl += IXGB_READ_REG(&adapter->hw, BPRCL); + adapter->stats.bprch += IXGB_READ_REG(&adapter->hw, BPRCH); + } adapter->stats.tprl += IXGB_READ_REG(&adapter->hw, TPRL); adapter->stats.tprh += IXGB_READ_REG(&adapter->hw, TPRH); adapter->stats.gprcl += IXGB_READ_REG(&adapter->hw, GPRCL); adapter->stats.gprch += IXGB_READ_REG(&adapter->hw, GPRCH); - adapter->stats.bprcl += IXGB_READ_REG(&adapter->hw, BPRCL); - adapter->stats.bprch += IXGB_READ_REG(&adapter->hw, BPRCH); - adapter->stats.mprcl += IXGB_READ_REG(&adapter->hw, MPRCL); - adapter->stats.mprch += IXGB_READ_REG(&adapter->hw, MPRCH); adapter->stats.uprcl += IXGB_READ_REG(&adapter->hw, UPRCL); adapter->stats.uprch += IXGB_READ_REG(&adapter->hw, UPRCH); adapter->stats.vprcl += IXGB_READ_REG(&adapter->hw, VPRCL); -- cgit v1.2.3 From 06c2f9ecb5b53f9d4fc1ef596da16683cc4af5ba Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 18:46:51 -0700 Subject: [PATCH] ixgb: Do not set the RS bit on context descriptors Don't set the RS bit on context descriptors, causes un-necessary bus activity Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/ixgb/ixgb_main.c net-drivers-2.6/drivers/net/ixgb.new/ixgb_main.c --- drivers/net/ixgb/ixgb_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 1498b4e4246..364a9e78b0c 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1209,10 +1209,10 @@ ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb) | IXGB_CONTEXT_DESC_CMD_TSE | IXGB_CONTEXT_DESC_CMD_IP | IXGB_CONTEXT_DESC_CMD_TCP - | IXGB_CONTEXT_DESC_CMD_RS | IXGB_CONTEXT_DESC_CMD_IDE | (skb->len - (hdr_len))); + if(++i == adapter->tx_ring.count) i = 0; adapter->tx_ring.next_to_use = i; @@ -1247,8 +1247,7 @@ ixgb_tx_csum(struct ixgb_adapter *adapter, struct sk_buff *skb) context_desc->mss = 0; context_desc->cmd_type_len = cpu_to_le32(IXGB_CONTEXT_DESC_TYPE - | IXGB_TX_DESC_CMD_RS - | IXGB_TX_DESC_CMD_IDE); + | IXGB_TX_DESC_CMD_IDE); if(++i == adapter->tx_ring.count) i = 0; adapter->tx_ring.next_to_use = i; -- cgit v1.2.3 From 0c73f58636385a4d3dc68d0d0829d4c39d61b621 Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 18:48:06 -0700 Subject: [PATCH] ixgb: Change RDT write bump size to 4 Change RDT write bump size back to 4 Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/ixgb/ixgb.h net-drivers-2.6/drivers/net/ixgb.new/ixgb.h --- drivers/net/ixgb/ixgb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h index 26c4f15f7fc..f8d3385c784 100644 --- a/drivers/net/ixgb/ixgb.h +++ b/drivers/net/ixgb/ixgb.h @@ -110,7 +110,7 @@ struct ixgb_adapter; #define IXGB_TX_QUEUE_WAKE 16 /* How many Rx Buffers do we bundle into one write to the hardware ? */ -#define IXGB_RX_BUFFER_WRITE 16 /* Must be power of 2 */ +#define IXGB_RX_BUFFER_WRITE 4 /* Must be power of 2 */ /* only works for sizes that are powers of 2 */ #define IXGB_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1))) -- cgit v1.2.3 From 6dfbb6dd391139be9f1cd333877c6e2b03da4bba Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 18:56:40 -0700 Subject: [PATCH] ixgb: Mask RXO interrupt Disable RXO interrupt to decrease recovery time when system is overloaded with data Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/ixgb/ixgb_main.c net-drivers-2.6/drivers/net/ixgb.new/ixgb_main.c --- drivers/net/ixgb/ixgb_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 364a9e78b0c..da6b9d6e6db 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -224,8 +224,8 @@ ixgb_irq_enable(struct ixgb_adapter *adapter) { if(atomic_dec_and_test(&adapter->irq_sem)) { IXGB_WRITE_REG(&adapter->hw, IMS, - IXGB_INT_RXT0 | IXGB_INT_RXDMT0 | IXGB_INT_TXDW | - IXGB_INT_RXO | IXGB_INT_LSC); + IXGB_INT_RXT0 | IXGB_INT_RXDMT0 | IXGB_INT_TXDW | + IXGB_INT_LSC); IXGB_WRITE_FLUSH(&adapter->hw); } } -- cgit v1.2.3 From 41639fed1b32dde4ea3d94242a89308435d341be Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 18:51:54 -0700 Subject: [PATCH] ixgb: Reset status in the Rx Reset status in the Rx descriptor prior to handing it to the controller. Leave three Rx descriptors unused Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/ixgb/ixgb_main.c net-drivers-2.6/drivers/net/ixgb.new/ixgb_main.c --- drivers/net/ixgb/ixgb_main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index da6b9d6e6db..a6a13f6fe65 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1977,8 +1977,8 @@ ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter) num_group_tail_writes = IXGB_RX_BUFFER_WRITE; - /* leave one descriptor unused */ - while(--cleancount > 0) { + /* leave three descriptors unused */ + while(--cleancount > 2) { rx_desc = IXGB_RX_DESC(*rx_ring, i); skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN); @@ -2005,6 +2005,10 @@ ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter) PCI_DMA_FROMDEVICE); rx_desc->buff_addr = cpu_to_le64(buffer_info->dma); + /* guarantee DD bit not set now before h/w gets descriptor + * this is the rest of the workaround for h/w double + * writeback. */ + rx_desc->status = 0; if((i & ~(num_group_tail_writes- 1)) == i) { /* Force memory writes to complete before letting h/w -- cgit v1.2.3 From abf481d6af8670c89f33f354c6fbd9977b23cebc Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:03:32 -0700 Subject: [PATCH] ixgb: Fix EEPROM functions to be endian-aware Fix EEPROM functions to be endian-aware Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/ixgb/ixgb_ee.c net-drivers-2.6/drivers/net/ixgb.new/ixgb_ee.c --- drivers/net/ixgb/ixgb_ee.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/net/ixgb/ixgb_ee.c b/drivers/net/ixgb/ixgb_ee.c index 653e99f919c..3aae110c556 100644 --- a/drivers/net/ixgb/ixgb_ee.c +++ b/drivers/net/ixgb/ixgb_ee.c @@ -411,7 +411,7 @@ ixgb_write_eeprom(struct ixgb_hw *hw, uint16_t offset, uint16_t data) ixgb_cleanup_eeprom(hw); /* clear the init_ctrl_reg_1 to signify that the cache is invalidated */ - ee_map->init_ctrl_reg_1 = EEPROM_ICW1_SIGNATURE_CLEAR; + ee_map->init_ctrl_reg_1 = le16_to_cpu(EEPROM_ICW1_SIGNATURE_CLEAR); return; } @@ -483,7 +483,7 @@ ixgb_get_eeprom_data(struct ixgb_hw *hw) DEBUGOUT("ixgb_ee: Checksum invalid.\n"); /* clear the init_ctrl_reg_1 to signify that the cache is * invalidated */ - ee_map->init_ctrl_reg_1 = EEPROM_ICW1_SIGNATURE_CLEAR; + ee_map->init_ctrl_reg_1 = le16_to_cpu(EEPROM_ICW1_SIGNATURE_CLEAR); return (FALSE); } @@ -579,7 +579,7 @@ ixgb_get_ee_compatibility(struct ixgb_hw *hw) struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return(ee_map->compatibility); + return (le16_to_cpu(ee_map->compatibility)); return(0); } @@ -616,7 +616,7 @@ ixgb_get_ee_init_ctrl_reg_1(struct ixgb_hw *hw) struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return(ee_map->init_ctrl_reg_1); + return (le16_to_cpu(ee_map->init_ctrl_reg_1)); return(0); } @@ -635,7 +635,7 @@ ixgb_get_ee_init_ctrl_reg_2(struct ixgb_hw *hw) struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return(ee_map->init_ctrl_reg_2); + return (le16_to_cpu(ee_map->init_ctrl_reg_2)); return(0); } @@ -654,7 +654,7 @@ ixgb_get_ee_subsystem_id(struct ixgb_hw *hw) struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return(ee_map->subsystem_id); + return (le16_to_cpu(ee_map->subsystem_id)); return(0); } @@ -673,7 +673,7 @@ ixgb_get_ee_subvendor_id(struct ixgb_hw *hw) struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return(ee_map->subvendor_id); + return (le16_to_cpu(ee_map->subvendor_id)); return(0); } @@ -692,7 +692,7 @@ ixgb_get_ee_device_id(struct ixgb_hw *hw) struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return(ee_map->device_id); + return (le16_to_cpu(ee_map->device_id)); return(0); } @@ -711,7 +711,7 @@ ixgb_get_ee_vendor_id(struct ixgb_hw *hw) struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return(ee_map->vendor_id); + return (le16_to_cpu(ee_map->vendor_id)); return(0); } @@ -730,7 +730,7 @@ ixgb_get_ee_swdpins_reg(struct ixgb_hw *hw) struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return(ee_map->swdpins_reg); + return (le16_to_cpu(ee_map->swdpins_reg)); return(0); } @@ -749,7 +749,7 @@ ixgb_get_ee_d3_power(struct ixgb_hw *hw) struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return(ee_map->d3_power); + return (le16_to_cpu(ee_map->d3_power)); return(0); } @@ -768,7 +768,7 @@ ixgb_get_ee_d0_power(struct ixgb_hw *hw) struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return(ee_map->d0_power); + return (le16_to_cpu(ee_map->d0_power)); return(0); } -- cgit v1.2.3 From 5e3c30deb21d0eb0da44830fb1c1fc7054e54229 Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:04:07 -0700 Subject: [PATCH] ixgb: Support for ethtool -d ixgb support for ethtool -d Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/ixgb/ixgb_ethtool.c net-drivers-2.6/drivers/net/ixgb.new/ixgb_ethtool.c --- drivers/net/ixgb/ixgb_ethtool.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index aea10e8aaa7..3fa113854ee 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -252,7 +252,9 @@ ixgb_get_regs(struct net_device *netdev, uint32_t *reg_start = reg; uint8_t i; - regs->version = (adapter->hw.device_id << 16) | adapter->hw.subsystem_id; + /* the 1 (one) below indicates an attempt at versioning, if the + * interface in ethtool or the driver this 1 should be incremented */ + regs->version = (1<<24) | hw->revision_id << 16 | hw->device_id; /* General Registers */ *reg++ = IXGB_READ_REG(hw, CTRL0); /* 0 */ -- cgit v1.2.3 From c2eba932b14718e34ac2609e35c6d41e032a2478 Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:04:32 -0700 Subject: [PATCH] ixgb: Remove hook for suspend, no power management Remove hook for suspend. No power management in 10GbE Controllers Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/ixgb/ixgb_main.c net-drivers-2.6/drivers/net/ixgb.new/ixgb_main.c --- drivers/net/ixgb/ixgb_main.c | 75 +++----------------------------------------- 1 file changed, 4 insertions(+), 71 deletions(-) diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index a6a13f6fe65..0a0f0417f85 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -120,33 +120,20 @@ static void ixgb_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid); static void ixgb_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid); static void ixgb_restore_vlan(struct ixgb_adapter *adapter); -static int ixgb_notify_reboot(struct notifier_block *, unsigned long event, - void *ptr); -static int ixgb_suspend(struct pci_dev *pdev, uint32_t state); - #ifdef CONFIG_NET_POLL_CONTROLLER /* for netdump / net console */ static void ixgb_netpoll(struct net_device *dev); #endif -struct notifier_block ixgb_notifier_reboot = { - .notifier_call = ixgb_notify_reboot, - .next = NULL, - .priority = 0 -}; - /* Exported from other modules */ extern void ixgb_check_options(struct ixgb_adapter *adapter); static struct pci_driver ixgb_driver = { - .name = ixgb_driver_name, + .name = ixgb_driver_name, .id_table = ixgb_pci_tbl, - .probe = ixgb_probe, - .remove = __devexit_p(ixgb_remove), - /* Power Managment Hooks */ - .suspend = NULL, - .resume = NULL + .probe = ixgb_probe, + .remove = __devexit_p(ixgb_remove), }; MODULE_AUTHOR("Intel Corporation, "); @@ -169,17 +156,12 @@ MODULE_LICENSE("GPL"); static int __init ixgb_init_module(void) { - int ret; printk(KERN_INFO "%s - version %s\n", ixgb_driver_string, ixgb_driver_version); printk(KERN_INFO "%s\n", ixgb_copyright); - ret = pci_module_init(&ixgb_driver); - if(ret >= 0) { - register_reboot_notifier(&ixgb_notifier_reboot); - } - return ret; + return pci_module_init(&ixgb_driver); } module_init(ixgb_init_module); @@ -194,7 +176,6 @@ module_init(ixgb_init_module); static void __exit ixgb_exit_module(void) { - unregister_reboot_notifier(&ixgb_notifier_reboot); pci_unregister_driver(&ixgb_driver); } @@ -2121,54 +2102,6 @@ ixgb_restore_vlan(struct ixgb_adapter *adapter) } } -/** - * ixgb_notify_reboot - handles OS notification of reboot event. - * @param nb notifier block, unused - * @param event Event being passed to driver to act upon - * @param p A pointer to our net device - **/ -static int -ixgb_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) -{ - struct pci_dev *pdev = NULL; - - switch(event) { - case SYS_DOWN: - case SYS_HALT: - case SYS_POWER_OFF: - while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) { - if (pci_dev_driver(pdev) == &ixgb_driver) - ixgb_suspend(pdev, 3); - } - } - return NOTIFY_DONE; -} - -/** - * ixgb_suspend - driver suspend function called from notify. - * @param pdev pci driver structure used for passing to - * @param state power state to enter - **/ -static int -ixgb_suspend(struct pci_dev *pdev, uint32_t state) -{ - struct net_device *netdev = pci_get_drvdata(pdev); - struct ixgb_adapter *adapter = netdev->priv; - - netif_device_detach(netdev); - - if(netif_running(netdev)) - ixgb_down(adapter, TRUE); - - pci_save_state(pdev); - - state = (state > 0) ? 3 : 0; - pci_set_power_state(pdev, state); - msec_delay(200); - - return 0; -} - #ifdef CONFIG_NET_POLL_CONTROLLER /* * Polling 'interrupt' - used by things like netconsole to send skbs -- cgit v1.2.3 From f404de1cd407c1f56fa478810c6c48e015d377bd Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:04:54 -0700 Subject: [PATCH] ixgb: Code optimization Code optimization Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/ixgb/ixgb_main.c net-drivers-2.6/drivers/net/ixgb.new/ixgb_main.c --- drivers/net/ixgb/ixgb_main.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 0a0f0417f85..db1089c67eb 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1822,7 +1822,6 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter) struct pci_dev *pdev = adapter->pdev; struct ixgb_rx_desc *rx_desc, *next_rxd; struct ixgb_buffer *buffer_info, *next_buffer, *next2_buffer; - struct sk_buff *skb, *next_skb; uint32_t length; unsigned int i, j; boolean_t cleaned = FALSE; @@ -1832,6 +1831,8 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter) buffer_info = &rx_ring->buffer_info[i]; while(rx_desc->status & IXGB_RX_DESC_STATUS_DD) { + struct sk_buff *skb, *next_skb; + u8 status; #ifdef CONFIG_IXGB_NAPI if(*work_done >= work_to_do) @@ -1839,7 +1840,9 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter) (*work_done)++; #endif + status = rx_desc->status; skb = buffer_info->skb; + prefetch(skb->data); if(++i == rx_ring->count) i = 0; @@ -1864,7 +1867,7 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter) length = le16_to_cpu(rx_desc->length); - if(unlikely(!(rx_desc->status & IXGB_RX_DESC_STATUS_EOP))) { + if(unlikely(!(status & IXGB_RX_DESC_STATUS_EOP))) { /* All receives must fit into a single buffer */ @@ -1872,12 +1875,7 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter) "length<%x>\n", length); dev_kfree_skb_irq(skb); - rx_desc->status = 0; - buffer_info->skb = NULL; - - rx_desc = next_rxd; - buffer_info = next_buffer; - continue; + goto rxdesc_done; } if (unlikely(rx_desc->errors @@ -1886,12 +1884,7 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter) IXGB_RX_DESC_ERRORS_RXE))) { dev_kfree_skb_irq(skb); - rx_desc->status = 0; - buffer_info->skb = NULL; - - rx_desc = next_rxd; - buffer_info = next_buffer; - continue; + goto rxdesc_done; } /* Good Receive */ @@ -1902,7 +1895,7 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter) skb->protocol = eth_type_trans(skb, netdev); #ifdef CONFIG_IXGB_NAPI - if(adapter->vlgrp && (rx_desc->status & IXGB_RX_DESC_STATUS_VP)) { + if(adapter->vlgrp && (status & IXGB_RX_DESC_STATUS_VP)) { vlan_hwaccel_receive_skb(skb, adapter->vlgrp, le16_to_cpu(rx_desc->special) & IXGB_RX_DESC_SPECIAL_VLAN_MASK); @@ -1910,7 +1903,7 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter) netif_receive_skb(skb); } #else /* CONFIG_IXGB_NAPI */ - if(adapter->vlgrp && (rx_desc->status & IXGB_RX_DESC_STATUS_VP)) { + if(adapter->vlgrp && (status & IXGB_RX_DESC_STATUS_VP)) { vlan_hwaccel_rx(skb, adapter->vlgrp, le16_to_cpu(rx_desc->special) & IXGB_RX_DESC_SPECIAL_VLAN_MASK); @@ -1920,9 +1913,12 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter) #endif /* CONFIG_IXGB_NAPI */ netdev->last_rx = jiffies; +rxdesc_done: + /* clean up descriptor, might be written over by hw */ rx_desc->status = 0; buffer_info->skb = NULL; + /* use prefetched values */ rx_desc = next_rxd; buffer_info = next_buffer; } -- cgit v1.2.3 From 37d16f823799918107440cb9e552b0709347f77c Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:05:12 -0700 Subject: [PATCH] ixgb: Fixed msec_delay in osdep to use msleep Fixed msec_delay in osdep to use msleep Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/ixgb/ixgb_osdep.h net-drivers-2.6/drivers/net/ixgb.new/ixgb_osdep.h --- drivers/net/ixgb/ixgb_osdep.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ixgb/ixgb_osdep.h b/drivers/net/ixgb/ixgb_osdep.h index 9eba9289190..dba20481ee8 100644 --- a/drivers/net/ixgb/ixgb_osdep.h +++ b/drivers/net/ixgb/ixgb_osdep.h @@ -45,8 +45,7 @@ /* Don't mdelay in interrupt context! */ \ BUG(); \ } else { \ - set_current_state(TASK_UNINTERRUPTIBLE); \ - schedule_timeout((x * HZ)/1000 + 2); \ + msleep(x); \ } } while(0) #endif -- cgit v1.2.3 From ac79c82e793bc2440c4765e5eb1b834d2c18edf2 Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:05:32 -0700 Subject: [PATCH] ixgb: Driver version, white space, comments, device id Driver version, white space, comments, device id & other Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak diff -up net-drivers-2.6/drivers/net/ixgb/ixgb_main.c net-drivers-2.6/drivers/net/ixgb.new/ixgb_main.c --- drivers/net/ixgb/ixgb_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index db1089c67eb..35f6a7c271a 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -47,7 +47,7 @@ char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver"; #else #define DRIVERNAPI "-NAPI" #endif -char ixgb_driver_version[] = "1.0.90-k2"DRIVERNAPI; +char ixgb_driver_version[] = "1.0.95-k2"DRIVERNAPI; char ixgb_copyright[] = "Copyright (c) 1999-2005 Intel Corporation."; /* ixgb_pci_tbl - PCI Device ID Table @@ -103,6 +103,7 @@ static int ixgb_change_mtu(struct net_device *netdev, int new_mtu); static int ixgb_set_mac(struct net_device *netdev, void *p); static irqreturn_t ixgb_intr(int irq, void *data, struct pt_regs *regs); static boolean_t ixgb_clean_tx_irq(struct ixgb_adapter *adapter); + #ifdef CONFIG_IXGB_NAPI static int ixgb_clean(struct net_device *netdev, int *budget); static boolean_t ixgb_clean_rx_irq(struct ixgb_adapter *adapter, @@ -1253,6 +1254,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, unsigned int nr_frags = skb_shinfo(skb)->nr_frags; unsigned int f; + len -= skb->data_len; i = tx_ring->next_to_use; @@ -1857,7 +1859,6 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter) next_skb = next_buffer->skb; prefetch(next_skb); - cleaned = TRUE; pci_unmap_single(pdev, @@ -2108,6 +2109,7 @@ ixgb_restore_vlan(struct ixgb_adapter *adapter) static void ixgb_netpoll(struct net_device *dev) { struct ixgb_adapter *adapter = dev->priv; + disable_irq(adapter->pdev->irq); ixgb_intr(adapter->pdev->irq, dev, NULL); enable_irq(adapter->pdev->irq); -- cgit v1.2.3 From 2acdb1e05c1a92e05ee710ed8f226a8f3183d5a0 Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:16:58 -0700 Subject: [PATCH] e100: Execute tx_timeout task outside interrupt context Execute tx_timeout task outside the interrupt context Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak --- drivers/net/e100.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 1b68dd5a49b..0f2837ebaab 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -539,6 +539,7 @@ struct nic { struct timer_list watchdog; struct timer_list blink_timer; struct mii_if_info mii; + struct work_struct tx_timeout_task; enum loopback loopback; struct mem *mem; @@ -1716,6 +1717,15 @@ static void e100_tx_timeout(struct net_device *netdev) { struct nic *nic = netdev_priv(netdev); + /* Reset outside of interrupt context, to avoid request_irq + * in interrupt context */ + schedule_work(&nic->tx_timeout_task); +} + +static void e100_tx_timeout_task(struct net_device *netdev) +{ + struct nic *nic = netdev_priv(netdev); + DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n", readb(&nic->csr->scb.status)); e100_down(netdev_priv(netdev)); @@ -2240,6 +2250,9 @@ static int __devinit e100_probe(struct pci_dev *pdev, nic->blink_timer.function = e100_blink_led; nic->blink_timer.data = (unsigned long)nic; + INIT_WORK(&nic->tx_timeout_task, + (void (*)(void *))e100_tx_timeout_task, netdev); + if((err = e100_alloc(nic))) { DPRINTK(PROBE, ERR, "Cannot alloc driver memory, aborting.\n"); goto err_out_iounmap; -- cgit v1.2.3 From 1f53367d5d75ba37f258f6e955d6fc24814051a0 Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:17:20 -0700 Subject: [PATCH] e100: Render e100 NAPI state machine Render e100 NAPI state machine to be similar to the non-NAPI one. Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak --- drivers/net/e100.c | 86 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 71 insertions(+), 15 deletions(-) diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 0f2837ebaab..2c8c14ebf20 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -269,6 +269,12 @@ enum scb_status { rus_mask = 0x3C, }; +enum ru_state { + RU_SUSPENDED = 0, + RU_RUNNING = 1, + RU_UNINITIALIZED = -1, +}; + enum scb_stat_ack { stat_ack_not_ours = 0x00, stat_ack_sw_gen = 0x04, @@ -510,7 +516,7 @@ struct nic { struct rx *rx_to_use; struct rx *rx_to_clean; struct rfd blank_rfd; - int ru_running; + enum ru_state ru_running; spinlock_t cb_lock ____cacheline_aligned; spinlock_t cmd_lock; @@ -1204,7 +1210,9 @@ static void e100_update_stats(struct nic *nic) } } - e100_exec_cmd(nic, cuc_dump_reset, 0); + + if(e100_exec_cmd(nic, cuc_dump_reset, 0)) + DPRINTK(TX_ERR, DEBUG, "exec cuc_dump_reset failed\n"); } static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex) @@ -1298,7 +1306,8 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev) /* SW workaround for ICH[x] 10Mbps/half duplex Tx hang. Issue a NOP command followed by a 1us delay before issuing the Tx command. */ - e100_exec_cmd(nic, cuc_nop, 0); + if(e100_exec_cmd(nic, cuc_nop, 0)) + DPRINTK(TX_ERR, DEBUG, "exec cuc_nop failed\n"); udelay(1); } @@ -1416,12 +1425,18 @@ static int e100_alloc_cbs(struct nic *nic) return 0; } -static inline void e100_start_receiver(struct nic *nic) +static inline void e100_start_receiver(struct nic *nic, struct rx *rx) { + if(!nic->rxs) return; + if(RU_SUSPENDED != nic->ru_running) return; + + /* handle init time starts */ + if(!rx) rx = nic->rxs; + /* (Re)start RU if suspended or idle and RFA is non-NULL */ - if(!nic->ru_running && nic->rx_to_clean->skb) { - e100_exec_cmd(nic, ruc_start, nic->rx_to_clean->dma_addr); - nic->ru_running = 1; + if(rx->skb) { + e100_exec_cmd(nic, ruc_start, rx->dma_addr); + nic->ru_running = RU_RUNNING; } } @@ -1438,6 +1453,13 @@ static inline int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data, RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL); + if(pci_dma_mapping_error(rx->dma_addr)) { + dev_kfree_skb_any(rx->skb); + rx->skb = 0; + rx->dma_addr = 0; + return -ENOMEM; + } + /* Link the RFD to end of RFA by linking previous RFD to * this one, and clearing EL bit of previous. */ if(rx->prev->skb) { @@ -1472,7 +1494,7 @@ static inline int e100_rx_indicate(struct nic *nic, struct rx *rx, /* If data isn't ready, nothing to indicate */ if(unlikely(!(rfd_status & cb_complete))) - return -EAGAIN; + return -ENODATA; /* Get actual data size */ actual_size = le16_to_cpu(rfd->actual_size) & 0x3FFF; @@ -1483,6 +1505,10 @@ static inline int e100_rx_indicate(struct nic *nic, struct rx *rx, pci_unmap_single(nic->pdev, rx->dma_addr, RFD_BUF_LEN, PCI_DMA_FROMDEVICE); + /* this allows for a fast restart without re-enabling interrupts */ + if(le16_to_cpu(rfd->command) & cb_el) + nic->ru_running = RU_SUSPENDED; + /* Pull off the RFD and put the actual data (minus eth hdr) */ skb_reserve(skb, sizeof(struct rfd)); skb_put(skb, actual_size); @@ -1515,20 +1541,45 @@ static inline void e100_rx_clean(struct nic *nic, unsigned int *work_done, unsigned int work_to_do) { struct rx *rx; + int restart_required = 0; + struct rx *rx_to_start = NULL; + + /* are we already rnr? then pay attention!!! this ensures that + * the state machine progression never allows a start with a + * partially cleaned list, avoiding a race between hardware + * and rx_to_clean when in NAPI mode */ + if(RU_SUSPENDED == nic->ru_running) + restart_required = 1; /* Indicate newly arrived packets */ for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) { - if(e100_rx_indicate(nic, rx, work_done, work_to_do)) + int err = e100_rx_indicate(nic, rx, work_done, work_to_do); + if(-EAGAIN == err) { + /* hit quota so have more work to do, restart once + * cleanup is complete */ + restart_required = 0; + break; + } else if(-ENODATA == err) break; /* No more to clean */ } + /* save our starting point as the place we'll restart the receiver */ + if(restart_required) + rx_to_start = nic->rx_to_clean; + /* Alloc new skbs to refill list */ for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) { if(unlikely(e100_rx_alloc_skb(nic, rx))) break; /* Better luck next time (see watchdog) */ } - e100_start_receiver(nic); + if(restart_required) { + // ack the rnr? + writeb(stat_ack_rnr, &nic->csr->scb.stat_ack); + e100_start_receiver(nic, rx_to_start); + if(work_done) + (*work_done)++; + } } static void e100_rx_clean_list(struct nic *nic) @@ -1536,6 +1587,8 @@ static void e100_rx_clean_list(struct nic *nic) struct rx *rx; unsigned int i, count = nic->params.rfds.count; + nic->ru_running = RU_UNINITIALIZED; + if(nic->rxs) { for(rx = nic->rxs, i = 0; i < count; rx++, i++) { if(rx->skb) { @@ -1549,7 +1602,6 @@ static void e100_rx_clean_list(struct nic *nic) } nic->rx_to_use = nic->rx_to_clean = NULL; - nic->ru_running = 0; } static int e100_rx_alloc_list(struct nic *nic) @@ -1558,6 +1610,7 @@ static int e100_rx_alloc_list(struct nic *nic) unsigned int i, count = nic->params.rfds.count; nic->rx_to_use = nic->rx_to_clean = NULL; + nic->ru_running = RU_UNINITIALIZED; if(!(nic->rxs = kmalloc(sizeof(struct rx) * count, GFP_ATOMIC))) return -ENOMEM; @@ -1573,6 +1626,7 @@ static int e100_rx_alloc_list(struct nic *nic) } nic->rx_to_use = nic->rx_to_clean = nic->rxs; + nic->ru_running = RU_SUSPENDED; return 0; } @@ -1594,7 +1648,7 @@ static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs) /* We hit Receive No Resource (RNR); restart RU after cleaning */ if(stat_ack & stat_ack_rnr) - nic->ru_running = 0; + nic->ru_running = RU_SUSPENDED; e100_disable_irq(nic); netif_rx_schedule(netdev); @@ -1684,7 +1738,7 @@ static int e100_up(struct nic *nic) if((err = e100_hw_init(nic))) goto err_clean_cbs; e100_set_multicast_list(nic->netdev); - e100_start_receiver(nic); + e100_start_receiver(nic, 0); mod_timer(&nic->watchdog, jiffies); if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ, nic->netdev->name, nic->netdev))) @@ -1759,7 +1813,7 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode) mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR, BMCR_LOOPBACK); - e100_start_receiver(nic); + e100_start_receiver(nic, 0); if(!(skb = dev_alloc_skb(ETH_DATA_LEN))) { err = -ENOMEM; @@ -2233,6 +2287,7 @@ static int __devinit e100_probe(struct pci_dev *pdev, e100_get_defaults(nic); + /* locks must be initialized before calling hw_reset */ spin_lock_init(&nic->cb_lock); spin_lock_init(&nic->cmd_lock); @@ -2348,7 +2403,8 @@ static int e100_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - e100_hw_init(nic); + if(e100_hw_init(nic)) + DPRINTK(HW, ERR, "e100_hw_init failed\n"); netif_device_attach(netdev); if(netif_running(netdev)) -- cgit v1.2.3 From 0236ebb7ae85935b3b96eef7e8a4e203ea9958a0 Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:17:42 -0700 Subject: [PATCH] e100: Synchronize interface link state with poll routine Synchronize interface link state with e100 poll routine Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak --- drivers/net/e100.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 2c8c14ebf20..c1ca2dae7c4 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1743,8 +1743,11 @@ static int e100_up(struct nic *nic) if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ, nic->netdev->name, nic->netdev))) goto err_no_irq; - e100_enable_irq(nic); netif_wake_queue(nic->netdev); + netif_poll_enable(nic->netdev); + /* enable ints _after_ enabling poll, preventing a race between + * disable ints+schedule */ + e100_enable_irq(nic); return 0; err_no_irq: @@ -1758,11 +1761,13 @@ err_rx_clean_list: static void e100_down(struct nic *nic) { + /* wait here for poll to complete */ + netif_poll_disable(nic->netdev); + netif_stop_queue(nic->netdev); e100_hw_reset(nic); free_irq(nic->pdev->irq, nic->netdev); del_timer_sync(&nic->watchdog); netif_carrier_off(nic->netdev); - netif_stop_queue(nic->netdev); e100_clean_cbs(nic); e100_rx_clean_list(nic); } -- cgit v1.2.3 From 6bdacb1ad58bb6b772a4fc18f21684437bd5f439 Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:17:54 -0700 Subject: [PATCH] e100: Fix Wake on lan related issues Fix Wake on lan related issues Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak --- drivers/net/e100.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/drivers/net/e100.c b/drivers/net/e100.c index c1ca2dae7c4..a43b82512b6 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -971,7 +971,8 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb) if(nic->flags & multicast_all) config->multicast_all = 0x1; /* 1=accept, 0=no */ - if(!(nic->flags & wol_magic)) + /* disable WoL when up */ + if(netif_running(nic->netdev) || !(nic->flags & wol_magic)) config->magic_packet_disable = 0x1; /* 1=off, 0=on */ if(nic->mac >= mac_82558_D101_A4) { @@ -1718,6 +1719,7 @@ static int e100_change_mtu(struct net_device *netdev, int new_mtu) return 0; } +#ifdef CONFIG_PM static int e100_asf(struct nic *nic) { /* ASF can be enabled from eeprom */ @@ -1726,6 +1728,7 @@ static int e100_asf(struct nic *nic) !(nic->eeprom[eeprom_config_asf] & eeprom_gcl) && ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE)); } +#endif static int e100_up(struct nic *nic) { @@ -1938,7 +1941,6 @@ static int e100_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) else nic->flags &= ~wol_magic; - pci_enable_wake(nic->pdev, 0, nic->flags & (wol_magic | e100_asf(nic))); e100_exec_cb(nic, NULL, e100_configure); return 0; @@ -2336,7 +2338,8 @@ static int __devinit e100_probe(struct pci_dev *pdev, (nic->eeprom[eeprom_id] & eeprom_id_wol)) nic->flags |= wol_magic; - pci_enable_wake(pdev, 0, nic->flags & (wol_magic | e100_asf(nic))); + /* ack any pending wake events, disable PME */ + pci_enable_wake(pdev, 0, 0); strcpy(netdev->name, "eth%d"); if((err = register_netdev(netdev))) { @@ -2408,6 +2411,8 @@ static int e100_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); + /* ack any pending wake events, disable PME */ + pci_enable_wake(pdev, 0, 0); if(e100_hw_init(nic)) DPRINTK(HW, ERR, "e100_hw_init failed\n"); @@ -2419,6 +2424,21 @@ static int e100_resume(struct pci_dev *pdev) } #endif + +static void e100_shutdown(struct device *dev) +{ + struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); + struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev_priv(netdev); + +#ifdef CONFIG_PM + pci_enable_wake(pdev, 0, nic->flags & (wol_magic | e100_asf(nic))); +#else + pci_enable_wake(pdev, 0, nic->flags & (wol_magic)); +#endif +} + + static struct pci_driver e100_driver = { .name = DRV_NAME, .id_table = e100_id_table, @@ -2428,6 +2448,11 @@ static struct pci_driver e100_driver = { .suspend = e100_suspend, .resume = e100_resume, #endif + + .driver = { + .shutdown = e100_shutdown, + } + }; static int __init e100_init_module(void) -- cgit v1.2.3 From 962082b6df11fe8cabafd2971b07c914cd52ee2a Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:19:46 -0700 Subject: [PATCH] e100: Performance optimizations to e100 Tx Path Performance optimizations to e100 Tx Path Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak --- drivers/net/e100.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/e100.c b/drivers/net/e100.c index a43b82512b6..fc2a401d561 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -777,7 +777,7 @@ static int e100_eeprom_save(struct nic *nic, u16 start, u16 count) return 0; } -#define E100_WAIT_SCB_TIMEOUT 40 +#define E100_WAIT_SCB_TIMEOUT 20000 /* we might have to wait 100ms!!! */ static inline int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr) { unsigned long flags; @@ -847,6 +847,10 @@ static inline int e100_exec_cb(struct nic *nic, struct sk_buff *skb, * because the controller is too busy, so * let's just queue the command and try again * when another command is scheduled. */ + if(err == -ENOSPC) { + //request a reset + schedule_work(&nic->tx_timeout_task); + } break; } else { nic->cuc_cmd = cuc_resume; @@ -891,7 +895,7 @@ static void mdio_write(struct net_device *netdev, int addr, int reg, int data) static void e100_get_defaults(struct nic *nic) { - struct param_range rfds = { .min = 64, .max = 256, .count = 64 }; + struct param_range rfds = { .min = 16, .max = 256, .count = 64 }; struct param_range cbs = { .min = 64, .max = 256, .count = 64 }; pci_read_config_byte(nic->pdev, PCI_REVISION_ID, &nic->rev_id); @@ -906,8 +910,9 @@ static void e100_get_defaults(struct nic *nic) /* Quadwords to DMA into FIFO before starting frame transmit */ nic->tx_threshold = 0xE0; - nic->tx_command = cpu_to_le16(cb_tx | cb_i | cb_tx_sf | - ((nic->mac >= mac_82558_D101_A4) ? cb_cid : 0)); + /* no interrupt for every tx completion, delay = 256us if not 557*/ + nic->tx_command = cpu_to_le16(cb_tx | cb_tx_sf | + ((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i)); /* Template for a freshly allocated RFD */ nic->blank_rfd.command = cpu_to_le16(cb_el); @@ -1289,12 +1294,15 @@ static inline void e100_xmit_prepare(struct nic *nic, struct cb *cb, struct sk_buff *skb) { cb->command = nic->tx_command; + /* interrupt every 16 packets regardless of delay */ + if((nic->cbs_avail & ~15) == nic->cbs_avail) cb->command |= cb_i; cb->u.tcb.tbd_array = cb->dma_addr + offsetof(struct cb, u.tcb.tbd); cb->u.tcb.tcb_byte_count = 0; cb->u.tcb.threshold = nic->tx_threshold; cb->u.tcb.tbd_count = 1; cb->u.tcb.tbd.buf_addr = cpu_to_le32(pci_map_single(nic->pdev, skb->data, skb->len, PCI_DMA_TODEVICE)); + // check for mapping failure? cb->u.tcb.tbd.size = cpu_to_le16(skb->len); } -- cgit v1.2.3 From 042e2fb70006f135469d546726451b7d14768980 Mon Sep 17 00:00:00 2001 From: Malli Chilakala Date: Thu, 28 Apr 2005 19:20:14 -0700 Subject: [PATCH] e100: Driver version, white space, comments, device id Driver version, white space, comments. Also enabled ICH-7 support Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Ganesh Venkatesan Signed-off-by: John Ronciak --- drivers/net/e100.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/e100.c b/drivers/net/e100.c index fc2a401d561..4a47df5a9ff 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -155,9 +155,9 @@ #define DRV_NAME "e100" #define DRV_EXT "-NAPI" -#define DRV_VERSION "3.3.6-k2"DRV_EXT +#define DRV_VERSION "3.4.8-k2"DRV_EXT #define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" -#define DRV_COPYRIGHT "Copyright(c) 1999-2004 Intel Corporation" +#define DRV_COPYRIGHT "Copyright(c) 1999-2005 Intel Corporation" #define PFX DRV_NAME ": " #define E100_WATCHDOG_PERIOD (2 * HZ) @@ -210,11 +210,17 @@ static struct pci_device_id e100_id_table[] = { INTEL_8255X_ETHERNET_DEVICE(0x1069, 6), INTEL_8255X_ETHERNET_DEVICE(0x106A, 6), INTEL_8255X_ETHERNET_DEVICE(0x106B, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1091, 7), + INTEL_8255X_ETHERNET_DEVICE(0x1092, 7), + INTEL_8255X_ETHERNET_DEVICE(0x1093, 7), + INTEL_8255X_ETHERNET_DEVICE(0x1094, 7), + INTEL_8255X_ETHERNET_DEVICE(0x1095, 7), INTEL_8255X_ETHERNET_DEVICE(0x1209, 0), INTEL_8255X_ETHERNET_DEVICE(0x1229, 0), INTEL_8255X_ETHERNET_DEVICE(0x2449, 2), INTEL_8255X_ETHERNET_DEVICE(0x2459, 2), INTEL_8255X_ETHERNET_DEVICE(0x245D, 2), + INTEL_8255X_ETHERNET_DEVICE(0x27DC, 7), { 0, } }; MODULE_DEVICE_TABLE(pci, e100_id_table); -- cgit v1.2.3 From f85bdb9ce9e130ce00f7a91523931fdd8f96f102 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 12 May 2005 15:49:54 -0400 Subject: [PATCH] libata: stop setting sdev->host->max_sectors for lba48 drives Avoid changing sdev->host->max_sectors because it can prevent use of non-lba48 drives on other ports of the same adapter. Signed-off-by: Stuart Hayes Signed-off-by: John W. Linville --- drivers/scsi/libata-scsi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 4c96df060c3..416ba67ba9e 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -347,7 +347,10 @@ int ata_scsi_slave_config(struct scsi_device *sdev) */ if ((dev->flags & ATA_DFLAG_LBA48) && ((dev->flags & ATA_DFLAG_LOCK_SECTORS) == 0)) { - sdev->host->max_sectors = 2048; + /* + * do not overwrite sdev->host->max_sectors, since + * other drives on this host may not support LBA48 + */ blk_queue_max_sectors(sdev->request_queue, 2048); } } -- cgit v1.2.3 From 1bcd315362e215a72b56d1330bbf32f1c74eefb5 Mon Sep 17 00:00:00 2001 From: Don Fry Date: Fri, 29 Apr 2005 14:51:17 -0700 Subject: [PATCH] pcnet32: fix resource leak with loopback test When running the loopback test, resources are not properly released on completion. This patch frees all transmit resources after running the loopback test. Tested on ia32 and ppc64 hardware. Signed-off-by: Don Fry --- drivers/net/pcnet32.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 17947e6c879..13f11487696 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -22,8 +22,8 @@ *************************************************************************/ #define DRV_NAME "pcnet32" -#define DRV_VERSION "1.30i" -#define DRV_RELDATE "06.28.2004" +#define DRV_VERSION "1.30j" +#define DRV_RELDATE "29.04.2005" #define PFX DRV_NAME ": " static const char *version = @@ -256,6 +256,7 @@ static int homepna[MAX_UNITS]; * homepna for selecting HomePNA mode for PCNet/Home 79C978. * v1.30h 24 Jun 2004 Don Fry correctly select auto, speed, duplex in bcr32. * v1.30i 28 Jun 2004 Don Fry change to use module_param. + * v1.30j 29 Apr 2005 Don Fry fix skb/map leak with loopback test. */ @@ -395,6 +396,7 @@ static void pcnet32_led_blink_callback(struct net_device *dev); static int pcnet32_get_regs_len(struct net_device *dev); static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *ptr); +static void pcnet32_purge_tx_ring(struct net_device *dev); enum pci_flags_bit { PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, @@ -785,6 +787,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t *data1) } clean_up: + pcnet32_purge_tx_ring(dev); x = a->read_csr(ioaddr, 15) & 0xFFFF; a->write_csr(ioaddr, 15, (x & ~0x0044)); /* reset bits 6 and 2 */ -- cgit v1.2.3 From 21b1ed74ee3667dcabcba92e486988ea9119a085 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Fri, 29 Apr 2005 17:34:59 +0800 Subject: [PATCH] libata: Prevent the interrupt handler from completing a command twice Problem: During the libata CD-ROM stress test, sometimes the "BUG: timeout without command" error is seen. Root cause: Unexpected interrupt occurs after the ata_qc_complete() is called, but before the SCSI error handler. The interrupt handler is invoked before the SCSI error handler, and it clears the command by calling ata_qc_complete() again. Later when the SCSI error handler is run, the ata_queued_cmd is already gone, causing the "BUG: timeout without command" error. Changes: - Use the ATA_QCFLAG_ACTIVE flag to prevent the interrupt handler from completing the command twice, before the scsi_error_handler. Signed-off-by: Albert Lee --- drivers/scsi/libata-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 0b5d3a5b7ed..f70935cba17 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2539,7 +2539,7 @@ static void atapi_request_sense(struct ata_port *ap, struct ata_device *dev, ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer)); qc->dma_dir = DMA_FROM_DEVICE; - memset(&qc->cdb, 0, sizeof(ap->cdb_len)); + memset(&qc->cdb, 0, ap->cdb_len); qc->cdb[0] = REQUEST_SENSE; qc->cdb[4] = SCSI_SENSE_BUFFERSIZE; @@ -2811,6 +2811,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) /* call completion callback */ rc = qc->complete_fn(qc, drv_stat); + qc->flags &= ~ATA_QCFLAG_ACTIVE; /* if callback indicates not to complete command (non-zero), * return immediately @@ -3229,7 +3230,8 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs) struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc && (!(qc->tf.ctl & ATA_NIEN))) + if (qc && (!(qc->tf.ctl & ATA_NIEN)) && + (qc->flags & ATA_QCFLAG_ACTIVE)) handled |= ata_host_intr(ap, qc); } } -- cgit v1.2.3 From cdcca89e1a90fa9112260bd6384f20fcc4280e21 Mon Sep 17 00:00:00 2001 From: Brett Russ Date: Mon, 28 Mar 2005 15:10:27 -0500 Subject: [PATCH] libata: flush COMRESET set and clear Updated patch to fix erroneous flush of COMRESET set and missing flush of COMRESET clear. Created a new routine scr_write_flush() to try to prevent this in the future. Also, this patch is based on libata-2.6 instead of the previous libata-dev-2.6 based patch. Signed-off-by: Brett Russ Index: libata-2.6/drivers/scsi/libata-core.c =================================================================== --- drivers/scsi/libata-core.c | 6 +++--- include/linux/libata.h | 7 +++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index f70935cba17..ee9b96da841 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1253,11 +1253,11 @@ void __sata_phy_reset(struct ata_port *ap) unsigned long timeout = jiffies + (HZ * 5); if (ap->flags & ATA_FLAG_SATA_RESET) { - scr_write(ap, SCR_CONTROL, 0x301); /* issue phy wake/reset */ - scr_read(ap, SCR_STATUS); /* dummy read; flush */ + /* issue phy wake/reset */ + scr_write_flush(ap, SCR_CONTROL, 0x301); udelay(400); /* FIXME: a guess */ } - scr_write(ap, SCR_CONTROL, 0x300); /* issue phy wake/clear reset */ + scr_write_flush(ap, SCR_CONTROL, 0x300); /* phy wake/clear reset */ /* wait for phy to become ready, if necessary */ do { diff --git a/include/linux/libata.h b/include/linux/libata.h index 505160ab472..1f7e2039a04 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -584,6 +584,13 @@ static inline void scr_write(struct ata_port *ap, unsigned int reg, u32 val) ap->ops->scr_write(ap, reg, val); } +static inline void scr_write_flush(struct ata_port *ap, unsigned int reg, + u32 val) +{ + ap->ops->scr_write(ap, reg, val); + (void) ap->ops->scr_read(ap, reg); +} + static inline unsigned int sata_dev_present(struct ata_port *ap) { return ((scr_read(ap, SCR_STATUS) & 0xf) == 0x3) ? 1 : 0; -- cgit v1.2.3 From 4b40033ef110b833986c1a1d958a951b695f9fbc Mon Sep 17 00:00:00 2001 From: Domen Puncer Date: Sun, 15 May 2005 16:01:50 -0700 Subject: [SPARC]: Eliminate local MIN/MAX macros in drivers/sbus/char/aurora.c From: Christophe Lucas min/max macros from kernel.h are safe, a lot of handcrafted MIN/MAX are not. Signed-off-by: Christophe Lucas Signed-off-by: Domen Puncer --- drivers/sbus/char/aurora.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c index e5fa1703856..650d5e924f4 100644 --- a/drivers/sbus/char/aurora.c +++ b/drivers/sbus/char/aurora.c @@ -81,10 +81,6 @@ unsigned char irqs[4] = { int irqhit=0; #endif -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - static struct tty_driver *aurora_driver; static struct Aurora_board aurora_board[AURORA_NBOARD] = { {0,}, @@ -594,7 +590,7 @@ static void aurora_transmit(struct Aurora_board const * bp, int chip) &bp->r[chip]->r[CD180_TDR]); port->COR2 &= ~COR2_ETC; } - count = MIN(port->break_length, 0xff); + count = min(port->break_length, 0xff); sbus_writeb(CD180_C_ESC, &bp->r[chip]->r[CD180_TDR]); sbus_writeb(CD180_C_DELAY, @@ -1575,7 +1571,7 @@ static int aurora_write(struct tty_struct * tty, save_flags(flags); while (1) { cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + c = min(count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); if (c <= 0) { restore_flags(flags); -- cgit v1.2.3 From f7a3aae1723e7ffc9c4fcdb489365da7a3d81255 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 3 Apr 2005 09:15:52 +0100 Subject: [PATCH] drivers/net/wireless enabled by wrong option NET_WIRELESS is only a subset of the stuff in drivers/net/wireless; NET_RADIO is what covers all of them. Signed-off-by: Al Viro --- drivers/net/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 6202b10dbb4..e038d55e4f6 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -187,7 +187,7 @@ obj-$(CONFIG_TR) += tokenring/ obj-$(CONFIG_WAN) += wan/ obj-$(CONFIG_ARCNET) += arcnet/ obj-$(CONFIG_NET_PCMCIA) += pcmcia/ -obj-$(CONFIG_NET_WIRELESS) += wireless/ +obj-$(CONFIG_NET_RADIO) += wireless/ obj-$(CONFIG_NET_TULIP) += tulip/ obj-$(CONFIG_HAMRADIO) += hamradio/ obj-$(CONFIG_IRDA) += irda/ -- cgit v1.2.3 From 99718699f5746cc365f3a9ab4769568a1da97635 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Thu, 14 Apr 2005 11:20:32 -0700 Subject: [PATCH] {PATCH] Fix IBM EMAC driver ioctl bug Fix IBM EMAC driver ioctl bug. I found IBM EMAC driver bug. So mii-tool command print wrong status. # mii-tool eth0: 10 Mbit, half duplex, no link eth1: 10 Mbit, half duplex, no link I can get correct status on fixed kernel. # mii-tool eth0: negotiated 100baseTx-FD, link okZZ eth1: negotiated 100baseTx-FD, link ok Hiroaki Fuse Signed-off-by: Geoff Levand for CELF --- drivers/net/ibm_emac/ibm_emac_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index ab44358ddbf..6482d994d48 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -1595,7 +1595,7 @@ static struct ethtool_ops emac_ethtool_ops = { static int emac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct ocp_enet_private *fep = dev->priv; - uint *data = (uint *) & rq->ifr_ifru; + uint16_t *data = (uint16_t *) & rq->ifr_ifru; switch (cmd) { case SIOCGMIIPHY: -- cgit v1.2.3 From c4cc26d3310a6614a20e32276228a5d44159fc9b Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Wed, 27 Apr 2005 12:48:56 +0200 Subject: [PATCH] Typo in tulip driver This patch fixes a typo in tulip driver in 2.6.12-rc3. --- drivers/net/tulip/tulip_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index d098b3ba353..e0ae3ed6e57 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1104,7 +1104,7 @@ static void set_rx_mode(struct net_device *dev) if (entry != 0) { /* Avoid a chip errata by prefixing a dummy entry. Don't do this on the ULI526X as it triggers a different problem */ - if (!(tp->chip_id == ULI526X && (tp->revision = 0x40 || tp->revision == 0x50))) { + if (!(tp->chip_id == ULI526X && (tp->revision == 0x40 || tp->revision == 0x50))) { tp->tx_buffers[entry].skb = NULL; tp->tx_buffers[entry].mapping = 0; tp->tx_ring[entry].length = -- cgit v1.2.3 From c8920ba041c8934b29370f5d62ab9ea8f147966b Mon Sep 17 00:00:00 2001 From: Daniel Andersen Date: Thu, 5 May 2005 15:14:09 -0700 Subject: [PATCH] wireless: 3CRWE154G72 Kconfig help fix Version 2 of the 3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72 is not supported by the prism54 project. To stop confusion, the kernel documentation should state so as 3com made a good job hiding the version. Signed-off-by: Andrew Morton diff -puN drivers/net/wireless/Kconfig~wireless-3crwe154g72-kconfig-help-fix drivers/net/wireless/Kconfig --- drivers/net/wireless/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 0aaa12c0c09..1d3231cc471 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -323,7 +323,7 @@ config PRISM54 For a complete list of supported cards visit . Here is the latest confirmed list of supported cards: - 3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72 + 3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72 (version 1) Allnet ALL0271 PCI Card Compex WL54G Cardbus Card Corega CG-WLCB54GT Cardbus Card -- cgit v1.2.3 From 8711a1b902e691c9b3bbd0d0624f836abe9641ca Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 16 May 2005 23:36:22 +0100 Subject: [PATCH] ARM: Fix build error Mainline kernels don't have VECTORS_HIGH nor COPYPAGE_MINICACHE yet. Signed-off-by: Russell King --- arch/arm/mm/copypage-v4mc.c | 6 +++--- arch/arm/mm/mm-armv.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/mm/copypage-v4mc.c b/arch/arm/mm/copypage-v4mc.c index 16384a7600a..fc69dccdace 100644 --- a/arch/arm/mm/copypage-v4mc.c +++ b/arch/arm/mm/copypage-v4mc.c @@ -71,10 +71,10 @@ void v4_mc_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr) { spin_lock(&minicache_lock); - set_pte(TOP_PTE(COPYPAGE_MINICACHE), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot)); - flush_tlb_kernel_page(COPYPAGE_MINICACHE); + set_pte(TOP_PTE(0xffff8000), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot)); + flush_tlb_kernel_page(0xffff8000); - mc_copy_user_page((void *)COPYPAGE_MINICACHE, kto); + mc_copy_user_page((void *)0xffff8000, kto); spin_unlock(&minicache_lock); } diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index fa60fd65fcf..2c2b93d77d4 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -685,7 +685,7 @@ void __init memtable_init(struct meminfo *mi) flush_cache_all(); flush_tlb_all(); - top_pmd = pmd_off_k(VECTORS_HIGH); + top_pmd = pmd_off_k(0xffff0000); } /* -- cgit v1.2.3 From a84a505956f5c795a9ab3d60d97b6b91a27aa571 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 11 May 2005 00:10:44 -0700 Subject: [PATCH] fix Linux kernel ELF core dump privilege elevation As reported by Paul Starzetz Reference: CAN-2005-1263 Signed-off-by: Greg Kroah-Hartman --- fs/binfmt_elf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index ce9423bb2de..c374be51b04 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -251,7 +251,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec, } /* Populate argv and envp */ - p = current->mm->arg_start; + p = current->mm->arg_end = current->mm->arg_start; while (argc-- > 0) { size_t len; __put_user((elf_addr_t)p, argv++); @@ -1301,7 +1301,7 @@ static void fill_prstatus(struct elf_prstatus *prstatus, static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, struct mm_struct *mm) { - int i, len; + unsigned int i, len; /* first copy the parameters from user space */ memset(psinfo, 0, sizeof(struct elf_prpsinfo)); -- cgit v1.2.3 From 68f66feb300423bb9ee5daecb1951af394425a38 Mon Sep 17 00:00:00 2001 From: Stephen Tweedie Date: Fri, 13 May 2005 23:31:19 -0400 Subject: [PATCH] Fix root hole in raw device [Patch] Fix raw device ioctl pass-through Raw character devices are supposed to pass ioctls through to the block devices they are bound to. Unfortunately, they are using the wrong function for this: ioctl_by_bdev(), instead of blkdev_ioctl(). ioctl_by_bdev() performs a set_fs(KERNEL_DS) before calling the ioctl, redirecting the user-space buffer access to the kernel address space. This is, needless to say, a bad thing. This was noticed first on s390, where raw IO was non-functioning. The s390 driver config does not actually allow raw IO to be enabled, which was the first part of the problem. Secondly, the s390 kernel address space is distinct from user, causing legal raw ioctls to fail. I've reproduced this on a kernel built with 4G:4G split on x86, which fails in the same way (-EFAULT if the address does not exist kernel-side; returns success without actually populating the user buffer if it does.) The patch below fixes both the config and address-space problems. It's based closely on a patch by Jan Glauber , which has been tested on s390 at IBM. I've tested it on x86 4G:4G (split address space) and x86_64 (common address space). Kernel-address-space access has been assigned CAN-2005-1264. Signed-off-by: Stephen Tweedie Signed-off-by: Dave Jones Signed-off-by: Greg Kroah-Hartman --- drivers/block/ioctl.c | 2 ++ drivers/char/raw.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/block/ioctl.c b/drivers/block/ioctl.c index 5e03f5157ef..6d7bcc9da9e 100644 --- a/drivers/block/ioctl.c +++ b/drivers/block/ioctl.c @@ -237,3 +237,5 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg) } return ret; } + +EXPORT_SYMBOL_GPL(blkdev_ioctl); diff --git a/drivers/char/raw.c b/drivers/char/raw.c index a2e33ec7961..131465e8de5 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -122,7 +122,7 @@ raw_ioctl(struct inode *inode, struct file *filp, { struct block_device *bdev = filp->private_data; - return ioctl_by_bdev(bdev, command, arg); + return blkdev_ioctl(bdev->bd_inode, filp, command, arg); } static void bind_device(struct raw_config_request *rq) -- cgit v1.2.3 From 118326e940bdecef6c459d42ccf05256ba86daa7 Mon Sep 17 00:00:00 2001 From: Peter Osterlund Date: Sat, 14 May 2005 00:58:30 -0700 Subject: [PATCH] Fix root hole in pktcdvd ioctl_by_bdev may only be used INSIDE the kernel. If the "arg" argument refers to memory that is accessed by put_user/get_user in the ioctl function, the memory needs to be in the kernel address space (that's the set_fs(KERNEL_DS) doing in the ioctl_by_bdev). This works on i386 because even with set_fs(KERNEL_DS) the user space memory is still accessible with put_user/get_user. That is not true for s390. In short the ioctl implementation of the pktcdvd device driver is horribly broken. Signed-off-by: Peter Osterlund Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/block/pktcdvd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 1a1fa3ccb91..82ccad0a7f1 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2406,7 +2406,7 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u case CDROM_LAST_WRITTEN: case CDROM_SEND_PACKET: case SCSI_IOCTL_SEND_COMMAND: - return ioctl_by_bdev(pd->bdev, cmd, arg); + return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg); case CDROMEJECT: /* @@ -2414,7 +2414,7 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u * have to unlock it or else the eject command fails. */ pkt_lock_door(pd, 0); - return ioctl_by_bdev(pd->bdev, cmd, arg); + return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg); default: printk("pktcdvd: Unknown ioctl for %s (%x)\n", pd->name, cmd); -- cgit v1.2.3 From 80615f81534109a22a732d0328d63ced4432824e Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 10 May 2005 06:45:10 -0700 Subject: [PATCH] USB: usbnet driver fixes Updates to the usbnet driver: - Remove a warning when built with Zaurus support but not CDC Ethernet; just moves an #ifdef to cover more code - Two tweaks to the pseudo-MDLM support: * correctly handle _either_ of the two GUIDs * ignore a padding bit that doesn't seem necessary - Remove ID for one Motorola phone that uses the MDLM stuff. It also updates the Kconfig helptext to make it clearer that the "Zaurus" configuration option supports an increasing (sigh) family of nonstandard peripheral protocols. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/Kconfig | 14 ++++++++----- drivers/usb/net/usbnet.c | 53 ++++++++++++++++++++++++------------------------ 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index db64c908d4a..b104430e2c6 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -219,17 +219,21 @@ config USB_EPSON2888 by some sample firmware from Epson. config USB_ZAURUS - boolean "Sharp Zaurus (stock ROMs)" + boolean "Sharp Zaurus (stock ROMs) and compatible" depends on USB_USBNET select CRC32 default y help Choose this option to support the usb networking links used by Zaurus models like the SL-5000D, SL-5500, SL-5600, A-300, B-500. - - If you install an alternate ROM image, you may no longer need - to support this protocol. Only the "eth-fd" driver really needs - this non-conformant variant of CDC Ethernet protocol. + This also supports some related device firmware, as used in some + PDAs from Olympus and some cell phones from Motorola. + + If you install an alternate ROM image, such as the Linux 2.6 based + versions of OpenZaurus, you should no longer need to support this + protocol. Only the "eth-fd" or "net_fd" drivers in these devices + really need this non-conformant variant of CDC Ethernet (or in + some cases CDC MDLM) protocol, not "g_ether". config USB_CDCETHER boolean "CDC Ethernet support (smart devices such as cable modems)" diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index f6bc6b3b333..85476e76b24 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -1517,6 +1517,26 @@ static void cdc_unbind (struct usbnet *dev, struct usb_interface *intf) } } +#endif /* NEED_GENERIC_CDC */ + + +#ifdef CONFIG_USB_CDCETHER +#define HAVE_HARDWARE + +/*------------------------------------------------------------------------- + * + * Communications Device Class, Ethernet Control model + * + * Takes two interfaces. The DATA interface is inactive till an altsetting + * is selected. Configuration data includes class descriptors. + * + * This should interop with whatever the 2.4 "CDCEther.c" driver + * (by Brad Hards) talked with. + * + *-------------------------------------------------------------------------*/ + +#include + static void dumpspeed (struct usbnet *dev, __le32 *speeds) { @@ -1567,26 +1587,6 @@ static void cdc_status (struct usbnet *dev, struct urb *urb) } } -#endif /* NEED_GENERIC_CDC */ - - -#ifdef CONFIG_USB_CDCETHER -#define HAVE_HARDWARE - -/*------------------------------------------------------------------------- - * - * Communications Device Class, Ethernet Control model - * - * Takes two interfaces. The DATA interface is inactive till an altsetting - * is selected. Configuration data includes class descriptors. - * - * This should interop with whatever the 2.4 "CDCEther.c" driver - * (by Brad Hards) talked with. - * - *-------------------------------------------------------------------------*/ - -#include - static u8 nibble (unsigned char c) { if (likely (isdigit (c))) @@ -2765,7 +2765,7 @@ static int blan_mdlm_bind (struct usbnet *dev, struct usb_interface *intf) } /* expect bcdVersion 1.0, ignore */ if (memcmp(&desc->bGUID, blan_guid, 16) - || memcmp(&desc->bGUID, blan_guid, 16) ) { + && memcmp(&desc->bGUID, blan_guid, 16) ) { /* hey, this one might _really_ be MDLM! */ dev_dbg (&intf->dev, "MDLM guid\n"); goto bad_desc; @@ -2797,11 +2797,13 @@ static int blan_mdlm_bind (struct usbnet *dev, struct usb_interface *intf) * - bPad (ignored, for PADAFTER -- BLAN-only) * bits are: * - 0x01 -- Zaurus framing (add CRC) - * - 0x02 -- PADBEFORE - * - 0x04 -- PADAFTER + * - 0x02 -- PADBEFORE (CRC includes some padding) + * - 0x04 -- PADAFTER (some padding after CRC) * - 0x08 -- "fermat" packet mangling (for hw bugs) + * the PADBEFORE appears not to matter; we interop + * with devices that use it and those that don't. */ - if (detail->bDetailData[1] != 0x01) { + if ((detail->bDetailData[1] & ~02) != 0x01) { /* bmDataCapabilites == 0 would be fine too, * but framing is minidriver-coupled for now. */ @@ -4070,9 +4072,6 @@ static const struct usb_device_id products [] = { }, { USB_DEVICE (0x8086, 0x07d3), // "blob" bootloader .driver_info = (unsigned long) &blob_info, -}, { - USB_DEVICE (0x22b8, 0x600c), // USBNET Motorola E680 - .driver_info = (unsigned long) &linuxdev_info, }, { // Linux Ethernet/RNDIS gadget on pxa210/25x/26x // e.g. Gumstix, current OpenZaurus, ... -- cgit v1.2.3 From 4756ae5b5234e08150ac089f7d989613948f00e5 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 9 May 2005 17:23:51 -0700 Subject: [PATCH] USB: ehci suspend must stop timer Force the EHCI watchdog timer off during suspend, in case for some reason it was still running after the root hub suspended. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hub.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 02fefab3501..429330bc38d 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -72,6 +72,7 @@ static int ehci_hub_suspend (struct usb_hcd *hcd) } /* turn off now-idle HC */ + del_timer_sync (&ehci->watchdog); ehci_halt (ehci); hcd->state = HC_STATE_SUSPENDED; -- cgit v1.2.3 From 25b6f08e3fa0d84e26a373a205cfdad208b54af7 Mon Sep 17 00:00:00 2001 From: Lonnie Mendez Date: Tue, 10 May 2005 17:09:52 -0500 Subject: [PATCH] USB: cypress_m8: add support for the DeLorme Earthmate lt-20 This patch adds support for the DeLorme Earthmate lt-20 to the cypress_m8 driver. The device was tested and found to be compatible with the cypress_m8 driver. This is a resend with the complete patch which properly compiles. Adds support for the DeLorme Earthmate lt-20 to the cypress_m8 driver. Signed-off-by: Lonnie Mendez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cypress_m8.c | 2 ++ drivers/usb/serial/cypress_m8.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index f34a9bb6a21..012e63e0580 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -89,6 +89,7 @@ static int interval; static struct usb_device_id id_table_earthmate [] = { { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) }, + { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) }, { } /* Terminating entry */ }; @@ -99,6 +100,7 @@ static struct usb_device_id id_table_cyphidcomrs232 [] = { static struct usb_device_id id_table_combined [] = { { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) }, + { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) }, { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/cypress_m8.h b/drivers/usb/serial/cypress_m8.h index 1012ee6b19c..1fa119efe41 100644 --- a/drivers/usb/serial/cypress_m8.h +++ b/drivers/usb/serial/cypress_m8.h @@ -13,6 +13,7 @@ /* DeLorme Earthmate USB - a GPS device */ #define VENDOR_ID_DELORME 0x1163 #define PRODUCT_ID_EARTHMATEUSB 0x0100 +#define PRODUCT_ID_EARTHMATEUSB_LT20 0x0200 /* Cypress HID->COM RS232 Adapter */ #define VENDOR_ID_CYPRESS 0x04b4 -- cgit v1.2.3 From 360b52b08972ada8fd4421e9a7bcbe1ea186c20e Mon Sep 17 00:00:00 2001 From: Greg KH Date: Tue, 10 May 2005 06:45:10 -0700 Subject: [PATCH] USB: add modalias sysfs file for usb devices Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/sysfs.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index ec9b3bde8ae..4ab50009291 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -286,6 +286,39 @@ static ssize_t show_interface_string(struct device *dev, char *buf) } static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL); +static ssize_t show_modalias(struct device *dev, char *buf) +{ + struct usb_interface *intf; + struct usb_device *udev; + + intf = to_usb_interface(dev); + udev = interface_to_usbdev(intf); + if (udev->descriptor.bDeviceClass == 0) { + struct usb_host_interface *alt = intf->cur_altsetting; + + return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X\n", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), + le16_to_cpu(udev->descriptor.bcdDevice), + udev->descriptor.bDeviceClass, + udev->descriptor.bDeviceSubClass, + udev->descriptor.bDeviceProtocol, + alt->desc.bInterfaceClass, + alt->desc.bInterfaceSubClass, + alt->desc.bInterfaceProtocol); + } else { + return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic*isc*ip*\n", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), + le16_to_cpu(udev->descriptor.bcdDevice), + udev->descriptor.bDeviceClass, + udev->descriptor.bDeviceSubClass, + udev->descriptor.bDeviceProtocol); + } + +} +static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); + static struct attribute *intf_attrs[] = { &dev_attr_bInterfaceNumber.attr, &dev_attr_bAlternateSetting.attr, @@ -293,6 +326,7 @@ static struct attribute *intf_attrs[] = { &dev_attr_bInterfaceClass.attr, &dev_attr_bInterfaceSubClass.attr, &dev_attr_bInterfaceProtocol.attr, + &dev_attr_modalias.attr, NULL, }; static struct attribute_group intf_attr_grp = { -- cgit v1.2.3 From 135255605d089202bec61b4a000ee762e9bc9d9c Mon Sep 17 00:00:00 2001 From: Pete Jewell Date: Mon, 16 May 2005 21:53:03 -0700 Subject: [PATCH] Fix for bttv driver (v0.9.15) for Leadtek WinFast VC100 XP capture cards This is a tiny patch that fixes bttv-cards.c so that Leadtek WinFast VC100 XP video capture cards work. I've been advised to post it here after having already posted it to the v4l mailing list. Acked-by: Gerd Knorr Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/bttv-cards.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c index 85224b90e39..6334122704a 100644 --- a/drivers/media/video/bttv-cards.c +++ b/drivers/media/video/bttv-cards.c @@ -1946,7 +1946,6 @@ struct tvcard bttv_tvcards[] = { .no_tda9875 = 1, .no_tda7432 = 1, .tuner_type = TUNER_ABSENT, - .no_video = 1, .pll = PLL_28, },{ .name = "Teppro TEV-560/InterVision IV-560", -- cgit v1.2.3 From 0c3f2be423dafb9f914afe85e532e3fffd502fde Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 16 May 2005 21:53:04 -0700 Subject: [PATCH] serio resume fix serio - do not attempt to immediately disconnect port if resume failed, let kseriod take care of it. Otherwise we may attempt to unregister associated input devices which will generate hotplug events which are not handled well during swsusp. Signed-off-by: Dmitry Torokhov Cc: Vojtech Pavlik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/input/serio/serio.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 3313e2daeab..b28ea337935 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -779,7 +779,6 @@ static int serio_resume(struct device *dev) struct serio *serio = to_serio_port(dev); if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) { - serio_disconnect_port(serio); /* * Driver re-probing can take a while, so better let kseriod * deal with it. -- cgit v1.2.3 From 64b14d375263019753dd1405e4edd91a1715301d Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 16 May 2005 21:53:06 -0700 Subject: [PATCH] alps printk tidy Make the alps printk output look consistent. Cc: Vojtech Pavlik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/input/mouse/alps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 1f85a9718c8..52c6fd2e70c 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -395,7 +395,7 @@ int alps_init(struct psmouse *psmouse) } if (param[0] & 0x04) { - printk(KERN_INFO " Enabling hardware tapping\n"); + printk(KERN_INFO "alps.c: Enabling hardware tapping\n"); if (alps_tap_mode(psmouse, 1)) printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n"); } -- cgit v1.2.3 From f3a5c73d5ecb40909db662c4d2ace497b25c5940 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 16 May 2005 21:53:06 -0700 Subject: [PATCH] ALPS resume fix ALPS needs to be reset for detection to work reliably when reconnecting. Signed-off-by: Dmitry Torokhov Cc: Vojtech Pavlik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/input/mouse/alps.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 52c6fd2e70c..42a9f7f6f8c 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -341,6 +341,8 @@ static int alps_reconnect(struct psmouse *psmouse) unsigned char param[4]; int version; + psmouse_reset(psmouse); + if (!(priv->i = alps_get_model(psmouse, &version))) return -1; -- cgit v1.2.3 From 1ff2c873ca11f9e6abffb004b908756b27597672 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 16 May 2005 21:53:07 -0700 Subject: [PATCH] serport oops fix serport - avoid calling serio_interrupt or serio_write_wakeup on unregistered port. Also fix memory leak which could happen if serport was left unused by moving serio allocation down to serport_ldisc_read. Signed-off-by: Dmitry Torokhov Cc: Vojtech Pavlik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/input/serio/serport.c | 98 ++++++++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 30 deletions(-) diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 22f73683952..f6b85222ba3 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -27,11 +27,15 @@ MODULE_LICENSE("GPL"); MODULE_ALIAS_LDISC(N_MOUSE); #define SERPORT_BUSY 1 +#define SERPORT_ACTIVE 2 +#define SERPORT_DEAD 3 struct serport { struct tty_struct *tty; wait_queue_head_t wait; struct serio *serio; + struct serio_device_id id; + spinlock_t lock; unsigned long flags; }; @@ -45,11 +49,29 @@ static int serport_serio_write(struct serio *serio, unsigned char data) return -(serport->tty->driver->write(serport->tty, &data, 1) != 1); } +static int serport_serio_open(struct serio *serio) +{ + struct serport *serport = serio->port_data; + unsigned long flags; + + spin_lock_irqsave(&serport->lock, flags); + set_bit(SERPORT_ACTIVE, &serport->flags); + spin_unlock_irqrestore(&serport->lock, flags); + + return 0; +} + + static void serport_serio_close(struct serio *serio) { struct serport *serport = serio->port_data; + unsigned long flags; + + spin_lock_irqsave(&serport->lock, flags); + clear_bit(SERPORT_ACTIVE, &serport->flags); + set_bit(SERPORT_DEAD, &serport->flags); + spin_unlock_irqrestore(&serport->lock, flags); - serport->serio->id.type = 0; wake_up_interruptible(&serport->wait); } @@ -61,36 +83,21 @@ static void serport_serio_close(struct serio *serio) static int serport_ldisc_open(struct tty_struct *tty) { struct serport *serport; - struct serio *serio; - char name[64]; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - serport = kmalloc(sizeof(struct serport), GFP_KERNEL); - serio = kmalloc(sizeof(struct serio), GFP_KERNEL); - if (unlikely(!serport || !serio)) { - kfree(serport); - kfree(serio); + serport = kcalloc(1, sizeof(struct serport), GFP_KERNEL); + if (!serport) return -ENOMEM; - } - memset(serport, 0, sizeof(struct serport)); - serport->serio = serio; - set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); serport->tty = tty; - tty->disc_data = serport; - - memset(serio, 0, sizeof(struct serio)); - strlcpy(serio->name, "Serial port", sizeof(serio->name)); - snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty, name)); - serio->id.type = SERIO_RS232; - serio->write = serport_serio_write; - serio->close = serport_serio_close; - serio->port_data = serport; - + spin_lock_init(&serport->lock); init_waitqueue_head(&serport->wait); + tty->disc_data = serport; + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + return 0; } @@ -100,7 +107,8 @@ static int serport_ldisc_open(struct tty_struct *tty) static void serport_ldisc_close(struct tty_struct *tty) { - struct serport *serport = (struct serport*) tty->disc_data; + struct serport *serport = (struct serport *) tty->disc_data; + kfree(serport); } @@ -116,9 +124,19 @@ static void serport_ldisc_close(struct tty_struct *tty) 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; int i; + + spin_lock_irqsave(&serport->lock, flags); + + if (!test_bit(SERPORT_ACTIVE, &serport->flags)) + goto out; + for (i = 0; i < count; i++) serio_interrupt(serport->serio, cp[i], 0, NULL); + +out: + spin_unlock_irqrestore(&serport->lock, flags); } /* @@ -141,16 +159,33 @@ static int serport_ldisc_room(struct tty_struct *tty) static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char __user * buf, size_t nr) { struct serport *serport = (struct serport*) tty->disc_data; + struct serio *serio; char name[64]; if (test_and_set_bit(SERPORT_BUSY, &serport->flags)) return -EBUSY; + serport->serio = serio = kcalloc(1, sizeof(struct serio), GFP_KERNEL); + if (!serio) + return -ENOMEM; + + strlcpy(serio->name, "Serial port", sizeof(serio->name)); + snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty, name)); + serio->id = serport->id; + serio->id.type = SERIO_RS232; + serio->write = serport_serio_write; + serio->open = serport_serio_open; + serio->close = serport_serio_close; + serio->port_data = serport; + serio_register_port(serport->serio); printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty, name)); - wait_event_interruptible(serport->wait, !serport->serio->id.type); + + wait_event_interruptible(serport->wait, test_bit(SERPORT_DEAD, &serport->flags)); serio_unregister_port(serport->serio); + serport->serio = NULL; + clear_bit(SERPORT_DEAD, &serport->flags); clear_bit(SERPORT_BUSY, &serport->flags); return 0; @@ -163,16 +198,15 @@ static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, u static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg) { struct serport *serport = (struct serport*) tty->disc_data; - struct serio *serio = serport->serio; unsigned long type; if (cmd == SPIOCSTYPE) { if (get_user(type, (unsigned long __user *) arg)) return -EFAULT; - serio->id.proto = type & 0x000000ff; - serio->id.id = (type & 0x0000ff00) >> 8; - serio->id.extra = (type & 0x00ff0000) >> 16; + serport->id.proto = type & 0x000000ff; + serport->id.id = (type & 0x0000ff00) >> 8; + serport->id.extra = (type & 0x00ff0000) >> 16; return 0; } @@ -182,9 +216,13 @@ static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsi static void serport_ldisc_write_wakeup(struct tty_struct * tty) { - struct serport *sp = (struct serport *) tty->disc_data; + struct serport *serport = (struct serport *) tty->disc_data; + unsigned long flags; - serio_drv_write_wakeup(sp->serio); + spin_lock_irqsave(&serport->lock, flags); + if (test_bit(SERPORT_ACTIVE, &serport->flags)) + serio_drv_write_wakeup(serport->serio); + spin_unlock_irqrestore(&serport->lock, flags); } /* -- cgit v1.2.3 From baae956100334ffbd101eea5eeea9a5ac9cf3abd Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 16 May 2005 21:53:09 -0700 Subject: [PATCH] serio 'id' attributes move serio port's id attributes into separate subdirectory: ..devices/serioX/id_type -> ..devices/serioX/id/type ..devices/serioX/id_proto -> ..devices/serioX/id/proto Signed-off-by: Dmitry Torokhov Cc: Vojtech Pavlik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/input/serio/serio.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index b28ea337935..0beacb77ee1 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -388,6 +388,24 @@ static ssize_t serio_show_id_extra(struct device *dev, char *buf) return sprintf(buf, "%02x\n", serio->id.extra); } +static DEVICE_ATTR(type, S_IRUGO, serio_show_id_type, NULL); +static DEVICE_ATTR(proto, S_IRUGO, serio_show_id_proto, NULL); +static DEVICE_ATTR(id, S_IRUGO, serio_show_id_id, NULL); +static DEVICE_ATTR(extra, S_IRUGO, serio_show_id_extra, NULL); + +static struct attribute *serio_device_id_attrs[] = { + &dev_attr_type.attr, + &dev_attr_proto.attr, + &dev_attr_id.attr, + &dev_attr_extra.attr, + NULL +}; + +static struct attribute_group serio_id_attr_group = { + .name = "id", + .attrs = serio_device_id_attrs, +}; + static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t count) { struct serio *serio = to_serio_port(dev); @@ -444,10 +462,6 @@ static ssize_t serio_set_bind_mode(struct device *dev, const char *buf, size_t c static struct device_attribute serio_device_attrs[] = { __ATTR(description, S_IRUGO, serio_show_description, NULL), - __ATTR(id_type, S_IRUGO, serio_show_id_type, NULL), - __ATTR(id_proto, S_IRUGO, serio_show_id_proto, NULL), - __ATTR(id_id, S_IRUGO, serio_show_id_id, NULL), - __ATTR(id_extra, S_IRUGO, serio_show_id_extra, NULL), __ATTR(drvctl, S_IWUSR, NULL, serio_rebind_driver), __ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode), __ATTR_NULL @@ -498,6 +512,7 @@ static void serio_add_port(struct serio *serio) if (serio->start) serio->start(serio); device_add(&serio->dev); + sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group); serio->registered = 1; } @@ -526,6 +541,7 @@ static void serio_destroy_port(struct serio *serio) } if (serio->registered) { + sysfs_remove_group(&serio->dev.kobj, &serio_id_attr_group); device_del(&serio->dev); list_del_init(&serio->node); serio->registered = 0; -- cgit v1.2.3 From 64d13c00cf1f7c3d2c1ff449e2a0500ab568d319 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Mon, 16 May 2005 21:53:09 -0700 Subject: [PATCH] fix impossible VmallocChunk VmallocTotal: 34359738367 kB VmallocUsed: 266288 kB VmallocChunk: 18014366299193295 kB is unsettling - x86_64 and some other architectures keep a separate address range for modules in vmalloc's vmlist, which /proc/meminfo should pass over. Signed-off-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/mmu.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/fs/proc/mmu.c b/fs/proc/mmu.c index a7041038ad5..25d2d9c6e32 100644 --- a/fs/proc/mmu.c +++ b/fs/proc/mmu.c @@ -50,13 +50,23 @@ void get_vmalloc_info(struct vmalloc_info *vmi) read_lock(&vmlist_lock); for (vma = vmlist; vma; vma = vma->next) { + unsigned long addr = (unsigned long) vma->addr; + + /* + * Some archs keep another range for modules in vmlist + */ + if (addr < VMALLOC_START) + continue; + if (addr >= VMALLOC_END) + break; + vmi->used += vma->size; - free_area_size = (unsigned long) vma->addr - prev_end; + free_area_size = addr - prev_end; if (vmi->largest_chunk < free_area_size) vmi->largest_chunk = free_area_size; - prev_end = vma->size + (unsigned long) vma->addr; + prev_end = vma->size + addr; } if (VMALLOC_END - prev_end > vmi->largest_chunk) -- cgit v1.2.3 From 643bdc6fc0e1928f39b4a3f486447024216ca50f Mon Sep 17 00:00:00 2001 From: "Zhang, Yanmin" Date: Mon, 16 May 2005 21:53:11 -0700 Subject: [PATCH] ide proc destroy error Kernel 2.6 has an ide proc destroy error. Run #modprobe ide-core and #rmmod ide-core, then kernel will dump stack information like below. **********Log****************** Badness in remove_proc_entry at fs/proc/generic.c:693 Call Trace: [] show_stack+0x80/0xa0 sp=3De0000003e05dfbe0 = bsp=3De0000003e05d0ea8 [] dump_stack+0x30/0x60 sp=3De0000003e05dfdb0 = bsp=3De0000003e05d0e90 [] remove_proc_entry+0x530/0x540 sp=3De0000003e05dfdb0 = bsp=3De0000003e05d0e20 [] proc_ide_destroy+0x120/0x140 [ide_core] sp=3De0000003e05dfdc0 = bsp=3De0000003e05d0df0 [] cleanup_module+0x50/0xa0 [ide_core] sp=3De0000003e05dfdc0 = bsp=3De0000003e05d0dd0 [] sys_delete_module+0x390/0x580 sp=3De0000003e05dfdc0 = bsp=3De0000003e05d0d50 [] ia64_ret_from_syscall+0x0/0x20 sp=3De0000003e05dfe30 = bsp=3De0000003e05d0d50 [] _stext+0xffffffff00010640/0x400 sp=3De0000003e05e0000 = bsp=3De0000003e05d0d50 Signed-off-by: Zhang Yanmin Cc: Bartlomiej Zolnierkiewicz Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ide/ide-proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index bdff5ac5805..4b1e43b4118 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -516,6 +516,6 @@ void proc_ide_create(void) void proc_ide_destroy(void) { - remove_proc_entry("ide/drivers", proc_ide_root); + remove_proc_entry("drivers", proc_ide_root); remove_proc_entry("ide", NULL); } -- cgit v1.2.3 From a123edab03ac39e08c2f9cb4fc1af07e099c68bc Mon Sep 17 00:00:00 2001 From: Peter Lundkvist Date: Mon, 16 May 2005 21:53:12 -0700 Subject: [PATCH] Intel 6300ESB TCO timer support Additional i8xx_tco device support. Cc: David Hardeman Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/watchdog/i8xx_tco.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c index c337978dc96..b14d642439e 100644 --- a/drivers/char/watchdog/i8xx_tco.c +++ b/drivers/char/watchdog/i8xx_tco.c @@ -382,6 +382,7 @@ static struct pci_device_id i8xx_tco_pci_tbl[] = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, PCI_ANY_ID, PCI_ANY_ID, }, { 0, }, /* End of list */ }; MODULE_DEVICE_TABLE (pci, i8xx_tco_pci_tbl); -- cgit v1.2.3 From 02048817a70ad04dda5b30ad876c42a232229c99 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Mon, 16 May 2005 21:53:14 -0700 Subject: [PATCH] uml: remove elf.h Actually remove elf.h in the tree. The previous patch, due to a quilt bug/misuse, left it in the tree as a 0-length file, preventing the build to see it as missing and to generate a symlink in its place. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-um/elf.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 include/asm-um/elf.h diff --git a/include/asm-um/elf.h b/include/asm-um/elf.h deleted file mode 100644 index e69de29bb2d..00000000000 -- cgit v1.2.3 From 8f332287bc3f2801ba43682fd79baf24dc8ac1ce Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Mon, 16 May 2005 21:53:14 -0700 Subject: [PATCH] uml: change memcpy to memmove Replace one memcpy() call with overlapping source and dest arguments with one call to memmove(), to avoid data corruption. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/irq_user.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c index 6d6f9484b88..b3074cbaa47 100644 --- a/arch/um/kernel/irq_user.c +++ b/arch/um/kernel/irq_user.c @@ -236,9 +236,15 @@ static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg) (*prev)->fd, pollfds[i].fd); goto out; } - memcpy(&pollfds[i], &pollfds[i + 1], - (pollfds_num - i - 1) * sizeof(pollfds[0])); + pollfds_num--; + + /* This moves the *whole* array after pollfds[i] (though + * it doesn't spot as such)! */ + + memmove(&pollfds[i], &pollfds[i + 1], + (pollfds_num - i) * sizeof(pollfds[0])); + if(last_irq_ptr == &old_fd->next) last_irq_ptr = prev; *prev = (*prev)->next; -- cgit v1.2.3 From 29ac8e056f2016a8404edc02749d095019aa1f82 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 16 May 2005 21:53:15 -0700 Subject: [PATCH] md: fix splitting of md/linear request that cross a device boundary When a request crosses a boundary between devices, it needs to be split. But where we should calculate the amount of the request before the boundary to find the split-point, we care currently calculating the amount that is *after* the boundary !!! Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/linear.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 161e9aa8729..b1941b887f4 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -269,9 +269,8 @@ static int linear_make_request (request_queue_t *q, struct bio *bio) * split it. */ struct bio_pair *bp; - bp = bio_split(bio, bio_split_pool, - (bio->bi_sector + (bio->bi_size >> 9) - - (tmp_dev->offset + tmp_dev->size))<<1); + bp = bio_split(bio, bio_split_pool, + ((tmp_dev->offset + tmp_dev->size)<<1) - bio->bi_sector); if (linear_make_request(q, &bp->bio1)) generic_make_request(&bp->bio1); if (linear_make_request(q, &bp->bio2)) -- cgit v1.2.3 From 7a5febe9ffeecd1e78c5b505260ccc1ef18021b4 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 16 May 2005 21:53:16 -0700 Subject: [PATCH] md: set the unplug_fn and issue_flush_fn for md devices *after* committed to creation We we set the too early, they may still be in place and possibly get called even though the array didn't get set up properly. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/multipath.c | 8 ++++---- drivers/md/raid1.c | 7 +++---- drivers/md/raid10.c | 6 +++--- drivers/md/raid5.c | 7 ++++--- drivers/md/raid6main.c | 6 +++--- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 4e4bfde3db5..2ae2d709cb1 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -462,10 +462,6 @@ static int multipath_run (mddev_t *mddev) } memset(conf->multipaths, 0, sizeof(struct multipath_info)*mddev->raid_disks); - mddev->queue->unplug_fn = multipath_unplug; - - mddev->queue->issue_flush_fn = multipath_issue_flush; - conf->working_disks = 0; ITERATE_RDEV(mddev,rdev,tmp) { disk_idx = rdev->raid_disk; @@ -528,6 +524,10 @@ static int multipath_run (mddev_t *mddev) * Ok, everything is just fine now */ mddev->array_size = mddev->size; + + mddev->queue->unplug_fn = multipath_unplug; + mddev->queue->issue_flush_fn = multipath_issue_flush; + return 0; out_free_conf: diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 83380b5d659..1db5de52d37 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1197,10 +1197,6 @@ static int run(mddev_t *mddev) if (!conf->r1bio_pool) goto out_no_mem; - mddev->queue->unplug_fn = raid1_unplug; - - mddev->queue->issue_flush_fn = raid1_issue_flush; - ITERATE_RDEV(mddev, rdev, tmp) { disk_idx = rdev->raid_disk; if (disk_idx >= mddev->raid_disks @@ -1282,6 +1278,9 @@ static int run(mddev_t *mddev) */ mddev->array_size = mddev->size; + mddev->queue->unplug_fn = raid1_unplug; + mddev->queue->issue_flush_fn = raid1_issue_flush; + return 0; out_no_mem: diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index e9dc2876a62..3c37be6423d 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1639,9 +1639,6 @@ static int run(mddev_t *mddev) mdname(mddev)); goto out_free_conf; } - mddev->queue->unplug_fn = raid10_unplug; - - mddev->queue->issue_flush_fn = raid10_issue_flush; ITERATE_RDEV(mddev, rdev, tmp) { disk_idx = rdev->raid_disk; @@ -1713,6 +1710,9 @@ static int run(mddev_t *mddev) mddev->array_size = size/2; mddev->resync_max_sectors = size; + mddev->queue->unplug_fn = raid10_unplug; + mddev->queue->issue_flush_fn = raid10_issue_flush; + /* Calculate max read-ahead size. * We need to readahead at least twice a whole stripe.... * maybe... diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index e96e2a10a9c..3cb11ac232f 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1620,9 +1620,6 @@ static int run (mddev_t *mddev) atomic_set(&conf->active_stripes, 0); atomic_set(&conf->preread_active_stripes, 0); - mddev->queue->unplug_fn = raid5_unplug_device; - mddev->queue->issue_flush_fn = raid5_issue_flush; - PRINTK("raid5: run(%s) called.\n", mdname(mddev)); ITERATE_RDEV(mddev,rdev,tmp) { @@ -1728,6 +1725,10 @@ memory = conf->max_nr_stripes * (sizeof(struct stripe_head) + } /* Ok, everything is just fine now */ + + mddev->queue->unplug_fn = raid5_unplug_device; + mddev->queue->issue_flush_fn = raid5_issue_flush; + mddev->array_size = mddev->size * (mddev->raid_disks - 1); return 0; abort: diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c index 8a33f351e09..908edd78a79 100644 --- a/drivers/md/raid6main.c +++ b/drivers/md/raid6main.c @@ -1779,9 +1779,6 @@ static int run (mddev_t *mddev) atomic_set(&conf->active_stripes, 0); atomic_set(&conf->preread_active_stripes, 0); - mddev->queue->unplug_fn = raid6_unplug_device; - mddev->queue->issue_flush_fn = raid6_issue_flush; - PRINTK("raid6: run(%s) called.\n", mdname(mddev)); ITERATE_RDEV(mddev,rdev,tmp) { @@ -1895,6 +1892,9 @@ static int run (mddev_t *mddev) /* Ok, everything is just fine now */ mddev->array_size = mddev->size * (mddev->raid_disks - 2); + + mddev->queue->unplug_fn = raid6_unplug_device; + mddev->queue->issue_flush_fn = raid6_issue_flush; return 0; abort: if (conf) { -- cgit v1.2.3 From 202d182a92c60416680e31baa697faa60b0882f5 Mon Sep 17 00:00:00 2001 From: Bjorn Steinbrink Date: Mon, 16 May 2005 21:53:17 -0700 Subject: [PATCH] mm: fix rss counter being incremented when unmapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes a bug introduced by the "mm counter operations through macros" patch, which replaced a decrement operation in with an increment macro in try_to_unmap_one(). Signed-off-by: Björn Steinbrink Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/rmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/rmap.c b/mm/rmap.c index 378de234c12..a6203b4e127 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -586,7 +586,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma) dec_mm_counter(mm, anon_rss); } - inc_mm_counter(mm, rss); + dec_mm_counter(mm, rss); page_remove_rmap(page); page_cache_release(page); -- cgit v1.2.3 From 7179906293ebdc333f14a03d3e58b03604848f3c Mon Sep 17 00:00:00 2001 From: Kirill Korotaev Date: Mon, 16 May 2005 21:53:18 -0700 Subject: [PATCH] mm acct accounting fix This patch fixes mm->total_vm and mm->locked_vm acctounting in case when move_page_tables() fails inside move_vma(). Signed-Off-By: Kirill Korotaev Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mremap.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mm/mremap.c b/mm/mremap.c index 0dd7ace94e5..ec7238a78f3 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -224,6 +224,12 @@ static unsigned long move_vma(struct vm_area_struct *vma, split = 1; } + /* + * if we failed to move page tables we still do total_vm increment + * since do_munmap() will decrement it by old_len == new_len + */ + mm->total_vm += new_len >> PAGE_SHIFT; + if (do_munmap(mm, old_addr, old_len) < 0) { /* OOM: unable to split vma, just get accounts right */ vm_unacct_memory(excess >> PAGE_SHIFT); @@ -237,7 +243,6 @@ static unsigned long move_vma(struct vm_area_struct *vma, vma->vm_next->vm_flags |= VM_ACCOUNT; } - mm->total_vm += new_len >> PAGE_SHIFT; __vm_stat_account(mm, vma->vm_flags, vma->vm_file, new_len>>PAGE_SHIFT); if (vm_flags & VM_LOCKED) { mm->locked_vm += new_len >> PAGE_SHIFT; -- cgit v1.2.3 From ac6b931c44fd9988eaa821c339d54ba06b212412 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 16 May 2005 21:53:19 -0700 Subject: [PATCH] x86_64: Reduce NMI watchdog stack usage NR_CPUs can be quite big these days. kmalloc the per CPU array instead of putting it onto the stack Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/nmi.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c index 61de0b34a01..ec13eb97e8e 100644 --- a/arch/x86_64/kernel/nmi.c +++ b/arch/x86_64/kernel/nmi.c @@ -114,7 +114,7 @@ static __init int cpu_has_lapic(void) static int __init check_nmi_watchdog (void) { - int counts[NR_CPUS]; + int *counts; int cpu; if (nmi_watchdog == NMI_NONE) @@ -125,6 +125,12 @@ static int __init check_nmi_watchdog (void) return -1; } + counts = kmalloc(NR_CPUS * sizeof(int),GFP_KERNEL); + if (!counts) { + nmi_watchdog = NMI_NONE; + return 0; + } + printk(KERN_INFO "Testing NMI watchdog ... "); for (cpu = 0; cpu < NR_CPUS; cpu++) @@ -139,6 +145,7 @@ static int __init check_nmi_watchdog (void) cpu_pda[cpu].__nmi_count); nmi_active = 0; lapic_nmi_owner &= ~LAPIC_NMI_WATCHDOG; + kfree(counts); return -1; } } @@ -149,6 +156,7 @@ static int __init check_nmi_watchdog (void) if (nmi_watchdog == NMI_LOCAL_APIC) nmi_hz = 1; + kfree(counts); return 0; } /* Have this called later during boot so counters are updating */ -- cgit v1.2.3 From 10ffdbb8d605be88b148f127ec86452f1364d4f0 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 16 May 2005 21:53:19 -0700 Subject: [PATCH] x86_64: Readd missing tests in entry.S Cleans up the system exit call slightly and synchronizes with my tree again. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/entry.S | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S index 1086b5fcac2..28817490fdc 100644 --- a/arch/x86_64/kernel/entry.S +++ b/arch/x86_64/kernel/entry.S @@ -220,13 +220,18 @@ sysret_careful: jmp sysret_check /* Handle a signal */ - /* edx: work flags (arg3) */ sysret_signal: sti + testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx + jz 1f + + /* Really a signal */ + /* edx: work flags (arg3) */ leaq do_notify_resume(%rip),%rax leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1 xorl %esi,%esi # oldset -> arg2 call ptregscall_common +1: movl $_TIF_NEED_RESCHED,%edi jmp sysret_check /* Do syscall tracing */ @@ -484,6 +489,8 @@ retint_careful: jmp retint_check retint_signal: + testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx + jz retint_swapgs sti SAVE_REST movq $-1,ORIG_RAX(%rsp) @@ -492,8 +499,8 @@ retint_signal: call do_notify_resume RESTORE_REST cli + movl $_TIF_NEED_RESCHED,%edi GET_THREAD_INFO(%rcx) - movl $_TIF_WORK_MASK,%edi jmp retint_check #ifdef CONFIG_PREEMPT -- cgit v1.2.3 From 637716a3825e186555361574aa1fa3c0ebf8018b Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 16 May 2005 21:53:20 -0700 Subject: [PATCH] x86_64: Add a guard page at the end of the 47bit address space This works around a bug in the AMD K8 CPUs. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-x86_64/processor.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h index f0581c35628..9f74a286ef1 100644 --- a/include/asm-x86_64/processor.h +++ b/include/asm-x86_64/processor.h @@ -159,9 +159,9 @@ static inline void clear_in_cr4 (unsigned long mask) /* - * User space process size. 47bits. + * User space process size. 47bits minus one guard page. */ -#define TASK_SIZE (0x800000000000UL) +#define TASK_SIZE (0x800000000000UL - 4096) /* This decides where the kernel will search for a free chunk of vm * space during mmap's. -- cgit v1.2.3 From a158608bf4c6260caf26089b00a000851e11357a Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 16 May 2005 21:53:21 -0700 Subject: [PATCH] x86_64/i386: fix defaults for physical/core id in /proc/cpuinfo Last round hopefully of cpu_core_id changes hopefully fow now: - Always initialize cpu_core_id for all CPUs, even when no dual core setup is detected. This prevents funny /proc/cpuinfo output - Do the same with phys_proc_id[] even when no HyperThreading - dito. - Use the CPU APIC-ID from CPUID 1 instead of the linux virtual CPU number to identify the core for AMD dual core setups. Patch for i386/x86-64. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/cpu/amd.c | 7 +++---- arch/i386/kernel/cpu/common.c | 7 +++++++ arch/x86_64/kernel/setup.c | 11 ++++++++++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c index 16dbc4151be..fa34a06c0d7 100644 --- a/arch/i386/kernel/cpu/amd.c +++ b/arch/i386/kernel/cpu/amd.c @@ -24,9 +24,6 @@ __asm__(".align 4\nvide: ret"); static void __init init_amd(struct cpuinfo_x86 *c) { -#ifdef CONFIG_X86_SMP - int cpu = c == &boot_cpu_data ? 0 : c - cpu_data; -#endif u32 l, h; int mbytes = num_physpages >> (20-PAGE_SHIFT); int r; @@ -205,7 +202,9 @@ static void __init init_amd(struct cpuinfo_x86 *c) * of two. */ if (c->x86_num_cores > 1) { - cpu_core_id[cpu] = cpu >> hweight32(c->x86_num_cores - 1); + int cpu = smp_processor_id(); + /* Fix up the APIC ID following AMD specifications. */ + cpu_core_id[cpu] >>= hweight32(c->x86_num_cores - 1); printk(KERN_INFO "CPU %d(%d) -> Core %d\n", cpu, c->x86_num_cores, cpu_core_id[cpu]); } diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index 6be0310e3cd..11e6e6f23fa 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -243,6 +243,13 @@ static void __init early_cpu_detect(void) } early_intel_workaround(c); + +#ifdef CONFIG_SMP +#ifdef CONFIG_X86_HT + phys_proc_id[smp_processor_id()] = +#endif + cpu_core_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff; +#endif } void __init generic_identify(struct cpuinfo_x86 * c) diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index 2129cf9ba6b..aab249a5746 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -731,7 +731,8 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c) int node = 0; if (c->x86_num_cores == 1) return; - cpu_core_id[cpu] = cpu >> hweight32(c->x86_num_cores - 1); + /* Fix up the APIC ID following the AMD specification. */ + cpu_core_id[cpu] >>= hweight32(c->x86_num_cores - 1); #ifdef CONFIG_NUMA /* When an ACPI SRAT table is available use the mappings from SRAT @@ -745,6 +746,9 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c) node = cpu_to_node[cpu]; } #endif + /* For now: - better than BAD_APIC_ID at least*/ + phys_proc_id[cpu] = cpu_core_id[cpu]; + printk(KERN_INFO "CPU %d(%d) -> Node %d -> Core %d\n", cpu, c->x86_num_cores, node, cpu_core_id[cpu]); #endif @@ -959,6 +963,11 @@ void __init early_identify_cpu(struct cpuinfo_x86 *c) /* Have CPUID level 0 only - unheard of */ c->x86 = 4; } + +#ifdef CONFIG_SMP + phys_proc_id[smp_processor_id()] = + cpu_core_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff; +#endif } /* -- cgit v1.2.3 From 1f5ee8da005f50d9f46ae5a7edba9a9c2d37b32e Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 16 May 2005 21:53:22 -0700 Subject: [PATCH] x86_64: Increase number of IO-APICs Needed by big systems and only costs a few K of memory. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-x86_64/apicdef.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-x86_64/apicdef.h b/include/asm-x86_64/apicdef.h index 3d7627ffe67..bfebdb69065 100644 --- a/include/asm-x86_64/apicdef.h +++ b/include/asm-x86_64/apicdef.h @@ -112,7 +112,7 @@ #define APIC_BASE (fix_to_virt(FIX_APIC_BASE)) -#define MAX_IO_APICS 32 +#define MAX_IO_APICS 128 /* * All x86-64 systems are xAPIC compatible. -- cgit v1.2.3 From 93ef70a217637ade3f335303a112b22a134a1ec2 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 16 May 2005 21:53:24 -0700 Subject: [PATCH] x86_64: Don't look up struct page pointer of physical address in iounmap It could be in a memory hole not mapped in mem_map and that causes the hash lookup to go off to nirvana. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/mm/ioremap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c index 74ec8554b19..c6fb0cb6999 100644 --- a/arch/x86_64/mm/ioremap.c +++ b/arch/x86_64/mm/ioremap.c @@ -272,7 +272,7 @@ void iounmap(volatile void __iomem *addr) if ((p->flags >> 20) && p->phys_addr + p->size - 1 < virt_to_phys(high_memory)) { /* p->size includes the guard page, but cpa doesn't like that */ - change_page_attr(virt_to_page(__va(p->phys_addr)), + change_page_attr_addr((unsigned long)__va(p->phys_addr), p->size >> PAGE_SHIFT, PAGE_KERNEL); global_flush_tlb(); -- cgit v1.2.3 From dda50e716dc9451f40eebfb2902c260e4f62cf34 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 16 May 2005 21:53:25 -0700 Subject: [PATCH] x86_64: Update TSC sync algorithm The new TSC sync algorithm recently submitted did not work too well. The result was that some MP machines where the TSC came up of the BIOS very unsynchronized and that did not have HPET support were nearly unusable because the time would jump forwards and backwards between CPUs. After a lot of research ;-) and some more prototypes I ended up with just using the one from IA64 which looks best. It has some internal self tuning that should adapt to changing interconnect latencies. It holds up in my tests so far. I believe it was originally written by David Mosberger, I just ported it over to x86-64. See the inline comment for a description. This cleans up the code because it uses smp_call_function for syncing instead of having custom hooks in SMP bootup. Please note that the cycle numbers it outputs are too optimistic because they do not take into account the latency of WRMSR and RDTSC, which can be hundreds of cycles. It seems to be able to sync a dual Opteron to 200-300 cycles, which is probably good enough. There is a timing window during AP bootup where interrupts can see inconsistent time before the TSC is synced. It is hard to avoid unfortunately because we can only do the TSC sync after some setup, and we need to enable interrupts before that. I just ignored it for now. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/smpboot.c | 257 ++++++++++++++++++++++++++++++------------- 1 file changed, 182 insertions(+), 75 deletions(-) diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index 73f7e8b9543..17efc40baa3 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -125,96 +125,210 @@ static void __cpuinit smp_store_cpu_info(int id) *c = boot_cpu_data; identify_cpu(c); + print_cpu_info(c); } /* - * Synchronize TSCs of CPUs + * New Funky TSC sync algorithm borrowed from IA64. + * Main advantage is that it doesn't reset the TSCs fully and + * in general looks more robust and it works better than my earlier + * attempts. I believe it was written by David Mosberger. Some minor + * adjustments for x86-64 by me -AK * - * This new algorithm is less accurate than the old "zero TSCs" - * one, but we cannot zero TSCs anymore in the new hotplug CPU - * model. + * Original comment reproduced below. + * + * Synchronize TSC of the current (slave) CPU with the TSC of the + * MASTER CPU (normally the time-keeper CPU). We use a closed loop to + * eliminate the possibility of unaccounted-for errors (such as + * getting a machine check in the middle of a calibration step). The + * basic idea is for the slave to ask the master what itc value it has + * and to read its own itc before and after the master responds. Each + * iteration gives us three timestamps: + * + * slave master + * + * t0 ---\ + * ---\ + * ---> + * tm + * /--- + * /--- + * t1 <--- + * + * + * The goal is to adjust the slave's TSC such that tm falls exactly + * half-way between t0 and t1. If we achieve this, the clocks are + * synchronized provided the interconnect between the slave and the + * master is symmetric. Even if the interconnect were asymmetric, we + * would still know that the synchronization error is smaller than the + * roundtrip latency (t0 - t1). + * + * When the interconnect is quiet and symmetric, this lets us + * synchronize the TSC to within one or two cycles. However, we can + * only *guarantee* that the synchronization is accurate to within a + * round-trip time, which is typically in the range of several hundred + * cycles (e.g., ~500 cycles). In practice, this means that the TSCs + * are usually almost perfectly synchronized, but we shouldn't assume + * that the accuracy is much better than half a micro second or so. + * + * [there are other errors like the latency of RDTSC and of the + * WRMSR. These can also account to hundreds of cycles. So it's + * probably worse. It claims 153 cycles error on a dual Opteron, + * but I suspect the numbers are actually somewhat worse -AK] */ -static atomic_t __cpuinitdata tsc_flag; +#define MASTER 0 +#define SLAVE (SMP_CACHE_BYTES/8) + +/* Intentionally don't use cpu_relax() while TSC synchronization + because we don't want to go into funky power save modi or cause + hypervisors to schedule us away. Going to sleep would likely affect + latency and low latency is the primary objective here. -AK */ +#define no_cpu_relax() barrier() + static __cpuinitdata DEFINE_SPINLOCK(tsc_sync_lock); -static unsigned long long __cpuinitdata bp_tsc, ap_tsc; +static volatile __cpuinitdata unsigned long go[SLAVE + 1]; +static int notscsync __cpuinitdata; + +#undef DEBUG_TSC_SYNC -#define NR_LOOPS 5 +#define NUM_ROUNDS 64 /* magic value */ +#define NUM_ITERS 5 /* likewise */ -static void __cpuinit sync_tsc_bp_init(int init) +/* Callback on boot CPU */ +static __cpuinit void sync_master(void *arg) { - if (init) - _raw_spin_lock(&tsc_sync_lock); - else - _raw_spin_unlock(&tsc_sync_lock); - atomic_set(&tsc_flag, 0); + unsigned long flags, i; + + if (smp_processor_id() != boot_cpu_id) + return; + + go[MASTER] = 0; + + local_irq_save(flags); + { + for (i = 0; i < NUM_ROUNDS*NUM_ITERS; ++i) { + while (!go[MASTER]) + no_cpu_relax(); + go[MASTER] = 0; + rdtscll(go[SLAVE]); + } + } + local_irq_restore(flags); } /* - * Synchronize TSC on AP with BP. + * Return the number of cycles by which our tsc differs from the tsc + * on the master (time-keeper) CPU. A positive number indicates our + * tsc is ahead of the master, negative that it is behind. */ -static void __cpuinit __sync_tsc_ap(void) +static inline long +get_delta(long *rt, long *master) { - if (!cpu_has_tsc) - return; - Dprintk("AP %d syncing TSC\n", smp_processor_id()); + unsigned long best_t0 = 0, best_t1 = ~0UL, best_tm = 0; + unsigned long tcenter, t0, t1, tm; + int i; - while (atomic_read(&tsc_flag) != 0) - cpu_relax(); - atomic_inc(&tsc_flag); - mb(); - _raw_spin_lock(&tsc_sync_lock); - wrmsrl(MSR_IA32_TSC, bp_tsc); - _raw_spin_unlock(&tsc_sync_lock); - rdtscll(ap_tsc); - mb(); - atomic_inc(&tsc_flag); - mb(); + for (i = 0; i < NUM_ITERS; ++i) { + rdtscll(t0); + go[MASTER] = 1; + while (!(tm = go[SLAVE])) + no_cpu_relax(); + go[SLAVE] = 0; + rdtscll(t1); + + if (t1 - t0 < best_t1 - best_t0) + best_t0 = t0, best_t1 = t1, best_tm = tm; + } + + *rt = best_t1 - best_t0; + *master = best_tm - best_t0; + + /* average best_t0 and best_t1 without overflow: */ + tcenter = (best_t0/2 + best_t1/2); + if (best_t0 % 2 + best_t1 % 2 == 2) + ++tcenter; + return tcenter - best_tm; } -static void __cpuinit sync_tsc_ap(void) +static __cpuinit void sync_tsc(void) { - int i; - for (i = 0; i < NR_LOOPS; i++) - __sync_tsc_ap(); + int i, done = 0; + long delta, adj, adjust_latency = 0; + unsigned long flags, rt, master_time_stamp, bound; +#if DEBUG_TSC_SYNC + static struct syncdebug { + long rt; /* roundtrip time */ + long master; /* master's timestamp */ + long diff; /* difference between midpoint and master's timestamp */ + long lat; /* estimate of tsc adjustment latency */ + } t[NUM_ROUNDS] __cpuinitdata; +#endif + + go[MASTER] = 1; + + smp_call_function(sync_master, NULL, 1, 0); + + while (go[MASTER]) /* wait for master to be ready */ + no_cpu_relax(); + + spin_lock_irqsave(&tsc_sync_lock, flags); + { + for (i = 0; i < NUM_ROUNDS; ++i) { + delta = get_delta(&rt, &master_time_stamp); + if (delta == 0) { + done = 1; /* let's lock on to this... */ + bound = rt; + } + + if (!done) { + unsigned long t; + if (i > 0) { + adjust_latency += -delta; + adj = -delta + adjust_latency/4; + } else + adj = -delta; + + rdtscll(t); + wrmsrl(MSR_IA32_TSC, t + adj); + } +#if DEBUG_TSC_SYNC + t[i].rt = rt; + t[i].master = master_time_stamp; + t[i].diff = delta; + t[i].lat = adjust_latency/4; +#endif + } + } + spin_unlock_irqrestore(&tsc_sync_lock, flags); + +#if DEBUG_TSC_SYNC + for (i = 0; i < NUM_ROUNDS; ++i) + printk("rt=%5ld master=%5ld diff=%5ld adjlat=%5ld\n", + t[i].rt, t[i].master, t[i].diff, t[i].lat); +#endif + + printk(KERN_INFO + "CPU %d: synchronized TSC with CPU %u (last diff %ld cycles, " + "maxerr %lu cycles)\n", + smp_processor_id(), boot_cpu_id, delta, rt); } -/* - * Synchronize TSC from BP to AP. - */ -static void __cpuinit __sync_tsc_bp(int cpu) +static void __cpuinit tsc_sync_wait(void) { - if (!cpu_has_tsc) + if (notscsync || !cpu_has_tsc) return; - - /* Wait for AP */ - while (atomic_read(&tsc_flag) == 0) - cpu_relax(); - /* Save BPs TSC */ - sync_core(); - rdtscll(bp_tsc); - /* Don't do the sync core here to avoid too much latency. */ - mb(); - /* Start the AP */ - _raw_spin_unlock(&tsc_sync_lock); - /* Wait for AP again */ - while (atomic_read(&tsc_flag) < 2) - cpu_relax(); - rdtscl(bp_tsc); - barrier(); + printk(KERN_INFO "CPU %d: Syncing TSC to CPU %u.\n", smp_processor_id(), + boot_cpu_id); + sync_tsc(); } -static void __cpuinit sync_tsc_bp(int cpu) +static __init int notscsync_setup(char *s) { - int i; - for (i = 0; i < NR_LOOPS - 1; i++) { - __sync_tsc_bp(cpu); - sync_tsc_bp_init(1); - } - __sync_tsc_bp(cpu); - printk(KERN_INFO "Synced TSC of CPU %d difference %Ld\n", - cpu, ap_tsc - bp_tsc); + notscsync = 1; + return 0; } +__setup("notscsync", notscsync_setup); static atomic_t init_deasserted __cpuinitdata; @@ -315,11 +429,6 @@ void __cpuinit start_secondary(void) cpu_init(); smp_callin(); - /* - * Synchronize the TSC with the BP - */ - sync_tsc_ap(); - /* otherwise gcc will move up the smp_processor_id before the cpu_init */ barrier(); @@ -334,7 +443,6 @@ void __cpuinit start_secondary(void) enable_8259A_irq(0); } - enable_APIC_timer(); /* @@ -343,6 +451,11 @@ void __cpuinit start_secondary(void) cpu_set(smp_processor_id(), cpu_online_map); mb(); + /* Wait for TSC sync to not schedule things before. + We still process interrupts, which could see an inconsistent + time in that window unfortunately. */ + tsc_sync_wait(); + cpu_idle(); } @@ -600,8 +713,6 @@ static int __cpuinit do_boot_cpu(int cpu, int apicid) if (cpu_isset(cpu, cpu_callin_map)) { /* number CPUs logically, starting from 1 (BSP is 0) */ - Dprintk("OK.\n"); - print_cpu_info(&cpu_data[cpu]); Dprintk("CPU has booted.\n"); } else { boot_error = 1; @@ -889,18 +1000,14 @@ int __cpuinit __cpu_up(unsigned int cpu) printk("__cpu_up: bad cpu %d\n", cpu); return -EINVAL; } - sync_tsc_bp_init(1); /* Boot it! */ err = do_boot_cpu(cpu, apicid); if (err < 0) { - sync_tsc_bp_init(0); Dprintk("do_boot_cpu failed %d\n", err); return err; } - sync_tsc_bp(cpu); - /* Unleash the CPU! */ Dprintk("waiting for cpu %d\n", cpu); -- cgit v1.2.3 From 2942283e970b357c146ebdcbbcc0bdf5048615ff Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 16 May 2005 21:53:26 -0700 Subject: [PATCH] x86_64: Remove x86_apicid field Remove x86_apicid field Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/setup.c | 4 +--- include/asm-x86_64/processor.h | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index aab249a5746..966dfc768cb 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -727,7 +727,7 @@ static void __init display_cacheinfo(struct cpuinfo_x86 *c) static void __init amd_detect_cmp(struct cpuinfo_x86 *c) { #ifdef CONFIG_SMP - int cpu = c->x86_apicid; + int cpu = smp_processor_id(); int node = 0; if (c->x86_num_cores == 1) return; @@ -929,7 +929,6 @@ void __init early_identify_cpu(struct cpuinfo_x86 *c) c->x86_clflush_size = 64; c->x86_cache_alignment = c->x86_clflush_size; c->x86_num_cores = 1; - c->x86_apicid = c == &boot_cpu_data ? 0 : c - cpu_data; c->extended_cpuid_level = 0; memset(&c->x86_capability, 0, sizeof c->x86_capability); @@ -958,7 +957,6 @@ void __init early_identify_cpu(struct cpuinfo_x86 *c) } if (c->x86_capability[0] & (1<<19)) c->x86_clflush_size = ((misc >> 8) & 0xff) * 8; - c->x86_apicid = misc >> 24; } else { /* Have CPUID level 0 only - unheard of */ c->x86 = 4; diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h index 9f74a286ef1..d641b19f6da 100644 --- a/include/asm-x86_64/processor.h +++ b/include/asm-x86_64/processor.h @@ -62,7 +62,6 @@ struct cpuinfo_x86 { int x86_tlbsize; /* number of 4K pages in DTLB/ITLB combined(in pages)*/ __u8 x86_virt_bits, x86_phys_bits; __u8 x86_num_cores; - __u8 x86_apicid; __u32 x86_power; __u32 extended_cpuid_level; /* Max extended CPUID function supported */ unsigned long loops_per_jiffy; -- cgit v1.2.3 From 622dcaf974668f7dee252fc6a8f9a2710c2070f4 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 16 May 2005 21:53:26 -0700 Subject: [PATCH] x86_64: Don't print the internal k8c+ flag in /proc/cpuinfo It is not very useful to the user and more an kernel internal implementation detail. So hide it. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index 966dfc768cb..b9fd0252c27 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -1095,7 +1095,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* Other (Linux-defined) */ - "cxmmx", NULL, "cyrix_arr", "centaur_mcr", "k8c+", + "cxmmx", NULL, "cyrix_arr", "centaur_mcr", NULL, "constant_tsc", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -- cgit v1.2.3 From 0af2be0b721997512191e981a051fcb070b87260 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 16 May 2005 21:53:27 -0700 Subject: [PATCH] x86_64: Remove unique APIC/IO-APIC ID check It is unnecessary on modern Intel or AMD systems, and that is all we support on x86-64 Also causes problems on various systems Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/io_apic.c | 70 -------------------------------------------- arch/x86_64/kernel/mpparse.c | 2 +- include/asm-x86_64/io_apic.h | 1 - 3 files changed, 1 insertion(+), 72 deletions(-) diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 60be58617eb..ac768432495 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -1804,76 +1804,6 @@ device_initcall(ioapic_init_sysfs); #define IO_APIC_MAX_ID 0xFE -int __init io_apic_get_unique_id (int ioapic, int apic_id) -{ - union IO_APIC_reg_00 reg_00; - static physid_mask_t apic_id_map; - unsigned long flags; - int i = 0; - - /* - * The P4 platform supports up to 256 APIC IDs on two separate APIC - * buses (one for LAPICs, one for IOAPICs), where predecessors only - * supports up to 16 on one shared APIC bus. - * - * TBD: Expand LAPIC/IOAPIC support on P4-class systems to take full - * advantage of new APIC bus architecture. - */ - - if (physids_empty(apic_id_map)) - apic_id_map = phys_cpu_present_map; - - spin_lock_irqsave(&ioapic_lock, flags); - reg_00.raw = io_apic_read(ioapic, 0); - spin_unlock_irqrestore(&ioapic_lock, flags); - - if (apic_id >= IO_APIC_MAX_ID) { - apic_printk(APIC_QUIET, KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying " - "%d\n", ioapic, apic_id, reg_00.bits.ID); - apic_id = reg_00.bits.ID; - } - - /* - * Every APIC in a system must have a unique ID or we get lots of nice - * 'stuck on smp_invalidate_needed IPI wait' messages. - */ - if (physid_isset(apic_id, apic_id_map)) { - - for (i = 0; i < IO_APIC_MAX_ID; i++) { - if (!physid_isset(i, apic_id_map)) - break; - } - - if (i == IO_APIC_MAX_ID) - panic("Max apic_id exceeded!\n"); - - apic_printk(APIC_VERBOSE, KERN_WARNING "IOAPIC[%d]: apic_id %d already used, " - "trying %d\n", ioapic, apic_id, i); - - apic_id = i; - } - - physid_set(apic_id, apic_id_map); - - if (reg_00.bits.ID != apic_id) { - reg_00.bits.ID = apic_id; - - spin_lock_irqsave(&ioapic_lock, flags); - io_apic_write(ioapic, 0, reg_00.raw); - reg_00.raw = io_apic_read(ioapic, 0); - spin_unlock_irqrestore(&ioapic_lock, flags); - - /* Sanity check */ - if (reg_00.bits.ID != apic_id) - panic("IOAPIC[%d]: Unable change apic_id!\n", ioapic); - } - - apic_printk(APIC_VERBOSE,KERN_INFO "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id); - - return apic_id; -} - - int __init io_apic_get_version (int ioapic) { union IO_APIC_reg_01 reg_01; diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c index 7ec031c6ca1..f221231cd0a 100644 --- a/arch/x86_64/kernel/mpparse.c +++ b/arch/x86_64/kernel/mpparse.c @@ -759,7 +759,7 @@ void __init mp_register_ioapic ( mp_ioapics[idx].mpc_apicaddr = address; set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address); - mp_ioapics[idx].mpc_apicid = io_apic_get_unique_id(idx, id); + mp_ioapics[idx].mpc_apicid = id; mp_ioapics[idx].mpc_apicver = io_apic_get_version(idx); /* diff --git a/include/asm-x86_64/io_apic.h b/include/asm-x86_64/io_apic.h index 7efc932e8f0..32573749004 100644 --- a/include/asm-x86_64/io_apic.h +++ b/include/asm-x86_64/io_apic.h @@ -202,7 +202,6 @@ extern int skip_ioapic_setup; #define io_apic_assign_pci_irqs (mp_irq_entries && !skip_ioapic_setup && io_apic_irqs) #ifdef CONFIG_ACPI_BOOT -extern int io_apic_get_unique_id (int ioapic, int apic_id); extern int io_apic_get_version (int ioapic); extern int io_apic_get_redir_entries (int ioapic); extern int io_apic_set_pci_routing (int ioapic, int pin, int irq, int, int); -- cgit v1.2.3 From 312df5f1a1da780e084b328bcabb02a6dcd044c3 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 16 May 2005 21:53:28 -0700 Subject: [PATCH] x86_64: Add pmtimer support There are unfortunately more and more multi processor Opteron systems which don't have HPET timer support in the southbridge. This covers in particular Nvidia and VIA chipsets. They also don't guarantee that the TSCs are synchronized between CPUs; and especially with MP powernow the systems are nearly unusable because the time gets very inconsistent between CPUs. The timer code for x86-64 was originally written under the assumption that we could fall back to the HPET timer on such systems. But this doesn't work there. Another alternative is to use the ACPI PM timer as primary time source. This patch does that. The kernel only uses PM timer when there is no other choice because it has some disadvantages. Ported over from i386. It should be faster than the i386 version because I dropped the "read three times" workaround, but is still considerable slower than HPET and also does not work together with vsyscalls which have to be disabled. Cc: Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/Kconfig | 14 ++++++ arch/x86_64/kernel/Makefile | 1 + arch/x86_64/kernel/pmtimer.c | 101 ++++++++++++++++++++++++++++++++++++++++++ arch/x86_64/kernel/time.c | 62 +++++++++++++++++++------- arch/x86_64/kernel/vsyscall.c | 3 +- include/asm-x86_64/proto.h | 5 +++ include/asm-x86_64/vsyscall.h | 3 ++ 7 files changed, 170 insertions(+), 19 deletions(-) create mode 100644 arch/x86_64/kernel/pmtimer.c diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index 44ee7f6acf7..82cb2a3f127 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -303,6 +303,20 @@ config HPET_TIMER as it is off-chip. You can find the HPET spec at . +config X86_PM_TIMER + bool "PM timer" + default y + help + Support the ACPI PM timer for time keeping. This is slow, + but is useful on some chipsets without HPET on systems with more + than one CPU. On a single processor or single socket multi core + system it is normally not required. + When the PM timer is active 64bit vsyscalls are disabled + and should not be enabled (/proc/sys/kernel/vsyscall64 should + not be changed). + The kernel selects the PM timer only as a last resort, so it is + useful to enable just in case. + config HPET_EMULATE_RTC bool "Provide RTC interrupt" depends on HPET_TIMER && RTC=y diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 0a3318e08ab..5ca4a4598fd 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_GART_IOMMU) += pci-gart.o aperture.o obj-$(CONFIG_DUMMY_IOMMU) += pci-nommu.o pci-dma.o obj-$(CONFIG_SWIOTLB) += swiotlb.o obj-$(CONFIG_KPROBES) += kprobes.o +obj-$(CONFIG_X86_PM_TIMER) += pmtimer.o obj-$(CONFIG_MODULES) += module.o diff --git a/arch/x86_64/kernel/pmtimer.c b/arch/x86_64/kernel/pmtimer.c new file mode 100644 index 00000000000..feb5f108dd2 --- /dev/null +++ b/arch/x86_64/kernel/pmtimer.c @@ -0,0 +1,101 @@ +/* Ported over from i386 by AK, original copyright was: + * + * (C) Dominik Brodowski 2003 + * + * Driver to use the Power Management Timer (PMTMR) available in some + * southbridges as primary timing source for the Linux kernel. + * + * Based on parts of linux/drivers/acpi/hardware/hwtimer.c, timer_pit.c, + * timer_hpet.c, and on Arjan van de Ven's implementation for 2.4. + * + * This file is licensed under the GPL v2. + * + * Dropped all the hardware bug workarounds for now. Hopefully they + * are not needed on 64bit chipsets. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* The I/O port the PMTMR resides at. + * The location is detected during setup_arch(), + * in arch/i386/kernel/acpi/boot.c */ +u32 pmtmr_ioport; + +/* value of the Power timer at last timer interrupt */ +static u32 offset_delay; +static u32 last_pmtmr_tick; + +#define ACPI_PM_MASK 0xFFFFFF /* limit it to 24 bits */ + +static inline u32 cyc2us(u32 cycles) +{ + /* The Power Management Timer ticks at 3.579545 ticks per microsecond. + * 1 / PM_TIMER_FREQUENCY == 0.27936511 =~ 286/1024 [error: 0.024%] + * + * Even with HZ = 100, delta is at maximum 35796 ticks, so it can + * easily be multiplied with 286 (=0x11E) without having to fear + * u32 overflows. + */ + cycles *= 286; + return (cycles >> 10); +} + +int pmtimer_mark_offset(void) +{ + static int first_run = 1; + unsigned long tsc; + u32 lost; + + u32 tick = inl(pmtmr_ioport); + u32 delta; + + delta = cyc2us((tick - last_pmtmr_tick) & ACPI_PM_MASK); + + last_pmtmr_tick = tick; + monotonic_base += delta * NSEC_PER_USEC; + + delta += offset_delay; + + lost = delta / (USEC_PER_SEC / HZ); + offset_delay = delta % (USEC_PER_SEC / HZ); + + rdtscll(tsc); + vxtime.last_tsc = tsc - offset_delay * cpu_khz; + + /* don't calculate delay for first run, + or if we've got less then a tick */ + if (first_run || (lost < 1)) { + first_run = 0; + offset_delay = 0; + } + + return lost - 1; +} + +unsigned int do_gettimeoffset_pm(void) +{ + u32 now, offset, delta = 0; + + offset = last_pmtmr_tick; + now = inl(pmtmr_ioport); + delta = (now - offset) & ACPI_PM_MASK; + + return offset_delay + cyc2us(delta); +} + + +static int __init nopmtimer_setup(char *s) +{ + pmtmr_ioport = 0; + return 0; +} + +__setup("nopmtimer", nopmtimer_setup); diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 0e3b60e1ac5..735b6767c8e 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include /* for PM timer frequency */ #include #include #include @@ -396,6 +398,10 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) (offset - vxtime.last)*(NSEC_PER_SEC/HZ) / hpet_tick; vxtime.last = offset; +#ifdef CONFIG_X86_PM_TIMER + } else if (vxtime.mode == VXTIME_PMTMR) { + lost = pmtimer_mark_offset(); +#endif } else { offset = (((tsc - vxtime.last_tsc) * vxtime.tsc_quot) >> 32) - (USEC_PER_SEC / HZ); @@ -898,6 +904,13 @@ void __init time_init(void) hpet_period; cpu_khz = hpet_calibrate_tsc(); timename = "HPET"; +#ifdef CONFIG_X86_PM_TIMER + } else if (pmtmr_ioport) { + vxtime_hz = PM_TIMER_FREQUENCY; + timename = "PM"; + pit_init(); + cpu_khz = pit_calibrate_tsc(); +#endif } else { pit_init(); cpu_khz = pit_calibrate_tsc(); @@ -922,6 +935,27 @@ void __init time_init(void) #endif } +/* + * Make an educated guess if the TSC is trustworthy and synchronized + * over all CPUs. + */ +static __init int unsynchronized_tsc(void) +{ +#ifdef CONFIG_SMP + if (oem_force_hpet_timer()) + return 1; + /* Intel systems are normally all synchronized. Exceptions + are handled in the OEM check above. */ + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) + return 0; + /* All in a single socket - should be synchronized */ + if (cpus_weight(cpu_core_map[0]) == num_online_cpus()) + return 0; +#endif + /* Assume multi socket systems are not synchronized */ + return num_online_cpus() > 1; +} + /* * Decide after all CPUs are booted what mode gettimeofday should use. */ @@ -929,29 +963,23 @@ void __init time_init_gtod(void) { char *timetype; - /* - * AMD systems with more than one CPU don't have fully synchronized - * TSCs. Always use HPET gettimeofday for these, although it is slower. - * Intel SMP systems usually have synchronized TSCs, so use always - * the TSC. - * - * Exceptions: - * IBM Summit2 checked by oem_force_hpet_timer(). - * AMD dual core may also not need HPET. Check me. - * - * Can be turned off with "notsc". - */ - if (num_online_cpus() > 1 && - boot_cpu_data.x86_vendor == X86_VENDOR_AMD) - notsc = 1; - /* Some systems will want to disable TSC and use HPET. */ - if (oem_force_hpet_timer()) + if (unsynchronized_tsc()) notsc = 1; if (vxtime.hpet_address && notsc) { timetype = "HPET"; vxtime.last = hpet_readl(HPET_T0_CMP) - hpet_tick; vxtime.mode = VXTIME_HPET; do_gettimeoffset = do_gettimeoffset_hpet; +#ifdef CONFIG_X86_PM_TIMER + /* Using PM for gettimeofday is quite slow, but we have no other + choice because the TSC is too unreliable on some systems. */ + } else if (pmtmr_ioport && !vxtime.hpet_address && notsc) { + timetype = "PM"; + do_gettimeoffset = do_gettimeoffset_pm; + vxtime.mode = VXTIME_PMTMR; + sysctl_vsyscall = 0; + printk(KERN_INFO "Disabling vsyscall due to use of PM timer\n"); +#endif } else { timetype = vxtime.hpet_address ? "HPET/TSC" : "PIT/TSC"; vxtime.mode = VXTIME_TSC; diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c index b4b8dc59663..1a7541435ef 100644 --- a/arch/x86_64/kernel/vsyscall.c +++ b/arch/x86_64/kernel/vsyscall.c @@ -65,7 +65,7 @@ static force_inline void do_vgettimeofday(struct timeval * tv) usec = (__xtime.tv_nsec / 1000) + (__jiffies - __wall_jiffies) * (1000000 / HZ); - if (__vxtime.mode == VXTIME_TSC) { + if (__vxtime.mode != VXTIME_HPET) { sync_core(); rdtscll(t); if (t < __vxtime.last_tsc) @@ -217,7 +217,6 @@ static int __init vsyscall_init(void) BUG_ON((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime)); BUG_ON((VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE))); map_vsyscall(); - sysctl_vsyscall = 1; register_sysctl_table(kernel_root_table2, 0); return 0; } diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h index d0f8f8b4c39..f2f073642d6 100644 --- a/include/asm-x86_64/proto.h +++ b/include/asm-x86_64/proto.h @@ -30,6 +30,11 @@ extern void ia32_syscall(void); extern void iommu_hole_init(void); extern void time_init_gtod(void); +extern int pmtimer_mark_offset(void); +extern unsigned int do_gettimeoffset_pm(void); +extern u32 pmtmr_ioport; +extern unsigned long long monotonic_base; +extern int sysctl_vsyscall; extern void do_softirq_thunk(void); diff --git a/include/asm-x86_64/vsyscall.h b/include/asm-x86_64/vsyscall.h index b0c8d433990..2872da23fc7 100644 --- a/include/asm-x86_64/vsyscall.h +++ b/include/asm-x86_64/vsyscall.h @@ -25,6 +25,7 @@ enum vsyscall_num { #define VXTIME_TSC 1 #define VXTIME_HPET 2 +#define VXTIME_PMTMR 3 struct vxtime_data { long hpet_address; /* HPET base address */ @@ -54,6 +55,8 @@ extern struct timezone sys_tz; extern int sysctl_vsyscall; extern seqlock_t xtime_lock; +extern int sysctl_vsyscall; + #define ARCH_HAVE_XTIME_LOCK 1 #endif /* __KERNEL__ */ -- cgit v1.2.3 From d1099e8a18960693c04507bdd7b9403db70bfd97 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 16 May 2005 21:53:29 -0700 Subject: [PATCH] x86_64: check if ptrace RIP is canonical This works around an AMD Erratum. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/ptrace.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c index e26e86bb56f..892212161aa 100644 --- a/arch/x86_64/kernel/ptrace.c +++ b/arch/x86_64/kernel/ptrace.c @@ -277,6 +277,11 @@ static int putreg(struct task_struct *child, return -EIO; value &= 0xffff; break; + case offsetof(struct user_regs_struct, rip): + /* Check if the new RIP address is canonical */ + if (value >= TASK_SIZE) + return -EIO; + break; } put_stack_long(child, regno - sizeof(struct pt_regs), value); return 0; -- cgit v1.2.3 From f6b8d4778c04148729cc0b0dcd335a4411c44276 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 16 May 2005 21:53:30 -0700 Subject: [PATCH] x86_64: Fix canonical checking for segment registers in ptrace Allowed user programs to set a non canonical segment base, which would cause oopses in the kernel later. Credit-to: Alexander Nyberg For identifying and reporting this bug. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/ptrace.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c index 892212161aa..60dc9b98951 100644 --- a/arch/x86_64/kernel/ptrace.c +++ b/arch/x86_64/kernel/ptrace.c @@ -257,13 +257,13 @@ static int putreg(struct task_struct *child, value &= 0xffff; return 0; case offsetof(struct user_regs_struct,fs_base): - if (!((value >> 48) == 0 || (value >> 48) == 0xffff)) - return -EIO; + if (value >= TASK_SIZE) + return -EIO; child->thread.fs = value; return 0; case offsetof(struct user_regs_struct,gs_base): - if (!((value >> 48) == 0 || (value >> 48) == 0xffff)) - return -EIO; + if (value >= TASK_SIZE) + return -EIO; child->thread.gs = value; return 0; case offsetof(struct user_regs_struct, eflags): -- cgit v1.2.3 From 3b9ba4d5e23fcab24dd4d2e46dce11f5863869b4 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 16 May 2005 21:53:31 -0700 Subject: [PATCH] x86_64: When checking vmalloc mappings don't use pte_page The PTEs can point to ioremap mappings too, and these are often outside mem_map. The NUMA hash page lookup functions cannot handle out of bounds accesses properly. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/mm/fault.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c index e0330921676..5d6b2114cc9 100644 --- a/arch/x86_64/mm/fault.c +++ b/arch/x86_64/mm/fault.c @@ -234,6 +234,8 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, /* * Handle a fault on the vmalloc or module mapping area + * + * This assumes no large pages in there. */ static int vmalloc_fault(unsigned long address) { @@ -272,7 +274,10 @@ static int vmalloc_fault(unsigned long address) if (!pte_present(*pte_ref)) return -1; pte = pte_offset_kernel(pmd, address); - if (!pte_present(*pte) || pte_page(*pte) != pte_page(*pte_ref)) + /* Don't use pte_page here, because the mappings can point + outside mem_map, and the NUMA hash lookup cannot handle + that. */ + if (!pte_present(*pte) || pte_pfn(*pte) != pte_pfn(*pte_ref)) BUG(); __flush_tlb_all(); return 0; @@ -346,7 +351,9 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) * protection error (error_code & 1) == 0. */ if (unlikely(address >= TASK_SIZE)) { - if (!(error_code & 5)) { + if (!(error_code & 5) && + ((address >= VMALLOC_START && address < VMALLOC_END) || + (address >= MODULES_VADDR && address < MODULES_END))) { if (vmalloc_fault(address) < 0) goto bad_area_nosemaphore; return; -- cgit v1.2.3 From 376ec33fcb246fdd7de1696d33739a0fd36f6537 Mon Sep 17 00:00:00 2001 From: Suresh Siddha Date: Mon, 16 May 2005 21:53:32 -0700 Subject: [PATCH] x86_64: Fix OEM hpet check Use bitmap_zero instead of bitmap_empty to initialise cpu mask This makes it actually run reliable instead of relying on stack state. Signed-off-by: Suresh Siddha Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/apic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index 7e13545748e..7f0b44e4a6e 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c @@ -925,7 +925,7 @@ __init int oem_force_hpet_timer(void) unsigned id; DECLARE_BITMAP(clustermap, NUM_APIC_CLUSTERS); - bitmap_empty(clustermap, NUM_APIC_CLUSTERS); + bitmap_zero(clustermap, NUM_APIC_CLUSTERS); for (i = 0; i < NR_CPUS; i++) { id = bios_cpu_apicid[i]; -- cgit v1.2.3 From f3c5f5e7eeaf7c68ecc1d37200cd1ade0b3da7b9 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 16 May 2005 21:53:33 -0700 Subject: [PATCH] x86_64: Make vsyscall.c compile without CONFIG_SYSCTL Originally from Matt Tolentino Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/vsyscall.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c index 1a7541435ef..2e573442594 100644 --- a/arch/x86_64/kernel/vsyscall.c +++ b/arch/x86_64/kernel/vsyscall.c @@ -217,7 +217,9 @@ static int __init vsyscall_init(void) BUG_ON((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime)); BUG_ON((VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE))); map_vsyscall(); +#ifdef CONFIG_SYSCTL register_sysctl_table(kernel_root_table2, 0); +#endif return 0; } -- cgit v1.2.3 From 751521149a05e308d863d01ced61080ce1a2ec99 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 16 May 2005 21:53:34 -0700 Subject: [PATCH] x86_64: Collected NMI watchdog fixes. Collected NMI watchdog fixes. - Fix call of check_nmi_watchdog - Remove earlier move of check_nmi_watchdog to later. It does not fix the race it was supposed to fix fully. - Remove unused P6 definitions - Add support for performance counter based watchdog on P4 systems. This allows to run it only once per second, which saves some CPU time. Previously it would run at 1000Hz, which was too much. Code ported from i386 Make this the default on Intel systems. - Use check_nmi_watchdog with local APIC based nmi - Fix race in touch_nmi_watchdog - Fix bug that caused incorrect performance counters to be programmed in a few cases on K8. - Remove useless check for local APIC - Use local_t and per_cpu variables for per CPU data. - Keep other CPUs busy during check_nmi_watchdog to make sure they really tick when in lapic mode. - Only check CPUs that are actually online. - Various other fixes. - Fix fallback path when MSRs are unimplemented Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/apic.c | 3 +- arch/x86_64/kernel/nmi.c | 250 +++++++++++++++++++++++++++++-------------- arch/x86_64/kernel/smpboot.c | 3 + include/asm-x86_64/nmi.h | 2 + 4 files changed, 179 insertions(+), 79 deletions(-) diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index 7f0b44e4a6e..f8e6cc4fecd 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c @@ -33,6 +33,7 @@ #include #include #include +#include int apic_verbosity; @@ -1056,7 +1057,7 @@ int __init APIC_init_uniprocessor (void) nr_ioapics = 0; #endif setup_boot_APIC_clock(); - + check_nmi_watchdog(); return 0; } diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c index ec13eb97e8e..31c0f2e6ac9 100644 --- a/arch/x86_64/kernel/nmi.c +++ b/arch/x86_64/kernel/nmi.c @@ -33,6 +33,7 @@ #include #include #include +#include /* * lapic_nmi_owner tracks the ownership of the lapic NMI hardware: @@ -59,7 +60,8 @@ int panic_on_timeout; unsigned int nmi_watchdog = NMI_DEFAULT; static unsigned int nmi_hz = HZ; -unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */ +static unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */ +static unsigned int nmi_p4_cccr_val; /* Note that these events don't tick when the CPU idles. This means the frequency varies with CPU load. */ @@ -71,67 +73,87 @@ unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */ #define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING 0x76 #define K7_NMI_EVENT K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING -#define P6_EVNTSEL0_ENABLE (1 << 22) -#define P6_EVNTSEL_INT (1 << 20) -#define P6_EVNTSEL_OS (1 << 17) -#define P6_EVNTSEL_USR (1 << 16) -#define P6_EVENT_CPU_CLOCKS_NOT_HALTED 0x79 -#define P6_NMI_EVENT P6_EVENT_CPU_CLOCKS_NOT_HALTED +#define MSR_P4_MISC_ENABLE 0x1A0 +#define MSR_P4_MISC_ENABLE_PERF_AVAIL (1<<7) +#define MSR_P4_MISC_ENABLE_PEBS_UNAVAIL (1<<12) +#define MSR_P4_PERFCTR0 0x300 +#define MSR_P4_CCCR0 0x360 +#define P4_ESCR_EVENT_SELECT(N) ((N)<<25) +#define P4_ESCR_OS (1<<3) +#define P4_ESCR_USR (1<<2) +#define P4_CCCR_OVF_PMI0 (1<<26) +#define P4_CCCR_OVF_PMI1 (1<<27) +#define P4_CCCR_THRESHOLD(N) ((N)<<20) +#define P4_CCCR_COMPLEMENT (1<<19) +#define P4_CCCR_COMPARE (1<<18) +#define P4_CCCR_REQUIRED (3<<16) +#define P4_CCCR_ESCR_SELECT(N) ((N)<<13) +#define P4_CCCR_ENABLE (1<<12) +/* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter + CRU_ESCR0 (with any non-null event selector) through a complemented + max threshold. [IA32-Vol3, Section 14.9.9] */ +#define MSR_P4_IQ_COUNTER0 0x30C +#define P4_NMI_CRU_ESCR0 (P4_ESCR_EVENT_SELECT(0x3F)|P4_ESCR_OS|P4_ESCR_USR) +#define P4_NMI_IQ_CCCR0 \ + (P4_CCCR_OVF_PMI0|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT| \ + P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE) + +static __init inline int nmi_known_cpu(void) +{ + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + return boot_cpu_data.x86 == 15; + case X86_VENDOR_INTEL: + return boot_cpu_data.x86 == 15; + } + return 0; +} /* Run after command line and cpu_init init, but before all other checks */ void __init nmi_watchdog_default(void) { if (nmi_watchdog != NMI_DEFAULT) return; - - /* For some reason the IO APIC watchdog doesn't work on the AMD - 8111 chipset. For now switch to local APIC mode using - perfctr0 there. On Intel CPUs we don't have code to handle - the perfctr and the IO-APIC seems to work, so use that. */ - - if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) { - nmi_watchdog = NMI_LOCAL_APIC; - printk(KERN_INFO - "Using local APIC NMI watchdog using perfctr0\n"); - } else { - printk(KERN_INFO "Using IO APIC NMI watchdog\n"); + if (nmi_known_cpu()) + nmi_watchdog = NMI_LOCAL_APIC; + else nmi_watchdog = NMI_IO_APIC; - } } -/* Why is there no CPUID flag for this? */ -static __init int cpu_has_lapic(void) +#ifdef CONFIG_SMP +/* The performance counters used by NMI_LOCAL_APIC don't trigger when + * the CPU is idle. To make sure the NMI watchdog really ticks on all + * CPUs during the test make them busy. + */ +static __init void nmi_cpu_busy(void *data) { - switch (boot_cpu_data.x86_vendor) { - case X86_VENDOR_INTEL: - case X86_VENDOR_AMD: - return boot_cpu_data.x86 >= 6; - /* .... add more cpus here or find a different way to figure this out. */ - default: - return 0; - } + volatile int *endflag = data; + local_irq_enable(); + /* Intentionally don't use cpu_relax here. This is + to make sure that the performance counter really ticks, + even if there is a simulator or similar that catches the + pause instruction. On a real HT machine this is fine because + all other CPUs are busy with "useless" delay loops and don't + care if they get somewhat less cycles. */ + while (*endflag == 0) + barrier(); } +#endif -static int __init check_nmi_watchdog (void) +int __init check_nmi_watchdog (void) { + volatile int endflag = 0; int *counts; int cpu; - if (nmi_watchdog == NMI_NONE) - return 0; + counts = kmalloc(NR_CPUS * sizeof(int), GFP_KERNEL); + if (!counts) + return -1; - if (nmi_watchdog == NMI_LOCAL_APIC && !cpu_has_lapic()) { - nmi_watchdog = NMI_NONE; - return -1; - } + printk(KERN_INFO "testing NMI watchdog ... "); - counts = kmalloc(NR_CPUS * sizeof(int),GFP_KERNEL); - if (!counts) { - nmi_watchdog = NMI_NONE; - return 0; - } - - printk(KERN_INFO "Testing NMI watchdog ... "); + if (nmi_watchdog == NMI_LOCAL_APIC) + smp_call_function(nmi_cpu_busy, (void *)&endflag, 0, 0); for (cpu = 0; cpu < NR_CPUS; cpu++) counts[cpu] = cpu_pda[cpu].__nmi_count; @@ -139,16 +161,22 @@ static int __init check_nmi_watchdog (void) mdelay((10*1000)/nmi_hz); // wait 10 ticks for (cpu = 0; cpu < NR_CPUS; cpu++) { + if (!cpu_online(cpu)) + continue; if (cpu_pda[cpu].__nmi_count - counts[cpu] <= 5) { - printk("CPU#%d: NMI appears to be stuck (%d)!\n", + endflag = 1; + printk("CPU#%d: NMI appears to be stuck (%d->%d)!\n", cpu, + counts[cpu], cpu_pda[cpu].__nmi_count); nmi_active = 0; lapic_nmi_owner &= ~LAPIC_NMI_WATCHDOG; + nmi_perfctr_msr = 0; kfree(counts); return -1; } } + endflag = 1; printk("OK.\n"); /* now that we know it works we can reduce NMI frequency to @@ -159,8 +187,6 @@ static int __init check_nmi_watchdog (void) kfree(counts); return 0; } -/* Have this called later during boot so counters are updating */ -late_initcall(check_nmi_watchdog); int __init setup_nmi_watchdog(char *str) { @@ -178,7 +204,7 @@ int __init setup_nmi_watchdog(char *str) if (nmi >= NMI_INVALID) return 0; - nmi_watchdog = nmi; + nmi_watchdog = nmi; return 1; } @@ -193,7 +219,10 @@ static void disable_lapic_nmi_watchdog(void) wrmsr(MSR_K7_EVNTSEL0, 0, 0); break; case X86_VENDOR_INTEL: - wrmsr(MSR_IA32_EVNTSEL0, 0, 0); + if (boot_cpu_data.x86 == 15) { + wrmsr(MSR_P4_IQ_CCCR0, 0, 0); + wrmsr(MSR_P4_CRU_ESCR0, 0, 0); + } break; } nmi_active = -1; @@ -261,7 +290,7 @@ void enable_timer_nmi_watchdog(void) static int nmi_pm_active; /* nmi_active before suspend */ -static int lapic_nmi_suspend(struct sys_device *dev, pm_message_t state) +static int lapic_nmi_suspend(struct sys_device *dev, u32 state) { nmi_pm_active = nmi_active; disable_lapic_nmi_watchdog(); @@ -308,22 +337,27 @@ late_initcall(init_lapic_nmi_sysfs); * Original code written by Keith Owens. */ +static void clear_msr_range(unsigned int base, unsigned int n) +{ + unsigned int i; + + for(i = 0; i < n; ++i) + wrmsr(base+i, 0, 0); +} + static void setup_k7_watchdog(void) { int i; unsigned int evntsel; - /* No check, so can start with slow frequency */ - nmi_hz = 1; - - /* XXX should check these in EFER */ - nmi_perfctr_msr = MSR_K7_PERFCTR0; for(i = 0; i < 4; ++i) { /* Simulator may not support it */ - if (checking_wrmsrl(MSR_K7_EVNTSEL0+i, 0UL)) + if (checking_wrmsrl(MSR_K7_EVNTSEL0+i, 0UL)) { + nmi_perfctr_msr = 0; return; + } wrmsrl(MSR_K7_PERFCTR0+i, 0UL); } @@ -333,12 +367,54 @@ static void setup_k7_watchdog(void) | K7_NMI_EVENT; wrmsr(MSR_K7_EVNTSEL0, evntsel, 0); - wrmsrl(MSR_K7_PERFCTR0, -((u64)cpu_khz*1000) / nmi_hz); + wrmsr(MSR_K7_PERFCTR0, -(cpu_khz/nmi_hz*1000), -1); apic_write(APIC_LVTPC, APIC_DM_NMI); evntsel |= K7_EVNTSEL_ENABLE; wrmsr(MSR_K7_EVNTSEL0, evntsel, 0); } + +static int setup_p4_watchdog(void) +{ + unsigned int misc_enable, dummy; + + rdmsr(MSR_P4_MISC_ENABLE, misc_enable, dummy); + if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL)) + return 0; + + nmi_perfctr_msr = MSR_P4_IQ_COUNTER0; + nmi_p4_cccr_val = P4_NMI_IQ_CCCR0; +#ifdef CONFIG_SMP + if (smp_num_siblings == 2) + nmi_p4_cccr_val |= P4_CCCR_OVF_PMI1; +#endif + + if (!(misc_enable & MSR_P4_MISC_ENABLE_PEBS_UNAVAIL)) + clear_msr_range(0x3F1, 2); + /* MSR 0x3F0 seems to have a default value of 0xFC00, but current + docs doesn't fully define it, so leave it alone for now. */ + if (boot_cpu_data.x86_model >= 0x3) { + /* MSR_P4_IQ_ESCR0/1 (0x3ba/0x3bb) removed */ + clear_msr_range(0x3A0, 26); + clear_msr_range(0x3BC, 3); + } else { + clear_msr_range(0x3A0, 31); + } + clear_msr_range(0x3C0, 6); + clear_msr_range(0x3C8, 6); + clear_msr_range(0x3E0, 2); + clear_msr_range(MSR_P4_CCCR0, 18); + clear_msr_range(MSR_P4_PERFCTR0, 18); + + wrmsr(MSR_P4_CRU_ESCR0, P4_NMI_CRU_ESCR0, 0); + wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0 & ~P4_CCCR_ENABLE, 0); + Dprintk("setting P4_IQ_COUNTER0 to 0x%08lx\n", -(cpu_khz/nmi_hz*1000)); + wrmsr(MSR_P4_IQ_COUNTER0, -(cpu_khz/nmi_hz*1000), -1); + apic_write(APIC_LVTPC, APIC_DM_NMI); + wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0); + return 1; +} + void setup_apic_nmi_watchdog(void) { switch (boot_cpu_data.x86_vendor) { @@ -349,6 +425,13 @@ void setup_apic_nmi_watchdog(void) return; setup_k7_watchdog(); break; + case X86_VENDOR_INTEL: + if (boot_cpu_data.x86 != 15) + return; + if (!setup_p4_watchdog()) + return; + break; + default: return; } @@ -363,56 +446,67 @@ void setup_apic_nmi_watchdog(void) * * as these watchdog NMI IRQs are generated on every CPU, we only * have to check the current processor. - * - * since NMIs don't listen to _any_ locks, we have to be extremely - * careful not to rely on unsafe variables. The printk might lock - * up though, so we have to break up any console locks first ... - * [when there will be more tty-related locks, break them up - * here too!] */ -static unsigned int - last_irq_sums [NR_CPUS], - alert_counter [NR_CPUS]; +static DEFINE_PER_CPU(unsigned, last_irq_sum); +static DEFINE_PER_CPU(local_t, alert_counter); +static DEFINE_PER_CPU(int, nmi_touch); void touch_nmi_watchdog (void) { int i; /* - * Just reset the alert counters, (other CPUs might be - * spinning on locks we hold): + * Tell other CPUs to reset their alert counters. We cannot + * do it ourselves because the alert count increase is not + * atomic. */ for (i = 0; i < NR_CPUS; i++) - alert_counter[i] = 0; + per_cpu(nmi_touch, i) = 1; } void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason) { - int sum, cpu; + int sum; + int touched = 0; - cpu = safe_smp_processor_id(); sum = read_pda(apic_timer_irqs); - if (last_irq_sums[cpu] == sum) { + if (__get_cpu_var(nmi_touch)) { + __get_cpu_var(nmi_touch) = 0; + touched = 1; + } + if (!touched && __get_cpu_var(last_irq_sum) == sum) { /* * Ayiee, looks like this CPU is stuck ... * wait a few IRQs (5 seconds) before doing the oops ... */ - alert_counter[cpu]++; - if (alert_counter[cpu] == 5*nmi_hz) { + local_inc(&__get_cpu_var(alert_counter)); + if (local_read(&__get_cpu_var(alert_counter)) == 5*nmi_hz) { if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) { - alert_counter[cpu] = 0; + local_set(&__get_cpu_var(alert_counter), 0); return; } die_nmi("NMI Watchdog detected LOCKUP on CPU%d", regs); } } else { - last_irq_sums[cpu] = sum; - alert_counter[cpu] = 0; + __get_cpu_var(last_irq_sum) = sum; + local_set(&__get_cpu_var(alert_counter), 0); } - if (nmi_perfctr_msr) + if (nmi_perfctr_msr) { + if (nmi_perfctr_msr == MSR_P4_IQ_COUNTER0) { + /* + * P4 quirks: + * - An overflown perfctr will assert its interrupt + * until the OVF flag in its CCCR is cleared. + * - LVTPC is masked on interrupt and must be + * unmasked by the LVTPC handler. + */ + wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0); + apic_write(APIC_LVTPC, APIC_DM_NMI); + } wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1); + } } static int dummy_nmi_callback(struct pt_regs * regs, int cpu) diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index 17efc40baa3..d00e494c1a3 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -56,6 +56,7 @@ #include #include #include +#include /* Change for real CPU hotplug. Note other files need to be fixed first too. */ @@ -1030,4 +1031,6 @@ void __cpuinit smp_cpus_done(unsigned int max_cpus) detect_siblings(); time_init_gtod(); + + check_nmi_watchdog(); } diff --git a/include/asm-x86_64/nmi.h b/include/asm-x86_64/nmi.h index 21d56b086b9..d3abfc6a8fd 100644 --- a/include/asm-x86_64/nmi.h +++ b/include/asm-x86_64/nmi.h @@ -53,5 +53,7 @@ extern void die_nmi(char *str, struct pt_regs *regs); extern int panic_on_timeout; extern int unknown_nmi_panic; + +extern int check_nmi_watchdog(void); #endif /* ASM_NMI_H */ -- cgit v1.2.3 From 18a2b6471277c9ffbaa14a0c87a11a075eb354bd Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 16 May 2005 21:53:35 -0700 Subject: [PATCH] x86_64: Don't assume BSP has ID 0 in new smp bootup This patch removes the assumption that LAPIC entries contain the BSP as its first entry. This is a slight improvement to the temporary fix submitted by Suresh Siddha. - Removes assumption that LAPIC entries contain BSP first. - Builds x86_acpiid_to_apicid[] and bios_cpu_apicid[] properly with BSP as first entry. - Made maxcpus=1 boot on these systems. Since the parsing earlier in arch/x86_64/kernel/mpparse.c stopped after maxcpus entries, other entries were not processed, this causes kernel not to boot on these systems. TBD: x86_acpiid_to_apicid and bios_cpu_apicid[] seem to be exactly the same. This could be removed, but might need more work to cleanup. Signed-off-by: Ashok Raj Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/mpparse.c | 20 ++++++++++++++------ arch/x86_64/kernel/smpboot.c | 2 -- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c index f221231cd0a..f86d9db94bf 100644 --- a/arch/x86_64/kernel/mpparse.c +++ b/arch/x86_64/kernel/mpparse.c @@ -107,6 +107,7 @@ static int __init mpf_checksum(unsigned char *mp, int len) static void __init MP_processor_info (struct mpc_config_processor *m) { int ver; + static int found_bsp=0; if (!(m->mpc_cpuflag & CPU_ENABLED)) return; @@ -126,11 +127,6 @@ static void __init MP_processor_info (struct mpc_config_processor *m) " Processor ignored.\n", NR_CPUS); return; } - if (num_processors >= maxcpus) { - printk(KERN_WARNING "WARNING: maxcpus limit of %i reached." - " Processor ignored.\n", maxcpus); - return; - } num_processors++; @@ -150,7 +146,19 @@ static void __init MP_processor_info (struct mpc_config_processor *m) ver = 0x10; } apic_version[m->mpc_apicid] = ver; - bios_cpu_apicid[num_processors - 1] = m->mpc_apicid; + if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) { + /* + * bios_cpu_apicid is required to have processors listed + * in same order as logical cpu numbers. Hence the first + * entry is BSP, and so on. + */ + bios_cpu_apicid[0] = m->mpc_apicid; + x86_cpu_to_apicid[0] = m->mpc_apicid; + found_bsp = 1; + } else { + bios_cpu_apicid[num_processors - found_bsp] = m->mpc_apicid; + x86_cpu_to_apicid[num_processors - found_bsp] = m->mpc_apicid; + } } static void __init MP_bus_info (struct mpc_config_bus *m) diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index d00e494c1a3..5abdee1e16a 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -645,7 +645,6 @@ static int __cpuinit do_boot_cpu(int cpu, int apicid) printk("failed fork for CPU %d\n", cpu); return PTR_ERR(idle); } - x86_cpu_to_apicid[cpu] = apicid; cpu_pda[cpu].pcurrent = idle; @@ -954,7 +953,6 @@ void __cpuinit smp_prepare_cpus(unsigned int max_cpus) GET_APIC_ID(apic_read(APIC_ID)), boot_cpu_id); /* Or can we switch back to PIC here? */ } - x86_cpu_to_apicid[0] = boot_cpu_id; /* * Now start the IO-APICs -- cgit v1.2.3 From 59db2e6ed080ac385f19b9f4329133d634215bfd Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 16 May 2005 21:53:36 -0700 Subject: [PATCH] x86_64: Update defconfig Update defconfig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/defconfig | 58 ++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig index 9ce51dee30b..569595b74c7 100644 --- a/arch/x86_64/defconfig +++ b/arch/x86_64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.11-bk7 -# Sat Mar 12 23:43:44 2005 +# Linux kernel version: 2.6.12-rc4 +# Fri May 13 06:39:11 2005 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -11,8 +11,6 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_X86_CMPXCHG=y CONFIG_EARLY_PRINTK=y -CONFIG_HPET_TIMER=y -CONFIG_HPET_EMULATE_RTC=y CONFIG_GENERIC_ISA_DMA=y CONFIG_GENERIC_IOMAP=y @@ -22,6 +20,7 @@ CONFIG_GENERIC_IOMAP=y CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -33,7 +32,6 @@ CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=18 # CONFIG_HOTPLUG is not set CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y @@ -43,10 +41,11 @@ CONFIG_IKCONFIG_PROC=y CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SHMEM=y CONFIG_CC_ALIGN_FUNCTIONS=0 CONFIG_CC_ALIGN_LABELS=0 @@ -93,6 +92,9 @@ CONFIG_DISCONTIGMEM=y CONFIG_NUMA=y CONFIG_HAVE_DEC_LOCK=y CONFIG_NR_CPUS=8 +CONFIG_HPET_TIMER=y +CONFIG_X86_PM_TIMER=y +CONFIG_HPET_EMULATE_RTC=y CONFIG_GART_IOMMU=y CONFIG_SWIOTLB=y CONFIG_X86_MCE=y @@ -100,6 +102,7 @@ CONFIG_X86_MCE_INTEL=y CONFIG_SECCOMP=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_ISA_DMA_API=y # # Power management options @@ -129,7 +132,7 @@ CONFIG_ACPI_NUMA=y # CONFIG_ACPI_IBM is not set CONFIG_ACPI_TOSHIBA=y CONFIG_ACPI_BLACKLIST_YEAR=2001 -CONFIG_ACPI_DEBUG=y +# CONFIG_ACPI_DEBUG is not set CONFIG_ACPI_BUS=y CONFIG_ACPI_EC=y CONFIG_ACPI_POWER=y @@ -141,6 +144,7 @@ CONFIG_ACPI_SYSTEM=y # CPU Frequency scaling # CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y # CONFIG_CPU_FREQ_DEBUG is not set CONFIG_CPU_FREQ_STAT=y # CONFIG_CPU_FREQ_STAT_DETAILS is not set @@ -150,7 +154,6 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_TABLE=y # # CPUFreq processor drivers @@ -164,6 +167,7 @@ CONFIG_X86_ACPI_CPUFREQ=y # shared options # CONFIG_X86_ACPI_CPUFREQ_PROC_INTF=y +# CONFIG_X86_SPEEDSTEP_LIB is not set # # Bus options (PCI etc.) @@ -172,19 +176,17 @@ CONFIG_PCI=y CONFIG_PCI_DIRECT=y CONFIG_PCI_MMCONFIG=y CONFIG_UNORDERED_IO=y +# CONFIG_PCIEPORTBUS is not set CONFIG_PCI_MSI=y # CONFIG_PCI_LEGACY_PROC is not set # CONFIG_PCI_NAMES is not set +# CONFIG_PCI_DEBUG is not set # # PCCARD (PCMCIA/CardBus) support # # CONFIG_PCCARD is not set -# -# PC-card bridges -# - # # PCI Hotplug Support # @@ -254,7 +256,7 @@ CONFIG_LBD=y # IO Schedulers # CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y +# CONFIG_IOSCHED_AS is not set CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y # CONFIG_ATA_OVER_ETH is not set @@ -308,7 +310,8 @@ CONFIG_BLK_DEV_AMD74XX=y CONFIG_BLK_DEV_PIIX=y # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_PDC202XX_OLD is not set -# CONFIG_BLK_DEV_PDC202XX_NEW is not set +CONFIG_BLK_DEV_PDC202XX_NEW=y +# CONFIG_PDC202XX_FORCE is not set # CONFIG_BLK_DEV_SVWKS is not set # CONFIG_BLK_DEV_SIIMAGE is not set # CONFIG_BLK_DEV_SIS5513 is not set @@ -353,7 +356,7 @@ CONFIG_BLK_DEV_SD=y # # SCSI low-level drivers # -CONFIG_BLK_DEV_3W_XXXX_RAID=y +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set # CONFIG_SCSI_3W_9XXX is not set # CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AACRAID is not set @@ -384,7 +387,6 @@ CONFIG_SCSI_SATA_VIA=y # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_DMX3191D is not set # CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_IPS is not set @@ -392,7 +394,6 @@ CONFIG_SCSI_SATA_VIA=y # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_IPR is not set -# CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set CONFIG_SCSI_QLA2XXX=y @@ -401,6 +402,7 @@ CONFIG_SCSI_QLA2XXX=y # CONFIG_SCSI_QLA2300 is not set # CONFIG_SCSI_QLA2322 is not set # CONFIG_SCSI_QLA6312 is not set +# CONFIG_SCSI_LPFC is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_DEBUG is not set @@ -437,7 +439,6 @@ CONFIG_NET=y # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK_DEV is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y @@ -502,7 +503,7 @@ CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set +CONFIG_TUN=y # # ARCnet devices @@ -525,8 +526,7 @@ CONFIG_MII=y # CONFIG_HP100 is not set CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set -CONFIG_AMD8111_ETH=y -# CONFIG_AMD8111E_NAPI is not set +# CONFIG_AMD8111_ETH is not set # CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_B44 is not set CONFIG_FORCEDETH=y @@ -536,7 +536,7 @@ CONFIG_FORCEDETH=y # CONFIG_FEALNX is not set # CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set -CONFIG_8139CP=m +CONFIG_8139CP=y CONFIG_8139TOO=y # CONFIG_8139TOO_PIO is not set # CONFIG_8139TOO_TUNE_TWISTER is not set @@ -671,6 +671,7 @@ CONFIG_SERIAL_8250_NR_UARTS=4 # CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -696,6 +697,7 @@ CONFIG_RTC=y # CONFIG_AGP=y CONFIG_AGP_AMD64=y +CONFIG_AGP_INTEL=y # CONFIG_DRM is not set # CONFIG_MWAVE is not set CONFIG_RAW_DRIVER=y @@ -703,7 +705,7 @@ CONFIG_HPET=y # CONFIG_HPET_RTC_IRQ is not set CONFIG_HPET_MMAP=y CONFIG_MAX_RAW_DEVS=256 -CONFIG_HANGCHECK_TIMER=y +# CONFIG_HANGCHECK_TIMER is not set # # TPM devices @@ -786,6 +788,8 @@ CONFIG_SOUND_ICH=y # # USB support # +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y CONFIG_USB=y # CONFIG_USB_DEBUG is not set @@ -797,8 +801,6 @@ CONFIG_USB_DEVICEFS=y # CONFIG_USB_DYNAMIC_MINORS is not set # CONFIG_USB_SUSPEND is not set # CONFIG_USB_OTG is not set -CONFIG_USB_ARCH_HAS_HCD=y -CONFIG_USB_ARCH_HAS_OHCI=y # # USB Host Controller Drivers @@ -826,7 +828,6 @@ CONFIG_USB_PRINTER=y # CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_RW_DETECT is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set # CONFIG_USB_STORAGE_ISD200 is not set @@ -965,7 +966,7 @@ CONFIG_AUTOFS_FS=y # CD-ROM/DVD Filesystems # CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set +CONFIG_JOLIET=y # CONFIG_ZISOFS is not set # CONFIG_UDF_FS is not set @@ -1092,9 +1093,10 @@ CONFIG_OPROFILE=y # # Kernel hacking # +# CONFIG_PRINTK_TIME is not set CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y -# CONFIG_PRINTK_TIME is not set +CONFIG_LOG_BUF_SHIFT=18 # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set -- cgit v1.2.3 From 7a019225c797a1047470accee950d69cfe7c59c5 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 16 May 2005 21:53:37 -0700 Subject: [PATCH] mm/nommu.c: try to fix __vmalloc Linus changed the second argument of __vmalloc from int to unsigned int breaking the compilation for CONFIG_MMU=n configurations (since he only changed vmalloc.c but not nommu.c). Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/nommu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/nommu.c b/mm/nommu.c index b293ec1cc4e..c53e9c8f6b4 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -150,7 +150,8 @@ void vfree(void *addr) kfree(addr); } -void *__vmalloc(unsigned long size, int gfp_mask, pgprot_t prot) +void *__vmalloc(unsigned long size, unsigned int __nocast gfp_mask, + pgprot_t prot) { /* * kmalloc doesn't like __GFP_HIGHMEM for some reason -- cgit v1.2.3 From 53b21689ba567ad437e4d7917dd9da54a8d6fd5c Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 16 May 2005 21:53:38 -0700 Subject: [PATCH] drivers/input/keyboard/atkbd.c: fix off by one errors This patch fixes two possible off by one errors found by the Coverity checker (look at the period[i] and delay[j] in the two first unchanged lines). Signed-off-by: Adrian Bunk Cc: Vojtech Pavlik Cc: Dmitry Torokhov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/input/keyboard/atkbd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index ff66ed4ee2c..79c332f16fc 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -465,8 +465,10 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co if (atkbd->softrepeat) return 0; i = j = 0; - while (i < 32 && period[i] < dev->rep[REP_PERIOD]) i++; - while (j < 4 && delay[j] < dev->rep[REP_DELAY]) j++; + while (i < 31 && period[i] < dev->rep[REP_PERIOD]) + i++; + while (j < 3 && delay[j] < dev->rep[REP_DELAY]) + j++; dev->rep[REP_PERIOD] = period[i]; dev->rep[REP_DELAY] = delay[j]; param[0] = i | (j << 5); -- cgit v1.2.3 From 59afda786a58f2e8f74a48f2af90534d76d5338d Mon Sep 17 00:00:00 2001 From: Horst Hummel Date: Mon, 16 May 2005 21:53:39 -0700 Subject: [PATCH] s390: dasd set online failure dasd driver changes: - The feature check in dasd_generic_online returns an error if the devmap entry for the device is not yet available. Check for the feature after the device has been created. - Do symmetric registration/deregistration of cdev->handler. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/s390/block/dasd.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 02cfe244e06..ceeb3cf64a1 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -7,7 +7,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 * - * $Revision: 1.161 $ + * $Revision: 1.164 $ */ #include @@ -1766,10 +1766,10 @@ dasd_generic_probe (struct ccw_device *cdev, printk(KERN_WARNING "dasd_generic_probe: could not add sysfs entries " "for %s\n", cdev->dev.bus_id); + } else { + cdev->handler = &dasd_int_handler; } - cdev->handler = &dasd_int_handler; - return ret; } @@ -1780,6 +1780,8 @@ dasd_generic_remove (struct ccw_device *cdev) { struct dasd_device *device; + cdev->handler = NULL; + dasd_remove_sysfs_files(cdev); device = dasd_device_from_cdev(cdev); if (IS_ERR(device)) @@ -1810,14 +1812,14 @@ dasd_generic_set_online (struct ccw_device *cdev, struct dasd_device *device; int feature_diag, rc; - feature_diag = dasd_get_feature(cdev, DASD_FEATURE_USEDIAG); - if (feature_diag < 0) - return feature_diag; - device = dasd_create_device(cdev); if (IS_ERR(device)) return PTR_ERR(device); + feature_diag = dasd_get_feature(cdev, DASD_FEATURE_USEDIAG); + if (feature_diag < 0) + return feature_diag; + if (feature_diag) { if (!dasd_diag_discipline_pointer) { printk (KERN_WARNING -- cgit v1.2.3 From ba32311eb73f624a85a5fc2e043cda8e076f86ef Mon Sep 17 00:00:00 2001 From: "McMullan, Jason" Date: Mon, 16 May 2005 21:53:40 -0700 Subject: [PATCH] swapout oops fix Fix OOPS when swapping on a device that doesn't have an unplug_io_fn defined (eg, ATA Over Ethernet) Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/swapfile.c b/mm/swapfile.c index a60e0075d55..da48405cd9a 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -79,7 +79,7 @@ void swap_unplug_io_fn(struct backing_dev_info *unused_bdi, struct page *page) WARN_ON(page_count(page) <= 1); bdi = bdev->bd_inode->i_mapping->backing_dev_info; - bdi->unplug_io_fn(bdi, page); + blk_run_backing_dev(bdi, page); } up_read(&swap_unplug_sem); } -- cgit v1.2.3 From d0856009dbaf8eca2269d4129bb83940c0d95054 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 16 May 2005 21:53:41 -0700 Subject: [PATCH] crypto: fix null encryption/compression null_encrypt() needs to copy the data in case src and dst are disjunct, null_compress() needs to copy the data in any case as far as I can tell. I joined compress/decompress and encrypt/decrypt to avoid duplicating code. Without this patch ESP null_enc packets look like this: IP (tos 0x0, ttl 64, id 23130, offset 0, flags [DF], length: 128) 10.0.0.1 > 10.0.0.2: ESP(spi=0x0f9ca149,seq=0x4) 0x0000: 4500 0080 5a5a 4000 4032 cbef 0a00 0001 E...ZZ@.@2...... 0x0010: 0a00 0002 0f9c a149 0000 0004 0000 0000 .......I........ 0x0020: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0030: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0040: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0x0050: 0000 .. IP (tos 0x0, ttl 64, id 256, offset 0, flags [DF], length: 128) 10.0.0.2 > 10.0.0.1: ESP(spi=0x0e4f7b51,seq=0x2) 0x0000: 4500 0080 0100 4000 4032 254a 0a00 0002 E.....@.@2%J.... 0x0010: 0a00 0001 0e4f 7b51 0000 0002 a8a8 a8a8 .....O{Q........ 0x0020: a8a8 a8a8 a8a8 a8a8 a8a8 a8a8 a8a8 a8a8 ................ 0x0030: a8a8 a8a8 a8a8 a8a8 a8a8 a8a8 a8a8 a8a8 ................ 0x0040: a8a8 a8a8 a8a8 a8a8 a8a8 a8a8 a8a8 a8a8 ................ 0x0050: a8a8 .. Signed-off-by: Patrick McHardy Signed-off-by: Herbert Xu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- crypto/crypto_null.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c index f691d31fa9e..3fcf6e887e8 100644 --- a/crypto/crypto_null.c +++ b/crypto/crypto_null.c @@ -21,6 +21,7 @@ #include #include #include +#include #define NULL_KEY_SIZE 0 #define NULL_BLOCK_SIZE 1 @@ -28,11 +29,13 @@ static int null_compress(void *ctx, const u8 *src, unsigned int slen, u8 *dst, unsigned int *dlen) -{ return 0; } - -static int null_decompress(void *ctx, const u8 *src, unsigned int slen, - u8 *dst, unsigned int *dlen) -{ return 0; } +{ + if (slen > *dlen) + return -EINVAL; + memcpy(dst, src, slen); + *dlen = slen; + return 0; +} static void null_init(void *ctx) { } @@ -47,11 +50,10 @@ static int null_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags) { return 0; } -static void null_encrypt(void *ctx, u8 *dst, const u8 *src) -{ } - -static void null_decrypt(void *ctx, u8 *dst, const u8 *src) -{ } +static void null_crypt(void *ctx, u8 *dst, const u8 *src) +{ + memcpy(dst, src, NULL_BLOCK_SIZE); +} static struct crypto_alg compress_null = { .cra_name = "compress_null", @@ -62,7 +64,7 @@ static struct crypto_alg compress_null = { .cra_list = LIST_HEAD_INIT(compress_null.cra_list), .cra_u = { .compress = { .coa_compress = null_compress, - .coa_decompress = null_decompress } } + .coa_decompress = null_compress } } }; static struct crypto_alg digest_null = { @@ -90,8 +92,8 @@ static struct crypto_alg cipher_null = { .cia_min_keysize = NULL_KEY_SIZE, .cia_max_keysize = NULL_KEY_SIZE, .cia_setkey = null_setkey, - .cia_encrypt = null_encrypt, - .cia_decrypt = null_decrypt } } + .cia_encrypt = null_crypt, + .cia_decrypt = null_crypt } } }; MODULE_ALIAS("compress_null"); -- cgit v1.2.3 From 7baeb6a5ccab2d472679a053e64a63ac423c3a42 Mon Sep 17 00:00:00 2001 From: Peter Osterlund Date: Mon, 16 May 2005 21:53:42 -0700 Subject: [PATCH] CDRW/DVD packet writing data corruption fix I found a bug in the packet writing driver that could cause data corruption. The problem arised if the driver got a write request for a sector in a "zone" it was already working on. In that case it was supposed to queue the write request until it was done processing earlier requests for the same zone, and instead work on some other zone in the mean time. However, if there was no other zone to work on, the driver would initiate two packet_data objects for the same zone, causing unpredictable things to happen. Signed-off-by: Peter Osterlund Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/pktcdvd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 82ccad0a7f1..b9a6b7ad64f 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -914,8 +914,10 @@ static int pkt_handle_queue(struct pktcdvd_device *pd) bio = node->bio; zone = ZONE(bio->bi_sector, pd); list_for_each_entry(p, &pd->cdrw.pkt_active_list, list) { - if (p->sector == zone) + if (p->sector == zone) { + bio = NULL; goto try_next_bio; + } } break; try_next_bio: -- cgit v1.2.3 From 4f167fb491725ca0be9df0d76b4b2dd862cdfe0b Mon Sep 17 00:00:00 2001 From: "Zhang, Yanmin" Date: Mon, 16 May 2005 21:53:43 -0700 Subject: [PATCH] spurious interrupt fix On my IA64 machine, after kernel 2.6.12-rc3 boots, an edge-triggered interrupt (IRQ 46) keeps triggered over and over again. There is no IRQ 46 interrupt action handler. It has lots of impact on performance. Kernel 2.6.10 and its prior versions have no the problem. Basically, kernel 2.6.10 will mask the spurious edge interrupt if the interrupt is triggered for the second time and its status includes IRQ_DISABLE|IRQ_PENDING. Originally, IA64 kernel has its own specific _irq_desc definitions in file arch/ia64/kernel/irq.c. The definition initiates _irq_desc[irq].status to IRQ_DISABLE. Since kernel 2.6.11, it was moved to architecture independent codes, i.e. kernel/irq/handle.c, but kernel/irq/handle.c initiates _irq_desc[irq].status to 0 instead of IRQ_DISABLE. Signed-off-by: Zhang Yanmin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/irq/handle.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 2fb0e46e11f..06b5a632399 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -30,6 +30,7 @@ */ irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = { + .status = IRQ_DISABLED, .handler = &no_irq_type, .lock = SPIN_LOCK_UNLOCKED } -- cgit v1.2.3 From f1fc3990e2ffa14310cae89678c0b4ed1a3f094b Mon Sep 17 00:00:00 2001 From: Petr Vandrovec Date: Mon, 16 May 2005 21:53:44 -0700 Subject: [PATCH] serial_cs device identification fix serial_cs's vendor/device identification got broken by Yum Rayan's change '[PATCH] serial_cs: Reduce stack usage in serial_event()' - it changed buf type from u_short* to char*, breaking device manufacturer & card number retrieval. Due to this my modem stopped from being recognized as special case. Code will work much better if we'll rely on first_tuple's parser instead of doing parse ourselves. Code also looks simpler after change. Signed-off-by: Petr Vandrovec Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/serial/serial_cs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 6eeb48f6a48..0d7b65f93e8 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -661,10 +661,10 @@ void serial_config(dev_link_t * link) /* Is this a multiport card? */ tuple->DesiredTuple = CISTPL_MANFID; if (first_tuple(handle, tuple, parse) == CS_SUCCESS) { - info->manfid = le16_to_cpu(buf[0]); + info->manfid = parse->manfid.manf; for (i = 0; i < MULTI_COUNT; i++) if ((info->manfid == multi_id[i].manfid) && - (le16_to_cpu(buf[1]) == multi_id[i].prodid)) + (parse->manfid.card == multi_id[i].prodid)) break; if (i < MULTI_COUNT) info->multi = multi_id[i].multi; -- cgit v1.2.3 From 631330afdf9d29fe84526653674e8e061389d8f6 Mon Sep 17 00:00:00 2001 From: Dominik Hackl Date: Mon, 16 May 2005 21:53:45 -0700 Subject: [PATCH] fix Philips SAA7130/7134 TV dependency problem Solve a dependency-problem related to the SAA7130/7134 TV-card driver. The driver won't compile with CRC32 disabled, so I added it to the select list. Signed-off-by: Dominik Hackl Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index d3dd4228b72..6c05fddb69a 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -240,6 +240,7 @@ config VIDEO_SAA7134 select VIDEO_BUF select VIDEO_IR select VIDEO_TUNER + select CRC32 ---help--- This is a video4linux driver for Philips SAA7130/7134 based TV cards. -- cgit v1.2.3 From e8f5bdb02ce06925e7fc5916125bdebc533d4299 Mon Sep 17 00:00:00 2001 From: Rik van Riel Date: Mon, 16 May 2005 21:53:46 -0700 Subject: [PATCH] Makefile include path ordering The arch Makefile may override the include path order, which is used by Xen (and UML?) to make sure include/asm-xen is searched before include/asm-i386. The Makefile change to 2.6.12-rc4 made the top Makefile always override the value specified by the arch Makefile. This trivial patch makes the Xen kernel compile again. Signed-off-by: Rik van Riel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index bddcb861b49..1bb028317f2 100644 --- a/Makefile +++ b/Makefile @@ -530,7 +530,7 @@ endif include $(srctree)/arch/$(ARCH)/Makefile # arch Makefile may override CC so keep this after arch Makefile is included -NOSTDINC_FLAGS := -nostdinc -isystem $(shell $(CC) -print-file-name=include) +NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include) CHECKFLAGS += $(NOSTDINC_FLAGS) # warn about C99 declaration after statement -- cgit v1.2.3 From 3c0547ba8b3bbd8b26ae35e33ac17ff51f67f78c Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Mon, 16 May 2005 21:53:47 -0700 Subject: [PATCH] add_preferred_console() build fix Move add_preferred_console out of CONFIG_PRINTK so serial console does the right thing. Signed-off-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/printk.c | 72 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/kernel/printk.c b/kernel/printk.c index 290a07ce2c8..01b58d7d17f 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -160,42 +160,6 @@ static int __init console_setup(char *str) __setup("console=", console_setup); -/** - * add_preferred_console - add a device to the list of preferred consoles. - * - * The last preferred console added will be used for kernel messages - * and stdin/out/err for init. Normally this is used by console_setup - * above to handle user-supplied console arguments; however it can also - * be used by arch-specific code either to override the user or more - * commonly to provide a default console (ie from PROM variables) when - * the user has not supplied one. - */ -int __init add_preferred_console(char *name, int idx, char *options) -{ - struct console_cmdline *c; - int i; - - /* - * See if this tty is not yet registered, and - * if we have a slot free. - */ - for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) - if (strcmp(console_cmdline[i].name, name) == 0 && - console_cmdline[i].index == idx) { - selected_console = i; - return 0; - } - if (i == MAX_CMDLINECONSOLES) - return -E2BIG; - selected_console = i; - c = &console_cmdline[i]; - memcpy(c->name, name, sizeof(c->name)); - c->name[sizeof(c->name) - 1] = 0; - c->options = options; - c->index = idx; - return 0; -} - static int __init log_buf_len_setup(char *str) { unsigned long size = memparse(str, &str); @@ -670,6 +634,42 @@ static void call_console_drivers(unsigned long start, unsigned long end) {} #endif +/** + * add_preferred_console - add a device to the list of preferred consoles. + * + * The last preferred console added will be used for kernel messages + * and stdin/out/err for init. Normally this is used by console_setup + * above to handle user-supplied console arguments; however it can also + * be used by arch-specific code either to override the user or more + * commonly to provide a default console (ie from PROM variables) when + * the user has not supplied one. + */ +int __init add_preferred_console(char *name, int idx, char *options) +{ + struct console_cmdline *c; + int i; + + /* + * See if this tty is not yet registered, and + * if we have a slot free. + */ + for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) + if (strcmp(console_cmdline[i].name, name) == 0 && + console_cmdline[i].index == idx) { + selected_console = i; + return 0; + } + if (i == MAX_CMDLINECONSOLES) + return -E2BIG; + selected_console = i; + c = &console_cmdline[i]; + memcpy(c->name, name, sizeof(c->name)); + c->name[sizeof(c->name) - 1] = 0; + c->options = options; + c->index = idx; + return 0; +} + /** * acquire_console_sem - lock the console system for exclusive use. * -- cgit v1.2.3 From c64610ba585fabb36be78782868277f3d9741a2e Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 16 May 2005 21:53:49 -0700 Subject: [PATCH] block_read_full_page() get_block() error handling fix If block_read_full_page() detects an error when running get_block() it will run SetPageError(), then it will zero out the block in pagecache and will mark the buffer_head uptodate. So at the end of readahead we end up with a non-uptodate pagecache page which is marked PageError. But it has uptodate buffers. The pagefault code will run ClearPageError, will launch readpage a second time and block_read_full_page() will notice the uptodate buffers and will mark the page uptodate as well. We end up with an uptodate, !PageError page full of zeros and the error is lost. (It seems a little odd that filemap_nopage() runs ClearPageError(). I guess all of this adds up to meaning that for each attempted access to the page, the pagefault handler will retry the I/O. Which is good and bad. If the app is ignoring SIGBUS for some reason we could get a lot of back-to-back I/O errors.) Fix it by not marking the pagecache buffer_head as uptodate if the attempt to map that buffer to a disk block failed. Credit-to: Qu Fuping For reporting the bug and identifying its source. Signed-off-by: Qu Fuping Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/buffer.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/buffer.c b/fs/buffer.c index 6f88dcc6d00..7e9e409feaa 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2094,9 +2094,12 @@ int block_read_full_page(struct page *page, get_block_t *get_block) continue; if (!buffer_mapped(bh)) { + int err = 0; + fully_mapped = 0; if (iblock < lblock) { - if (get_block(inode, iblock, bh, 0)) + err = get_block(inode, iblock, bh, 0); + if (err) SetPageError(page); } if (!buffer_mapped(bh)) { @@ -2104,7 +2107,8 @@ int block_read_full_page(struct page *page, get_block_t *get_block) memset(kaddr + i * blocksize, 0, blocksize); flush_dcache_page(page); kunmap_atomic(kaddr, KM_USER0); - set_buffer_uptodate(bh); + if (!err) + set_buffer_uptodate(bh); continue; } /* -- cgit v1.2.3 From b81074800b98ac50b64d4c8d34e8abf0fda5e3d1 Mon Sep 17 00:00:00 2001 From: Kirill Korotaev Date: Mon, 16 May 2005 21:53:50 -0700 Subject: [PATCH] do_swap_page() can map random data if swap read fails There is a bug in do_swap_page(): when swap page happens to be unreadable, page filled with random data is mapped into user address space. The fix is to check for PageUptodate and send SIGBUS in case of error. Signed-Off-By: Kirill Korotaev Signed-Off-By: Alexey Kuznetsov Acked-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memory.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/mm/memory.c b/mm/memory.c index 6bad4c4064e..d209f745db7 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1701,12 +1701,13 @@ static int do_swap_page(struct mm_struct * mm, spin_lock(&mm->page_table_lock); page_table = pte_offset_map(pmd, address); if (unlikely(!pte_same(*page_table, orig_pte))) { - pte_unmap(page_table); - spin_unlock(&mm->page_table_lock); - unlock_page(page); - page_cache_release(page); ret = VM_FAULT_MINOR; - goto out; + goto out_nomap; + } + + if (unlikely(!PageUptodate(page))) { + ret = VM_FAULT_SIGBUS; + goto out_nomap; } /* The page isn't present yet, go ahead with the fault. */ @@ -1741,6 +1742,12 @@ static int do_swap_page(struct mm_struct * mm, spin_unlock(&mm->page_table_lock); out: return ret; +out_nomap: + pte_unmap(page_table); + spin_unlock(&mm->page_table_lock); + unlock_page(page); + page_cache_release(page); + goto out; } /* -- cgit v1.2.3 From 4c443d1b558b21520bd8fd6140b85cee0756becd Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Mon, 16 May 2005 21:53:52 -0700 Subject: [PATCH] selinux: fix avc_alloc_node() oom with no policy loaded This patch should fix the avc_alloc_node() oom condition that Andrew reported when no policy is loaded in SELinux. Prior to this patch, when no policy was loaded, the SELinux "security server" (policy engine) was only returning allowed decisions for the requested permissions for each access check. This caused the cache to thrash when trying to use SELinux for real work with no policy loaded (typically, the no policy loaded state is only for bootstrapping to the point where we can load an initial policy). This patch changes the SELinux security server to return the complete allowed access vector at once, and then to reset the cache after the initial policy load to flush the initial cache state created during bootstrapping. Signed-off-by: Stephen Smalley Signed-off-by: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- security/selinux/ss/services.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 5a820cf88c9..8449d667b06 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -476,8 +476,8 @@ int security_compute_av(u32 ssid, int rc = 0; if (!ss_initialized) { - avd->allowed = requested; - avd->decided = requested; + avd->allowed = 0xffffffff; + avd->decided = 0xffffffff; avd->auditallow = 0; avd->auditdeny = 0xffffffff; avd->seqno = latest_granting; @@ -1196,9 +1196,11 @@ int security_load_policy(void *data, size_t len) } policydb_loaded_version = policydb.policyvers; ss_initialized = 1; - + seqno = ++latest_granting; LOAD_UNLOCK; selinux_complete_init(); + avc_ss_reset(seqno); + selnl_notify_policyload(seqno); return 0; } -- cgit v1.2.3 From 3407c0fec3456325826c31792e77a80a6dec0e20 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Mon, 16 May 2005 21:53:53 -0700 Subject: [PATCH] mips: add resource management to pmu This patch had added resource management to vr41xx's pmu. Signed-off-by: Yoichi Yuasa Cc: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/mips/vr41xx/common/pmu.c | 55 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/arch/mips/vr41xx/common/pmu.c b/arch/mips/vr41xx/common/pmu.c index c5f1043de93..53166f3598b 100644 --- a/arch/mips/vr41xx/common/pmu.c +++ b/arch/mips/vr41xx/common/pmu.c @@ -1,7 +1,7 @@ /* * pmu.c, Power Management Unit routines for NEC VR4100 series. * - * Copyright (C) 2003-2004 Yoichi Yuasa + * Copyright (C) 2003-2005 Yoichi Yuasa * * 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 @@ -17,7 +17,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include +#include #include #include #include @@ -27,20 +29,31 @@ #include #include -#define PMUCNT2REG KSEG1ADDR(0x0f0000c6) +#define PMU_TYPE1_BASE 0x0b0000a0UL +#define PMU_TYPE1_SIZE 0x0eUL + +#define PMU_TYPE2_BASE 0x0f0000c0UL +#define PMU_TYPE2_SIZE 0x10UL + +#define PMUCNT2REG 0x06 #define SOFTRST 0x0010 +static void __iomem *pmu_base; + +#define pmu_read(offset) readw(pmu_base + (offset)) +#define pmu_write(offset, value) writew((value), pmu_base + (offset)) + static inline void software_reset(void) { - uint16_t val; + uint16_t pmucnt2; switch (current_cpu_data.cputype) { case CPU_VR4122: case CPU_VR4131: case CPU_VR4133: - val = readw(PMUCNT2REG); - val |= SOFTRST; - writew(val, PMUCNT2REG); + pmucnt2 = pmu_read(PMUCNT2REG); + pmucnt2 |= SOFTRST; + pmu_write(PMUCNT2REG, pmucnt2); break; default: break; @@ -71,6 +84,34 @@ static void vr41xx_power_off(void) static int __init vr41xx_pmu_init(void) { + unsigned long start, size; + + switch (current_cpu_data.cputype) { + case CPU_VR4111: + case CPU_VR4121: + start = PMU_TYPE1_BASE; + size = PMU_TYPE1_SIZE; + break; + case CPU_VR4122: + case CPU_VR4131: + case CPU_VR4133: + start = PMU_TYPE2_BASE; + size = PMU_TYPE2_SIZE; + break; + default: + printk("Unexpected CPU of NEC VR4100 series\n"); + return -ENODEV; + } + + if (request_mem_region(start, size, "PMU") == NULL) + return -EBUSY; + + pmu_base = ioremap(start, size); + if (pmu_base == NULL) { + release_mem_region(start, size); + return -EBUSY; + } + _machine_restart = vr41xx_restart; _machine_halt = vr41xx_halt; _machine_power_off = vr41xx_power_off; @@ -78,4 +119,4 @@ static int __init vr41xx_pmu_init(void) return 0; } -early_initcall(vr41xx_pmu_init); +core_initcall(vr41xx_pmu_init); -- cgit v1.2.3 From 24d568ed1b97cb93c2a917cd90296655a8b661a6 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Mon, 16 May 2005 21:53:55 -0700 Subject: [PATCH] alpha/osf_sys: use helper functions to convert between tv and jiffies Use helper functions to convert between timeval structure and jiffies rather than custom logic. Signed-off-by: Nishanth Aravamudan Signed-off-by: Domen Puncer Acked-by: Richard Henderson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/kernel/osf_sys.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 64e450dddb4..167fd89f870 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -1150,16 +1150,13 @@ osf_usleep_thread(struct timeval32 __user *sleep, struct timeval32 __user *remai if (get_tv32(&tmp, sleep)) goto fault; - ticks = tmp.tv_usec; - ticks = (ticks + (1000000 / HZ) - 1) / (1000000 / HZ); - ticks += tmp.tv_sec * HZ; + ticks = timeval_to_jiffies(&tmp); current->state = TASK_INTERRUPTIBLE; ticks = schedule_timeout(ticks); if (remain) { - tmp.tv_sec = ticks / HZ; - tmp.tv_usec = ticks % HZ; + jiffies_to_timeval(ticks, &tmp); if (put_tv32(remain, &tmp)) goto fault; } -- cgit v1.2.3 From afbf510d47c4009f5d67ec3c0e0b45eb0441bca3 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 16 May 2005 21:53:56 -0700 Subject: [PATCH] pcmcia/ds: handle any error code register_chrdev() can return errors (negative) other then -EBUSY, so check for any negative error code. Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/ds.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 66150d08b5c..c4ade288c5d 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1592,9 +1592,9 @@ static int __init init_pcmcia_bus(void) /* Set up character device for user mode clients */ i = register_chrdev(0, "pcmcia", &ds_fops); - if (i == -EBUSY) + if (i < 0) printk(KERN_NOTICE "unable to find a free device # for " - "Driver Services\n"); + "Driver Services (error=%d)\n", i); else major_dev = i; -- cgit v1.2.3 From 5418b6925c353c8286651b67fdb8559dd9e54e46 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 16 May 2005 21:53:57 -0700 Subject: [PATCH] kill These days handles everything, no need for an asm header on just two architectures. Signed-off-by: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ia64/ia32/ia32_ioctl.c | 1 - include/asm-ia64/ioctl32.h | 1 - include/asm-x86_64/ioctl32.h | 1 - 3 files changed, 3 deletions(-) diff --git a/arch/ia64/ia32/ia32_ioctl.c b/arch/ia64/ia32/ia32_ioctl.c index 9845dabe261..164b211f417 100644 --- a/arch/ia64/ia32/ia32_ioctl.c +++ b/arch/ia64/ia32/ia32_ioctl.c @@ -13,7 +13,6 @@ #define INCLUDES #include "compat_ioctl.c" -#include #define IOCTL_NR(a) ((a) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) diff --git a/include/asm-ia64/ioctl32.h b/include/asm-ia64/ioctl32.h index d0d227f45e0..e69de29bb2d 100644 --- a/include/asm-ia64/ioctl32.h +++ b/include/asm-ia64/ioctl32.h @@ -1 +0,0 @@ -#include diff --git a/include/asm-x86_64/ioctl32.h b/include/asm-x86_64/ioctl32.h index d0d227f45e0..e69de29bb2d 100644 --- a/include/asm-x86_64/ioctl32.h +++ b/include/asm-x86_64/ioctl32.h @@ -1 +0,0 @@ -#include -- cgit v1.2.3 From dfaa9c94b13071c9b5f8578d0ae99acc76c60139 Mon Sep 17 00:00:00 2001 From: William Lee Irwin III Date: Mon, 16 May 2005 21:53:58 -0700 Subject: [PATCH] profile.c: `schedule' parsing fix profile=schedule parsing is not quite what it should be. First, str[7] is 'e', not ',', but then even if it did fall through, prof_on = SCHED_PROFILING would be clobbered inside if (get_option(...)) So a small amount of rearrangement is done in this patch to correct it. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/profile.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/kernel/profile.c b/kernel/profile.c index 0221a50ca86..ad8cbb75ffa 100644 --- a/kernel/profile.c +++ b/kernel/profile.c @@ -49,15 +49,19 @@ static DECLARE_MUTEX(profile_flip_mutex); static int __init profile_setup(char * str) { + static char __initdata schedstr[] = "schedule"; int par; - if (!strncmp(str, "schedule", 8)) { + if (!strncmp(str, schedstr, strlen(schedstr))) { prof_on = SCHED_PROFILING; - printk(KERN_INFO "kernel schedule profiling enabled\n"); - if (str[7] == ',') - str += 8; - } - if (get_option(&str,&par)) { + if (str[strlen(schedstr)] == ',') + str += strlen(schedstr) + 1; + if (get_option(&str, &par)) + prof_shift = par; + printk(KERN_INFO + "kernel schedule profiling enabled (shift: %ld)\n", + prof_shift); + } else if (get_option(&str, &par)) { prof_shift = par; prof_on = CPU_PROFILING; printk(KERN_INFO "kernel profiling enabled (shift: %ld)\n", -- cgit v1.2.3 From a1446c7fb7610a7b417d8b2fadb6751f86ee833e Mon Sep 17 00:00:00 2001 From: Jody McIntyre Date: Mon, 16 May 2005 21:53:59 -0700 Subject: [PATCH] ieee1394: feature removal notices drivers/ieee1394 feature removal notices: amdtp, cmp, legacy rawiso interface Signed-off-by: Jody McIntyre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/feature-removal-schedule.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index d3c52dd24a2..b9eb209318a 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -63,3 +63,23 @@ Why: Outside of Linux, the only implementations of anything even people, who might be using implementations that I am not aware of, to adjust to this upcoming change. Who: Paul E. McKenney + +--------------------------- + +What: IEEE1394 Audio and Music Data Transmission Protocol driver, + Connection Management Procedures driver +When: November 2005 +Files: drivers/ieee1394/{amdtp,cmp}* +Why: These are incomplete, have never worked, and are better implemented + in userland via raw1394 (see http://freebob.sourceforge.net/ for + example.) +Who: Jody McIntyre + +--------------------------- + +What: raw1394: requests of type RAW1394_REQ_ISO_SEND, RAW1394_REQ_ISO_LISTEN +When: November 2005 +Why: Deprecated in favour of the new ioctl-based rawiso interface, which is + more efficient. You should really be using libraw1394 for raw1394 + access anyway. +Who: Jody McIntyre -- cgit v1.2.3 From f72cd138e6afc6d93a8e0aacb7e3160cf04d840b Mon Sep 17 00:00:00 2001 From: Jody McIntyre Date: Mon, 16 May 2005 21:53:59 -0700 Subject: [PATCH] ieee1394: drivers/ieee1394/pcilynx.c: remove dead options The options CONFIG_IEEE1394_PCILYNX_LOCALRAM and CONFIG_IEEE1394_PCILYNX_PORTS are not available for some time. Signed-off-by: Adrian Bunk Signed-off-by: Jody McIntyre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ieee1394/Kconfig | 5 - drivers/ieee1394/pcilynx.c | 391 +-------------------------------------------- drivers/ieee1394/pcilynx.h | 49 +----- 3 files changed, 2 insertions(+), 443 deletions(-) diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig index 78b201fb5e8..7d58af1ae30 100644 --- a/drivers/ieee1394/Kconfig +++ b/drivers/ieee1394/Kconfig @@ -84,11 +84,6 @@ config IEEE1394_PCILYNX To compile this driver as a module, say M here: the module will be called pcilynx. -# Non-maintained pcilynx options -# if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then -# bool ' Use PCILynx local RAM' CONFIG_IEEE1394_PCILYNX_LOCALRAM -# bool ' Support for non-IEEE1394 local ports' CONFIG_IEEE1394_PCILYNX_PORTS -# fi config IEEE1394_OHCI1394 tristate "OHCI-1394 support" depends on PCI && IEEE1394 diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c index a261d2b0e5a..2689d938276 100644 --- a/drivers/ieee1394/pcilynx.c +++ b/drivers/ieee1394/pcilynx.c @@ -834,327 +834,6 @@ static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) * IEEE-1394 functionality section END * ***************************************/ -#ifdef CONFIG_IEEE1394_PCILYNX_PORTS -/* VFS functions for local bus / aux device access. Access to those - * is implemented as a character device instead of block devices - * because buffers are not wanted for this. Therefore llseek (from - * VFS) can be used for these char devices with obvious effects. - */ -static int mem_open(struct inode*, struct file*); -static int mem_release(struct inode*, struct file*); -static unsigned int aux_poll(struct file*, struct poll_table_struct*); -static loff_t mem_llseek(struct file*, loff_t, int); -static ssize_t mem_read (struct file*, char*, size_t, loff_t*); -static ssize_t mem_write(struct file*, const char*, size_t, loff_t*); - - -static struct file_operations aux_ops = { - .owner = THIS_MODULE, - .read = mem_read, - .write = mem_write, - .poll = aux_poll, - .llseek = mem_llseek, - .open = mem_open, - .release = mem_release, -}; - - -static void aux_setup_pcls(struct ti_lynx *lynx) -{ - struct ti_pcl pcl; - - pcl.next = PCL_NEXT_INVALID; - pcl.user_data = pcl_bus(lynx, lynx->dmem_pcl); - put_pcl(lynx, lynx->dmem_pcl, &pcl); -} - -static int mem_open(struct inode *inode, struct file *file) -{ - int cid = iminor(inode); - enum { t_rom, t_aux, t_ram } type; - struct memdata *md; - - if (cid < PCILYNX_MINOR_AUX_START) { - /* just for completeness */ - return -ENXIO; - } else if (cid < PCILYNX_MINOR_ROM_START) { - cid -= PCILYNX_MINOR_AUX_START; - if (cid >= num_of_cards || !cards[cid].aux_port) - return -ENXIO; - type = t_aux; - } else if (cid < PCILYNX_MINOR_RAM_START) { - cid -= PCILYNX_MINOR_ROM_START; - if (cid >= num_of_cards || !cards[cid].local_rom) - return -ENXIO; - type = t_rom; - } else { - /* WARNING: Know what you are doing when opening RAM. - * It is currently used inside the driver! */ - cid -= PCILYNX_MINOR_RAM_START; - if (cid >= num_of_cards || !cards[cid].local_ram) - return -ENXIO; - type = t_ram; - } - - md = (struct memdata *)kmalloc(sizeof(struct memdata), SLAB_KERNEL); - if (md == NULL) - return -ENOMEM; - - md->lynx = &cards[cid]; - md->cid = cid; - - switch (type) { - case t_rom: - md->type = rom; - break; - case t_ram: - md->type = ram; - break; - case t_aux: - atomic_set(&md->aux_intr_last_seen, - atomic_read(&cards[cid].aux_intr_seen)); - md->type = aux; - break; - } - - file->private_data = md; - - return 0; -} - -static int mem_release(struct inode *inode, struct file *file) -{ - kfree(file->private_data); - return 0; -} - -static unsigned int aux_poll(struct file *file, poll_table *pt) -{ - struct memdata *md = (struct memdata *)file->private_data; - int cid = md->cid; - unsigned int mask; - - /* reading and writing is always allowed */ - mask = POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM; - - if (md->type == aux) { - poll_wait(file, &cards[cid].aux_intr_wait, pt); - - if (atomic_read(&md->aux_intr_last_seen) - != atomic_read(&cards[cid].aux_intr_seen)) { - mask |= POLLPRI; - atomic_inc(&md->aux_intr_last_seen); - } - } - - return mask; -} - -loff_t mem_llseek(struct file *file, loff_t offs, int orig) -{ - loff_t newoffs; - - switch (orig) { - case 0: - newoffs = offs; - break; - case 1: - newoffs = offs + file->f_pos; - break; - case 2: - newoffs = PCILYNX_MAX_MEMORY + 1 + offs; - break; - default: - return -EINVAL; - } - - if (newoffs < 0 || newoffs > PCILYNX_MAX_MEMORY + 1) return -EINVAL; - - file->f_pos = newoffs; - return newoffs; -} - -/* - * do not DMA if count is too small because this will have a serious impact - * on performance - the value 2400 was found by experiment and may not work - * everywhere as good as here - use mem_mindma option for modules to change - */ -static short mem_mindma = 2400; -module_param(mem_mindma, short, 0444); -MODULE_PARM_DESC(mem_mindma, "Minimum amount of data required to use DMA"); - -static ssize_t mem_dmaread(struct memdata *md, u32 physbuf, ssize_t count, - int offset) -{ - pcltmp_t pcltmp; - struct ti_pcl *pcl; - size_t retval; - int i; - DECLARE_WAITQUEUE(wait, current); - - count &= ~3; - count = min(count, 53196); - retval = count; - - if (reg_read(md->lynx, DMA_CHAN_CTRL(CHANNEL_LOCALBUS)) - & DMA_CHAN_CTRL_BUSY) { - PRINT(KERN_WARNING, md->lynx->id, "DMA ALREADY ACTIVE!"); - } - - reg_write(md->lynx, LBUS_ADDR, md->type | offset); - - pcl = edit_pcl(md->lynx, md->lynx->dmem_pcl, &pcltmp); - pcl->buffer[0].control = PCL_CMD_LBUS_TO_PCI | min(count, 4092); - pcl->buffer[0].pointer = physbuf; - count -= 4092; - - i = 0; - while (count > 0) { - i++; - pcl->buffer[i].control = min(count, 4092); - pcl->buffer[i].pointer = physbuf + i * 4092; - count -= 4092; - } - pcl->buffer[i].control |= PCL_LAST_BUFF; - commit_pcl(md->lynx, md->lynx->dmem_pcl, &pcltmp); - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&md->lynx->mem_dma_intr_wait, &wait); - run_sub_pcl(md->lynx, md->lynx->dmem_pcl, 2, CHANNEL_LOCALBUS); - - schedule(); - while (reg_read(md->lynx, DMA_CHAN_CTRL(CHANNEL_LOCALBUS)) - & DMA_CHAN_CTRL_BUSY) { - if (signal_pending(current)) { - retval = -EINTR; - break; - } - schedule(); - } - - reg_write(md->lynx, DMA_CHAN_CTRL(CHANNEL_LOCALBUS), 0); - remove_wait_queue(&md->lynx->mem_dma_intr_wait, &wait); - - if (reg_read(md->lynx, DMA_CHAN_CTRL(CHANNEL_LOCALBUS)) - & DMA_CHAN_CTRL_BUSY) { - PRINT(KERN_ERR, md->lynx->id, "DMA STILL ACTIVE!"); - } - - return retval; -} - -static ssize_t mem_read(struct file *file, char *buffer, size_t count, - loff_t *offset) -{ - struct memdata *md = (struct memdata *)file->private_data; - ssize_t bcount; - size_t alignfix; - loff_t off = *offset; /* avoid useless 64bit-arithmetic */ - ssize_t retval; - void *membase; - - if ((off + count) > PCILYNX_MAX_MEMORY+1) { - count = PCILYNX_MAX_MEMORY+1 - off; - } - if (count == 0 || off > PCILYNX_MAX_MEMORY) { - return -ENOSPC; - } - - switch (md->type) { - case rom: - membase = md->lynx->local_rom; - break; - case ram: - membase = md->lynx->local_ram; - break; - case aux: - membase = md->lynx->aux_port; - break; - default: - panic("pcilynx%d: unsupported md->type %d in %s", - md->lynx->id, md->type, __FUNCTION__); - } - - down(&md->lynx->mem_dma_mutex); - - if (count < mem_mindma) { - memcpy_fromio(md->lynx->mem_dma_buffer, membase+off, count); - goto out; - } - - bcount = count; - alignfix = 4 - (off % 4); - if (alignfix != 4) { - if (bcount < alignfix) { - alignfix = bcount; - } - memcpy_fromio(md->lynx->mem_dma_buffer, membase+off, - alignfix); - if (bcount == alignfix) { - goto out; - } - bcount -= alignfix; - off += alignfix; - } - - while (bcount >= 4) { - retval = mem_dmaread(md, md->lynx->mem_dma_buffer_dma - + count - bcount, bcount, off); - if (retval < 0) return retval; - - bcount -= retval; - off += retval; - } - - if (bcount) { - memcpy_fromio(md->lynx->mem_dma_buffer + count - bcount, - membase+off, bcount); - } - - out: - retval = copy_to_user(buffer, md->lynx->mem_dma_buffer, count); - up(&md->lynx->mem_dma_mutex); - - if (retval) return -EFAULT; - *offset += count; - return count; -} - - -static ssize_t mem_write(struct file *file, const char *buffer, size_t count, - loff_t *offset) -{ - struct memdata *md = (struct memdata *)file->private_data; - - if (((*offset) + count) > PCILYNX_MAX_MEMORY+1) { - count = PCILYNX_MAX_MEMORY+1 - *offset; - } - if (count == 0 || *offset > PCILYNX_MAX_MEMORY) { - return -ENOSPC; - } - - /* FIXME: dereferencing pointers to PCI mem doesn't work everywhere */ - switch (md->type) { - case aux: - if (copy_from_user(md->lynx->aux_port+(*offset), buffer, count)) - return -EFAULT; - break; - case ram: - if (copy_from_user(md->lynx->local_ram+(*offset), buffer, count)) - return -EFAULT; - break; - case rom: - /* the ROM may be writeable */ - if (copy_from_user(md->lynx->local_rom+(*offset), buffer, count)) - return -EFAULT; - break; - } - - file->f_pos += count; - return count; -} -#endif /* CONFIG_IEEE1394_PCILYNX_PORTS */ - /******************************************************** * Global stuff (interrupt handler, init/shutdown code) * @@ -1181,18 +860,6 @@ static irqreturn_t lynx_irq_handler(int irq, void *dev_id, reg_write(lynx, LINK_INT_STATUS, linkint); reg_write(lynx, PCI_INT_STATUS, intmask); -#ifdef CONFIG_IEEE1394_PCILYNX_PORTS - if (intmask & PCI_INT_AUX_INT) { - atomic_inc(&lynx->aux_intr_seen); - wake_up_interruptible(&lynx->aux_intr_wait); - } - - if (intmask & PCI_INT_DMA_HLT(CHANNEL_LOCALBUS)) { - wake_up_interruptible(&lynx->mem_dma_intr_wait); - } -#endif - - if (intmask & PCI_INT_1394) { if (linkint & LINK_INT_PHY_TIMEOUT) { PRINT(KERN_INFO, lynx->id, "PHY timeout occurred"); @@ -1484,15 +1151,9 @@ static void remove_card(struct pci_dev *dev) pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page, lynx->rcv_page_dma); case have_aux_buf: -#ifdef CONFIG_IEEE1394_PCILYNX_PORTS - pci_free_consistent(lynx->dev, 65536, lynx->mem_dma_buffer, - lynx->mem_dma_buffer_dma); -#endif case have_pcl_mem: -#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem, lynx->pcl_mem_dma); -#endif case clear: /* do nothing - already freed */ ; @@ -1546,7 +1207,6 @@ static int __devinit add_card(struct pci_dev *dev, spin_lock_init(&lynx->lock); spin_lock_init(&lynx->phy_reg_lock); -#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM lynx->pcl_mem = pci_alloc_consistent(dev, LOCALRAM_SIZE, &lynx->pcl_mem_dma); @@ -1558,16 +1218,6 @@ static int __devinit add_card(struct pci_dev *dev, } else { FAIL("failed to allocate PCL memory area"); } -#endif - -#ifdef CONFIG_IEEE1394_PCILYNX_PORTS - lynx->mem_dma_buffer = pci_alloc_consistent(dev, 65536, - &lynx->mem_dma_buffer_dma); - if (lynx->mem_dma_buffer == NULL) { - FAIL("failed to allocate DMA buffer for aux"); - } - lynx->state = have_aux_buf; -#endif lynx->rcv_page = pci_alloc_consistent(dev, PAGE_SIZE, &lynx->rcv_page_dma); @@ -1597,13 +1247,6 @@ static int __devinit add_card(struct pci_dev *dev, FAIL("failed to remap registers - card not accessible"); } -#ifdef CONFIG_IEEE1394_PCILYNX_LOCALRAM - if (lynx->local_ram == NULL) { - FAIL("failed to remap local RAM which is required for " - "operation"); - } -#endif - reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); /* Fix buggy cards with autoboot pin not tied low: */ reg_write(lynx, DMA0_CHAN_CTRL, 0); @@ -1624,13 +1267,6 @@ static int __devinit add_card(struct pci_dev *dev, /* alloc_pcl return values are not checked, it is expected that the * provided PCL space is sufficient for the initial allocations */ -#ifdef CONFIG_IEEE1394_PCILYNX_PORTS - if (lynx->aux_port != NULL) { - lynx->dmem_pcl = alloc_pcl(lynx); - aux_setup_pcls(lynx); - sema_init(&lynx->mem_dma_mutex, 1); - } -#endif lynx->rcv_pcl = alloc_pcl(lynx); lynx->rcv_pcl_start = alloc_pcl(lynx); lynx->async.pcl = alloc_pcl(lynx); @@ -1647,12 +1283,6 @@ static int __devinit add_card(struct pci_dev *dev, reg_write(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL); -#ifdef CONFIG_IEEE1394_PCILYNX_PORTS - reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_AUX_INT); - init_waitqueue_head(&lynx->mem_dma_intr_wait); - init_waitqueue_head(&lynx->aux_intr_wait); -#endif - tasklet_init(&lynx->iso_rcv.tq, (void (*)(unsigned long))iso_rcv_bh, (unsigned long)lynx); @@ -1944,37 +1574,18 @@ static int __init pcilynx_init(void) { int ret; -#ifdef CONFIG_IEEE1394_PCILYNX_PORTS - if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) { - PRINT_G(KERN_ERR, "allocation of char major number %d failed", - PCILYNX_MAJOR); - return -EBUSY; - } -#endif - ret = pci_register_driver(&lynx_pci_driver); if (ret < 0) { PRINT_G(KERN_ERR, "PCI module init failed"); - goto free_char_dev; + return ret; } return 0; - - free_char_dev: -#ifdef CONFIG_IEEE1394_PCILYNX_PORTS - unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME); -#endif - - return ret; } static void __exit pcilynx_cleanup(void) { pci_unregister_driver(&lynx_pci_driver); - -#ifdef CONFIG_IEEE1394_PCILYNX_PORTS - unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME); -#endif } diff --git a/drivers/ieee1394/pcilynx.h b/drivers/ieee1394/pcilynx.h index 644ec55d3d4..d631aa8383a 100644 --- a/drivers/ieee1394/pcilynx.h +++ b/drivers/ieee1394/pcilynx.h @@ -55,16 +55,6 @@ struct ti_lynx { void __iomem *aux_port; quadlet_t bus_info_block[5]; -#ifdef CONFIG_IEEE1394_PCILYNX_PORTS - atomic_t aux_intr_seen; - wait_queue_head_t aux_intr_wait; - - void *mem_dma_buffer; - dma_addr_t mem_dma_buffer_dma; - struct semaphore mem_dma_mutex; - wait_queue_head_t mem_dma_intr_wait; -#endif - /* * use local RAM of LOCALRAM_SIZE bytes for PCLs, which allows for * LOCALRAM_SIZE * 8 PCLs (each sized 128 bytes); @@ -72,11 +62,9 @@ struct ti_lynx { */ u8 pcl_bmap[LOCALRAM_SIZE / 1024]; -#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM /* point to PCLs memory area if needed */ void *pcl_mem; dma_addr_t pcl_mem_dma; -#endif /* PCLs for local mem / aux transfers */ pcl_t dmem_pcl; @@ -378,39 +366,6 @@ struct ti_pcl { #define pcloffs(MEMBER) (offsetof(struct ti_pcl, MEMBER)) -#ifdef CONFIG_IEEE1394_PCILYNX_LOCALRAM - -static inline void put_pcl(const struct ti_lynx *lynx, pcl_t pclid, - const struct ti_pcl *pcl) -{ - int i; - u32 *in = (u32 *)pcl; - u32 *out = (u32 *)(lynx->local_ram + pclid * sizeof(struct ti_pcl)); - - for (i = 0; i < 32; i++, out++, in++) { - writel(*in, out); - } -} - -static inline void get_pcl(const struct ti_lynx *lynx, pcl_t pclid, - struct ti_pcl *pcl) -{ - int i; - u32 *out = (u32 *)pcl; - u32 *in = (u32 *)(lynx->local_ram + pclid * sizeof(struct ti_pcl)); - - for (i = 0; i < 32; i++, out++, in++) { - *out = readl(in); - } -} - -static inline u32 pcl_bus(const struct ti_lynx *lynx, pcl_t pclid) -{ - return pci_resource_start(lynx->dev, 1) + pclid * sizeof(struct ti_pcl); -} - -#else /* CONFIG_IEEE1394_PCILYNX_LOCALRAM */ - static inline void put_pcl(const struct ti_lynx *lynx, pcl_t pclid, const struct ti_pcl *pcl) { @@ -431,10 +386,8 @@ static inline u32 pcl_bus(const struct ti_lynx *lynx, pcl_t pclid) return lynx->pcl_mem_dma + pclid * sizeof(struct ti_pcl); } -#endif /* CONFIG_IEEE1394_PCILYNX_LOCALRAM */ - -#if defined (CONFIG_IEEE1394_PCILYNX_LOCALRAM) || defined (__BIG_ENDIAN) +#if defined (__BIG_ENDIAN) typedef struct ti_pcl pcltmp_t; static inline struct ti_pcl *edit_pcl(const struct ti_lynx *lynx, pcl_t pclid, -- cgit v1.2.3 From 9ac485dc37b6336c5bf694f9933f43684fd1fd1e Mon Sep 17 00:00:00 2001 From: Jody McIntyre Date: Mon, 16 May 2005 21:54:00 -0700 Subject: [PATCH] ieee1394: drivers/ieee1394/ieee1394_transactions.c: possible cleanups This patch contains the following possible cleanups: - #if 0 the following unused global functions: - hpsb_lock - hpsb_send_gasp - ieee1394_transactions.h: remove the stale hpsb_lock64 prototype Signed-off-by: Adrian Bunk Signed-off-by: Jody McIntyre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ieee1394/ieee1394_core.c | 1 - drivers/ieee1394/ieee1394_transactions.c | 3 +++ drivers/ieee1394/ieee1394_transactions.h | 7 ------- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index 1c5845f7e4a..62764c39462 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -1248,7 +1248,6 @@ EXPORT_SYMBOL(hpsb_make_phypacket); EXPORT_SYMBOL(hpsb_make_isopacket); EXPORT_SYMBOL(hpsb_read); EXPORT_SYMBOL(hpsb_write); -EXPORT_SYMBOL(hpsb_lock); EXPORT_SYMBOL(hpsb_packet_success); /** highlevel.c **/ diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c index 09908b9564d..0aa876360f9 100644 --- a/drivers/ieee1394/ieee1394_transactions.c +++ b/drivers/ieee1394/ieee1394_transactions.c @@ -535,6 +535,7 @@ hpsb_write_fail: return retval; } +#if 0 int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation, u64 addr, int extcode, quadlet_t *data, quadlet_t arg) @@ -599,3 +600,5 @@ int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation, return retval; } + +#endif /* 0 */ diff --git a/drivers/ieee1394/ieee1394_transactions.h b/drivers/ieee1394/ieee1394_transactions.h index 526a43ceb49..45ba784fe6d 100644 --- a/drivers/ieee1394/ieee1394_transactions.h +++ b/drivers/ieee1394/ieee1394_transactions.h @@ -53,12 +53,5 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation, u64 addr, quadlet_t *buffer, size_t length); int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation, u64 addr, quadlet_t *buffer, size_t length); -int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation, - u64 addr, int extcode, quadlet_t *data, quadlet_t arg); -int hpsb_lock64(struct hpsb_host *host, nodeid_t node, unsigned int generation, - u64 addr, int extcode, octlet_t *data, octlet_t arg); -int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation, - quadlet_t *buffer, size_t length, u32 specifier_id, - unsigned int version); #endif /* _IEEE1394_TRANSACTIONS_H */ -- cgit v1.2.3 From 616b859fbd0e59707a24612d5b5fec791156c822 Mon Sep 17 00:00:00 2001 From: Jody McIntyre Date: Mon, 16 May 2005 21:54:01 -0700 Subject: [PATCH] ieee1394: remove NULL checks for kfree This patch removes redundant NULL pointer checks before kfree() in all of drivers/ieee1394/ Signed-off-by: Jesper Juhl Signed-off-by: Jody McIntyre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ieee1394/nodemgr.c | 3 +-- drivers/ieee1394/ohci1394.c | 2 +- drivers/ieee1394/video1394.c | 29 ++++++++--------------------- 3 files changed, 10 insertions(+), 24 deletions(-) diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index a1e30a66297..83e66ed97ab 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -1005,8 +1005,7 @@ static struct unit_directory *nodemgr_process_unit_directory return ud; unit_directory_error: - if (ud != NULL) - kfree(ud); + kfree(ud); return NULL; } diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 6cb0b586c29..36e25ac823d 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -2931,7 +2931,7 @@ static void free_dma_rcv_ctx(struct dma_rcv_ctx *d) kfree(d->prg_cpu); kfree(d->prg_bus); } - if (d->spb) kfree(d->spb); + kfree(d->spb); /* Mark this context as freed. */ d->ohci = NULL; diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c index 4bedf7113f4..6eb9b80b1bc 100644 --- a/drivers/ieee1394/video1394.c +++ b/drivers/ieee1394/video1394.c @@ -180,23 +180,13 @@ static int free_dma_iso_ctx(struct dma_iso_ctx *d) kfree(d->prg_reg); } - if (d->ir_prg) - kfree(d->ir_prg); - - if (d->it_prg) - kfree(d->it_prg); - - if (d->buffer_status) - kfree(d->buffer_status); - if (d->buffer_time) - kfree(d->buffer_time); - if (d->last_used_cmd) - kfree(d->last_used_cmd); - if (d->next_buffer) - kfree(d->next_buffer); - + kfree(d->ir_prg); + kfree(d->it_prg); + kfree(d->buffer_status); + kfree(d->buffer_time); + kfree(d->last_used_cmd); + kfree(d->next_buffer); list_del(&d->link); - kfree(d); return 0; @@ -1060,8 +1050,7 @@ static int __video1394_ioctl(struct file *file, PRINT(KERN_ERR, ohci->host->id, "Buffer %d is already used",v.buffer); spin_unlock_irqrestore(&d->lock,flags); - if (psizes) - kfree(psizes); + kfree(psizes); return -EBUSY; } @@ -1116,9 +1105,7 @@ static int __video1394_ioctl(struct file *file, } } - if (psizes) - kfree(psizes); - + kfree(psizes); return 0; } -- cgit v1.2.3 From 2554bd2a68e2c3ca7f2b953fe2860a9e84a5579a Mon Sep 17 00:00:00 2001 From: Jody McIntyre Date: Mon, 16 May 2005 21:54:03 -0700 Subject: [PATCH] ieee1394: drivers/ieee1394/pcilynx.c: Use the DMA_32BIT_MASK constant Use the DMA_32BIT_MASK constant from dma-mapping.h when calling pci_set_dma_mask() or pci_set_consistent_dma_mask() These patches include dma-mapping.h explicitly because it caused errors on some architectures otherwise. See http://marc.theaimsgroup.com/?t=108001993000001&r=1&w=2 for details Signed-off-by: Tobias Klauser Signed-off-by: Jody McIntyre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ieee1394/pcilynx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c index 2689d938276..bdb3a85cafa 100644 --- a/drivers/ieee1394/pcilynx.c +++ b/drivers/ieee1394/pcilynx.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -1185,7 +1186,7 @@ static int __devinit add_card(struct pci_dev *dev, error = -ENXIO; - if (pci_set_dma_mask(dev, 0xffffffff)) + if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) FAIL("DMA address limits not supported for PCILynx hardware"); if (pci_enable_device(dev)) FAIL("failed to enable PCILynx hardware"); -- cgit v1.2.3 From 8d98c5cd41d1932bb76a3945b4e8dea889224d87 Mon Sep 17 00:00:00 2001 From: Jody McIntyre Date: Mon, 16 May 2005 21:54:04 -0700 Subject: [PATCH] ieee1394: single buffer fixes to video1394 Apply and fixup patch from Markus Tavenrath for video1394 to allow only a single buffer on receive and two buffers on transmit. Tested with libdc1394 and dvconnect (libdv). Signed-off-by: Dan Dennedy Signed-off-by: Jody McIntyre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ieee1394/video1394.c | 110 +++++++++++++++++++++++++++++++++---------- 1 file changed, 85 insertions(+), 25 deletions(-) diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c index 6eb9b80b1bc..d68c4658f2f 100644 --- a/drivers/ieee1394/video1394.c +++ b/drivers/ieee1394/video1394.c @@ -35,6 +35,11 @@ * */ +/* Markus Tavenrath : + - fixed checks for valid buffer-numbers in video1394_icotl + - changed the ways the dma prg's are used, now it's possible to use + even a single dma buffer +*/ #include #include #include @@ -112,6 +117,7 @@ struct dma_iso_ctx { struct it_dma_prg **it_prg; unsigned int *buffer_status; + unsigned int *buffer_prg_assignment; struct timeval *buffer_time; /* time when the buffer was received */ unsigned int *last_used_cmd; /* For ISO Transmit with variable sized packets only ! */ @@ -183,6 +189,7 @@ static int free_dma_iso_ctx(struct dma_iso_ctx *d) kfree(d->ir_prg); kfree(d->it_prg); kfree(d->buffer_status); + kfree(d->buffer_prg_assignment); kfree(d->buffer_time); kfree(d->last_used_cmd); kfree(d->next_buffer); @@ -220,7 +227,7 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc, /* Init the regions for easy cleanup */ dma_region_init(&d->dma); - if (dma_region_alloc(&d->dma, d->num_desc * d->buf_size, ohci->dev, + if (dma_region_alloc(&d->dma, (d->num_desc - 1) * d->buf_size, ohci->dev, PCI_DMA_BIDIRECTIONAL)) { PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma buffer"); free_dma_iso_ctx(d); @@ -332,6 +339,8 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc, d->buffer_status = kmalloc(d->num_desc * sizeof(unsigned int), GFP_KERNEL); + d->buffer_prg_assignment = kmalloc(d->num_desc * sizeof(unsigned int), + GFP_KERNEL); d->buffer_time = kmalloc(d->num_desc * sizeof(struct timeval), GFP_KERNEL); d->last_used_cmd = kmalloc(d->num_desc * sizeof(unsigned int), @@ -344,6 +353,11 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc, free_dma_iso_ctx(d); return NULL; } + if (d->buffer_prg_assignment == NULL) { + PRINT(KERN_ERR, ohci->host->id, "Failed to allocate buffer_prg_assignment"); + free_dma_iso_ctx(d); + return NULL; + } if (d->buffer_time == NULL) { PRINT(KERN_ERR, ohci->host->id, "Failed to allocate buffer_time"); free_dma_iso_ctx(d); @@ -360,6 +374,7 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc, return NULL; } memset(d->buffer_status, 0, d->num_desc * sizeof(unsigned int)); + memset(d->buffer_prg_assignment, 0, d->num_desc * sizeof(unsigned int)); memset(d->buffer_time, 0, d->num_desc * sizeof(struct timeval)); memset(d->last_used_cmd, 0, d->num_desc * sizeof(unsigned int)); memset(d->next_buffer, -1, d->num_desc * sizeof(int)); @@ -369,7 +384,7 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc, PRINT(KERN_INFO, ohci->host->id, "Iso %s DMA: %d buffers " "of size %d allocated for a frame size %d, each with %d prgs", (type == OHCI_ISO_RECEIVE) ? "receive" : "transmit", - d->num_desc, d->buf_size, d->frame_size, d->nb_cmd); + d->num_desc - 1, d->buf_size, d->frame_size, d->nb_cmd); return d; } @@ -384,11 +399,36 @@ static void reset_ir_status(struct dma_iso_ctx *d, int n) d->ir_prg[n][i].status = cpu_to_le32(d->left_size); } +static void reprogram_dma_ir_prg(struct dma_iso_ctx *d, int n, int buffer, int flags) +{ + struct dma_cmd *ir_prg = d->ir_prg[n]; + unsigned long buf = (unsigned long)d->dma.kvirt + buffer * d->buf_size; + int i; + + d->buffer_prg_assignment[n] = buffer; + + ir_prg[0].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, buf - + (unsigned long)d->dma.kvirt)); + ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, + (buf + 4) - (unsigned long)d->dma.kvirt)); + + for (i=2;inb_cmd-1;i++) { + ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, + (buf+(i-1)*PAGE_SIZE) - + (unsigned long)d->dma.kvirt)); + } + + ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | + DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size); + ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, + (buf+(i-1)*PAGE_SIZE) - (unsigned long)d->dma.kvirt)); +} + static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n, int flags) { struct dma_cmd *ir_prg = d->ir_prg[n]; struct dma_prog_region *ir_reg = &d->prg_reg[n]; - unsigned long buf = (unsigned long)d->dma.kvirt + n * d->buf_size; + unsigned long buf = (unsigned long)d->dma.kvirt; int i; /* the first descriptor will read only 4 bytes */ @@ -498,7 +538,7 @@ static void wakeup_dma_ir_ctx(unsigned long l) for (i = 0; i < d->num_desc; i++) { if (d->ir_prg[i][d->nb_cmd-1].status & cpu_to_le32(0xFFFF0000)) { reset_ir_status(d, i); - d->buffer_status[i] = VIDEO1394_BUFFER_READY; + d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY; do_gettimeofday(&d->buffer_time[i]); } } @@ -575,7 +615,7 @@ static void wakeup_dma_it_ctx(unsigned long l) int next = d->next_buffer[i]; put_timestamp(ohci, d, next); d->it_prg[i][d->last_used_cmd[i]].end.status = 0; - d->buffer_status[i] = VIDEO1394_BUFFER_READY; + d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY; } } @@ -585,11 +625,25 @@ static void wakeup_dma_it_ctx(unsigned long l) wake_up_interruptible(&d->waitq); } +static void reprogram_dma_it_prg(struct dma_iso_ctx *d, int n, int buffer) +{ + struct it_dma_prg *it_prg = d->it_prg[n]; + unsigned long buf = (unsigned long)d->dma.kvirt + buffer * d->buf_size; + int i; + + d->buffer_prg_assignment[n] = buffer; + for (i=0;inb_cmd;i++) { + it_prg[i].end.address = + cpu_to_le32(dma_region_offset_to_bus(&d->dma, + (buf+i*d->packet_size) - (unsigned long)d->dma.kvirt)); + } +} + static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag) { struct it_dma_prg *it_prg = d->it_prg[n]; struct dma_prog_region *it_reg = &d->prg_reg[n]; - unsigned long buf = (unsigned long)d->dma.kvirt + n * d->buf_size; + unsigned long buf = (unsigned long)d->dma.kvirt; int i; d->last_used_cmd[n] = d->nb_cmd - 1; for (i=0;inb_cmd;i++) { @@ -786,7 +840,7 @@ static int __video1394_ioctl(struct file *file, if (cmd == VIDEO1394_IOC_LISTEN_CHANNEL) { d = alloc_dma_iso_ctx(ohci, OHCI_ISO_RECEIVE, - v.nb_buffers, v.buf_size, + v.nb_buffers + 1, v.buf_size, v.channel, 0); if (d == NULL) { @@ -807,7 +861,7 @@ static int __video1394_ioctl(struct file *file, } else { d = alloc_dma_iso_ctx(ohci, OHCI_ISO_TRANSMIT, - v.nb_buffers, v.buf_size, + v.nb_buffers + 1, v.buf_size, v.channel, v.packet_size); if (d == NULL) { @@ -879,6 +933,7 @@ static int __video1394_ioctl(struct file *file, { struct video1394_wait v; struct dma_iso_ctx *d; + int next_prg; if (copy_from_user(&v, argp, sizeof(v))) return -EFAULT; @@ -886,7 +941,7 @@ static int __video1394_ioctl(struct file *file, d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel); if (d == NULL) return -EFAULT; - if ((v.buffer<0) || (v.buffer>d->num_desc)) { + if ((v.buffer<0) || (v.buffer>=d->num_desc - 1)) { PRINT(KERN_ERR, ohci->host->id, "Buffer %d out of range",v.buffer); return -EINVAL; @@ -903,12 +958,14 @@ static int __video1394_ioctl(struct file *file, d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED; + next_prg = (d->last_buffer + 1) % d->num_desc; if (d->last_buffer>=0) d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = - cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], 0) + cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0) & 0xfffffff0) | 0x1); - d->last_buffer = v.buffer; + d->last_buffer = next_prg; + reprogram_dma_ir_prg(d, d->last_buffer, v.buffer, d->flags); d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = 0; @@ -920,7 +977,7 @@ static int __video1394_ioctl(struct file *file, /* Tell the controller where the first program is */ reg_write(ohci, d->cmdPtr, - dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], 0) | 0x1); + dma_prog_region_offset_to_bus(&d->prg_reg[d->last_buffer], 0) | 0x1); /* Run IR context */ reg_write(ohci, d->ctrlSet, 0x8000); @@ -941,7 +998,7 @@ static int __video1394_ioctl(struct file *file, { struct video1394_wait v; struct dma_iso_ctx *d; - int i; + int i = 0; if (copy_from_user(&v, argp, sizeof(v))) return -EFAULT; @@ -949,7 +1006,7 @@ static int __video1394_ioctl(struct file *file, d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel); if (d == NULL) return -EFAULT; - if ((v.buffer<0) || (v.buffer>d->num_desc)) { + if ((v.buffer<0) || (v.buffer>d->num_desc - 1)) { PRINT(KERN_ERR, ohci->host->id, "Buffer %d out of range",v.buffer); return -EINVAL; @@ -995,9 +1052,9 @@ static int __video1394_ioctl(struct file *file, * Look ahead to see how many more buffers have been received */ i=0; - while (d->buffer_status[(v.buffer+1)%d->num_desc]== + while (d->buffer_status[(v.buffer+1)%(d->num_desc - 1)]== VIDEO1394_BUFFER_READY) { - v.buffer=(v.buffer+1)%d->num_desc; + v.buffer=(v.buffer+1)%(d->num_desc - 1); i++; } spin_unlock_irqrestore(&d->lock, flags); @@ -1013,6 +1070,7 @@ static int __video1394_ioctl(struct file *file, struct video1394_wait v; unsigned int *psizes = NULL; struct dma_iso_ctx *d; + int next_prg; if (copy_from_user(&v, argp, sizeof(v))) return -EFAULT; @@ -1020,7 +1078,7 @@ static int __video1394_ioctl(struct file *file, d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel); if (d == NULL) return -EFAULT; - if ((v.buffer<0) || (v.buffer>d->num_desc)) { + if ((v.buffer<0) || (v.buffer>=d->num_desc - 1)) { PRINT(KERN_ERR, ohci->host->id, "Buffer %d out of range",v.buffer); return -EINVAL; @@ -1046,6 +1104,8 @@ static int __video1394_ioctl(struct file *file, spin_lock_irqsave(&d->lock,flags); + // last_buffer is last_prg + next_prg = (d->last_buffer + 1) % d->num_desc; if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) { PRINT(KERN_ERR, ohci->host->id, "Buffer %d is already used",v.buffer); @@ -1056,8 +1116,7 @@ static int __video1394_ioctl(struct file *file, if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) { initialize_dma_it_prg_var_packet_queue( - d, v.buffer, psizes, - ohci); + d, next_prg, psizes, ohci); } d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED; @@ -1065,16 +1124,17 @@ static int __video1394_ioctl(struct file *file, if (d->last_buffer >= 0) { d->it_prg[d->last_buffer] [ d->last_used_cmd[d->last_buffer] ].end.branchAddress = - cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], + cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0) & 0xfffffff0) | 0x3); d->it_prg[d->last_buffer] [ d->last_used_cmd[d->last_buffer] ].begin.branchAddress = - cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], + cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0) & 0xfffffff0) | 0x3); - d->next_buffer[d->last_buffer] = v.buffer; + d->next_buffer[d->last_buffer] = (v.buffer + 1) % (d->num_desc - 1); } - d->last_buffer = v.buffer; + d->last_buffer = next_prg; + reprogram_dma_it_prg(d, d->last_buffer, v.buffer); d->next_buffer[d->last_buffer] = -1; d->it_prg[d->last_buffer][d->last_used_cmd[d->last_buffer]].end.branchAddress = 0; @@ -1089,7 +1149,7 @@ static int __video1394_ioctl(struct file *file, /* Tell the controller where the first program is */ reg_write(ohci, d->cmdPtr, - dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], 0) | 0x3); + dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0) | 0x3); /* Run IT context */ reg_write(ohci, d->ctrlSet, 0x8000); @@ -1120,7 +1180,7 @@ static int __video1394_ioctl(struct file *file, d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel); if (d == NULL) return -EFAULT; - if ((v.buffer<0) || (v.buffer>d->num_desc)) { + if ((v.buffer<0) || (v.buffer>=d->num_desc-1)) { PRINT(KERN_ERR, ohci->host->id, "Buffer %d out of range",v.buffer); return -EINVAL; -- cgit v1.2.3 From 74a01d11c92c06a0ceac88ca306d507a8186e7f6 Mon Sep 17 00:00:00 2001 From: Jody McIntyre Date: Mon, 16 May 2005 21:54:05 -0700 Subject: [PATCH] ieee1394: fix cross_bound check for null ISO packets Fix cross_bound to not return 1 for zero-length regions. Fixes regression when sending null ISO packets. Signed-off-by: Jody McIntyre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ieee1394/ohci1394.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h index d1758d40961..cc66c1cae25 100644 --- a/drivers/ieee1394/ohci1394.h +++ b/drivers/ieee1394/ohci1394.h @@ -236,6 +236,9 @@ struct ti_ohci { static inline int cross_bound(unsigned long addr, unsigned int size) { + if (size == 0) + return 0; + if (size > PAGE_SIZE) return 1; -- cgit v1.2.3 From 6262d062a3fc803d1798365e745b39f4faa04b0e Mon Sep 17 00:00:00 2001 From: Jody McIntyre Date: Mon, 16 May 2005 21:54:05 -0700 Subject: [PATCH] ieee1394: fix premature expiry of async packets Set the initial sendtime to be 10 seconds in the future, to avoid the packet timing out while it's still queued to be sent. This fixes furthur "no tlabel match" problems caused by premature expiry. Signed-off-by: Jody McIntyre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ieee1394/ieee1394_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index 62764c39462..a294e45c77c 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -520,7 +520,7 @@ int hpsb_send_packet(struct hpsb_packet *packet) if (!packet->no_waiter || packet->expect_response) { atomic_inc(&packet->refcnt); - packet->sendtime = jiffies; + packet->sendtime = jiffies + 10 * HZ; skb_queue_tail(&host->pending_packet_queue, packet->skb); } -- cgit v1.2.3 From 1ec359729960f7896db8f642454e603d22519d20 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:06 -0700 Subject: [PATCH] dvb: b2c2/flexcop driver refactoring part 1: drop old b2c2-usb stuff b2c2/flexcop driver refactoring to support PCI and USB based cards, part 1: drop abandoned attempt to support USB devices Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/b2c2/Kconfig | 13 - drivers/media/dvb/b2c2/Makefile | 3 - drivers/media/dvb/b2c2/b2c2-common.c | 214 ------------- drivers/media/dvb/b2c2/b2c2-usb-core.c | 549 --------------------------------- 4 files changed, 779 deletions(-) delete mode 100644 drivers/media/dvb/b2c2/b2c2-common.c delete mode 100644 drivers/media/dvb/b2c2/b2c2-usb-core.c diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig index 52596907a0b..f1f6187b7c1 100644 --- a/drivers/media/dvb/b2c2/Kconfig +++ b/drivers/media/dvb/b2c2/Kconfig @@ -11,16 +11,3 @@ config DVB_B2C2_SKYSTAR for the B2C2/BBTI Air2PC-ATSC card. Say Y if you own such a device and want to use it. - -config DVB_B2C2_USB - tristate "B2C2/Technisat Air/Sky/Cable2PC USB" - depends on DVB_CORE && USB && EXPERIMENTAL - select DVB_STV0299 - select DVB_MT352 - help - Support for the Air/Sky/Cable2PC USB DVB device by B2C2. Currently - the does nothing, but providing basic function for the used usb - protocol. - - Say Y if you own such a device and want to use it. - diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile index 9fb1247bfab..f9cdc6f052d 100644 --- a/drivers/media/dvb/b2c2/Makefile +++ b/drivers/media/dvb/b2c2/Makefile @@ -1,6 +1,3 @@ -obj-b2c2-usb = b2c2-usb-core.o b2c2-common.o - obj-$(CONFIG_DVB_B2C2_SKYSTAR) += skystar2.o -obj-$(CONFIG_DVB_B2C2_USB) + = b2c2-usb.o EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/drivers/media/dvb/b2c2/b2c2-common.c b/drivers/media/dvb/b2c2/b2c2-common.c deleted file mode 100644 index 000d60c405e..00000000000 --- a/drivers/media/dvb/b2c2/b2c2-common.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * b2c2-common.c - common methods for the B2C2/Technisat SkyStar2 PCI DVB card and - * for the B2C2/Technisat Sky/Cable/AirStar USB devices - * based on the FlexCopII/FlexCopIII by B2C2, Inc. - * - * Copyright (C) 2003 Vadim Catana, skystar@moldova.cc - * - * FIX: DISEQC Tone Burst in flexcop_diseqc_ioctl() - * FIX: FULL soft DiSEqC for skystar2 (FlexCopII rev 130) VP310 equipped - * Vincenzo Di Massa, hawk.it at tiscalinet.it - * - * Converted to Linux coding style - * Misc reorganization, polishing, restyling - * Roberto Ragusa, r.ragusa at libero.it - * - * Added hardware filtering support, - * Niklas Peinecke, peinecke at gdv.uni-hannover.de - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * 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 Lesser 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 "stv0299.h" -#include "mt352.h" -#include "mt312.h" - -static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio) -{ - u8 aclk = 0; - u8 bclk = 0; - - if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } - else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } - else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; } - else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; } - else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; } - else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; } - - stv0299_writereg (fe, 0x13, aclk); - stv0299_writereg (fe, 0x14, bclk); - stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg (fe, 0x21, (ratio ) & 0xf0); - - return 0; -} - -static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) -{ - u8 buf[4]; - u32 div; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; -// struct adapter* adapter = (struct adapter*) fe->dvb->priv; - - div = params->frequency / 125; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x84; // 0xC4 - buf[3] = 0x08; - - if (params->frequency < 1500000) buf[3] |= 0x10; - -// if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static u8 samsung_tbmu24112_inittab[] = { - 0x01, 0x15, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x7D, - 0x05, 0x35, - 0x06, 0x02, - 0x07, 0x00, - 0x08, 0xC3, - 0x0C, 0x00, - 0x0D, 0x81, - 0x0E, 0x23, - 0x0F, 0x12, - 0x10, 0x7E, - 0x11, 0x84, - 0x12, 0xB9, - 0x13, 0x88, - 0x14, 0x89, - 0x15, 0xC9, - 0x16, 0x00, - 0x17, 0x5C, - 0x18, 0x00, - 0x19, 0x00, - 0x1A, 0x00, - 0x1C, 0x00, - 0x1D, 0x00, - 0x1E, 0x00, - 0x1F, 0x3A, - 0x20, 0x2E, - 0x21, 0x80, - 0x22, 0xFF, - 0x23, 0xC1, - 0x28, 0x00, - 0x29, 0x1E, - 0x2A, 0x14, - 0x2B, 0x0F, - 0x2C, 0x09, - 0x2D, 0x05, - 0x31, 0x1F, - 0x32, 0x19, - 0x33, 0xFE, - 0x34, 0x93, - 0xff, 0xff, -}; - -static struct stv0299_config samsung_tbmu24112_config = { - .demod_address = 0x68, - .inittab = samsung_tbmu24112_inittab, - .mclk = 88000000UL, - .invert = 0, - .enhanced_tuning = 0, - .skip_reinit = 0, - .lock_output = STV0229_LOCKOUTPUT_LK, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 100, - .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, - .pll_set = samsung_tbmu24112_pll_set, -}; - - - - - -static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) -{ - static u8 mt352_clock_config [] = { 0x89, 0x10, 0x2d }; - static u8 mt352_reset [] = { 0x50, 0x80 }; - static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; - static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 }; - static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; - - mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); - udelay(2000); - mt352_write(fe, mt352_reset, sizeof(mt352_reset)); - mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - - mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); - mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - - return 0; -} - -static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf) -{ - u32 div; - unsigned char bs = 0; - - #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ - div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - - if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09; - if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a; - if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08; - - pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address - pllbuf[1] = div >> 8; - pllbuf[2] = div & 0xff; - pllbuf[3] = 0xcc; - pllbuf[4] = bs; - - return 0; -} - -static struct mt352_config samsung_tdtc9251dh0_config = { - - .demod_address = 0x0f, - .demod_init = samsung_tdtc9251dh0_demod_init, - .pll_set = samsung_tdtc9251dh0_pll_set, -}; - -static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) -{ - u8 buf[4]; - u32 div; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; -// struct adapter* adapter = (struct adapter*) fe->dvb->priv; - - div = (params->frequency + (125/2)) / 125; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = (div >> 0) & 0xff; - buf[2] = 0x84 | ((div >> 10) & 0x60); - buf[3] = 0x80; - - if (params->frequency < 1550000) - buf[3] |= 0x02; - - //if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static struct mt312_config skystar23_samsung_tbdu18132_config = { - - .demod_address = 0x0e, - .pll_set = skystar23_samsung_tbdu18132_pll_set, -}; diff --git a/drivers/media/dvb/b2c2/b2c2-usb-core.c b/drivers/media/dvb/b2c2/b2c2-usb-core.c deleted file mode 100644 index 9306da046c9..00000000000 --- a/drivers/media/dvb/b2c2/b2c2-usb-core.c +++ /dev/null @@ -1,549 +0,0 @@ -/* - * Copyright (C) 2004 Patrick Boettcher , - * Luca Bertagnolio <>, - * - * based on information provided by John Jurrius from BBTI, Inc. - * - * 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, version 2. - * - */ - -#include -#include -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvb_demux.h" -#include "dvb_filter.h" -#include "dvb_net.h" -#include "dvb_frontend.h" - -/* debug */ -#define dprintk(level,args...) \ - do { if ((debug & level)) { printk(args); } } while (0) -#define debug_dump(b,l) if (debug) {\ - int i; deb_xfer("%s: %d > ",__FUNCTION__,l); \ - for (i = 0; i < l; i++) deb_xfer("%02x ", b[i]); \ - deb_xfer("\n");\ -} - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,ctrl=4 (or-able))."); - -#define deb_info(args...) dprintk(0x01,args) -#define deb_ts(args...) dprintk(0x02,args) -#define deb_ctrl(args...) dprintk(0x04,args) - -/* Version information */ -#define DRIVER_VERSION "0.0" -#define DRIVER_DESC "Driver for B2C2/Technisat Air/Cable/Sky-2-PC USB devices" -#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de" - -/* transfer parameters */ -#define B2C2_USB_FRAMES_PER_ISO 4 -#define B2C2_USB_NUM_ISO_URB 4 /* TODO check out a good value */ - -#define B2C2_USB_CTRL_PIPE_IN usb_rcvctrlpipe(b2c2->udev,0) -#define B2C2_USB_CTRL_PIPE_OUT usb_sndctrlpipe(b2c2->udev,0) -#define B2C2_USB_DATA_PIPE usb_rcvisocpipe(b2c2->udev,0x81) - -struct usb_b2c2_usb { - struct usb_device *udev; - struct usb_interface *uintf; - - u8 *iso_buffer; - int buffer_size; - dma_addr_t iso_dma_handle; - struct urb *iso_urb[B2C2_USB_NUM_ISO_URB]; -}; - - -/* - * USB - * 10 90 34 12 78 56 04 00 - * usb_control_msg(udev, usb_sndctrlpipe(udev,0), - * 0x90, - * 0x10, - * 0x1234, - * 0x5678, - * buf, - * 4, - * 5*HZ); - * - * extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, - * __u8 request, - * __u8 requesttype, - * __u16 value, - * __u16 index, - * void *data, - * __u16 size, - * int timeout); - * - */ - -/* request types */ -typedef enum { - -/* something is wrong with this part - RTYPE_READ_DW = (1 << 6), - RTYPE_WRITE_DW_1 = (3 << 6), - RTYPE_READ_V8_MEMORY = (6 << 6), - RTYPE_WRITE_V8_MEMORY = (7 << 6), - RTYPE_WRITE_V8_FLASH = (8 << 6), - RTYPE_GENERIC = (9 << 6), -*/ - RTYPE_READ_DW = (3 << 6), - RTYPE_WRITE_DW_1 = (1 << 6), - - RTYPE_READ_V8_MEMORY = (6 << 6), - RTYPE_WRITE_V8_MEMORY = (7 << 6), - RTYPE_WRITE_V8_FLASH = (8 << 6), - RTYPE_GENERIC = (9 << 6), -} b2c2_usb_request_type_t; - -/* request */ -typedef enum { - B2C2_USB_WRITE_V8_MEM = 0x04, - B2C2_USB_READ_V8_MEM = 0x05, - B2C2_USB_READ_REG = 0x08, - B2C2_USB_WRITE_REG = 0x0A, -/* B2C2_USB_WRITEREGLO = 0x0A, */ - B2C2_USB_WRITEREGHI = 0x0B, - B2C2_USB_FLASH_BLOCK = 0x10, - B2C2_USB_I2C_REQUEST = 0x11, - B2C2_USB_UTILITY = 0x12, -} b2c2_usb_request_t; - -/* function definition for I2C_REQUEST */ -typedef enum { - USB_FUNC_I2C_WRITE = 0x01, - USB_FUNC_I2C_MULTIWRITE = 0x02, - USB_FUNC_I2C_READ = 0x03, - USB_FUNC_I2C_REPEATWRITE = 0x04, - USB_FUNC_GET_DESCRIPTOR = 0x05, - USB_FUNC_I2C_REPEATREAD = 0x06, -/* DKT 020208 - add this to support special case of DiSEqC */ - USB_FUNC_I2C_CHECKWRITE = 0x07, - USB_FUNC_I2C_CHECKRESULT = 0x08, -} b2c2_usb_i2c_function_t; - -/* - * function definition for UTILITY request 0x12 - * DKT 020304 - new utility function - */ -typedef enum { - UTILITY_SET_FILTER = 0x01, - UTILITY_DATA_ENABLE = 0x02, - UTILITY_FLEX_MULTIWRITE = 0x03, - UTILITY_SET_BUFFER_SIZE = 0x04, - UTILITY_FLEX_OPERATOR = 0x05, - UTILITY_FLEX_RESET300_START = 0x06, - UTILITY_FLEX_RESET300_STOP = 0x07, - UTILITY_FLEX_RESET300 = 0x08, - UTILITY_SET_ISO_SIZE = 0x09, - UTILITY_DATA_RESET = 0x0A, - UTILITY_GET_DATA_STATUS = 0x10, - UTILITY_GET_V8_REG = 0x11, -/* DKT 020326 - add function for v1.14 */ - UTILITY_SRAM_WRITE = 0x12, - UTILITY_SRAM_READ = 0x13, - UTILITY_SRAM_TESTFILL = 0x14, - UTILITY_SRAM_TESTSET = 0x15, - UTILITY_SRAM_TESTVERIFY = 0x16, -} b2c2_usb_utility_function_t; - -#define B2C2_WAIT_FOR_OPERATION_RW 1 // 1 s -#define B2C2_WAIT_FOR_OPERATION_RDW 3 // 3 s -#define B2C2_WAIT_FOR_OPERATION_WDW 1 // 1 s - -#define B2C2_WAIT_FOR_OPERATION_V8READ 3 // 3 s -#define B2C2_WAIT_FOR_OPERATION_V8WRITE 3 // 3 s -#define B2C2_WAIT_FOR_OPERATION_V8FLASH 3 // 3 s - -/* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits - * in the IBI address, to make the V8 code simpler. - * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (these are the six bits used) - * in general: 0000 0HHH 000L LL00 - * IBI ADDRESS FORMAT: RHHH BLLL - * - * where R is the read(1)/write(0) bit, B is the busy bit - * and HHH and LLL are the two sets of three bits from the PCI address. - */ -#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70)) -#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4)) - -/* - * DKT 020228 - forget about this VENDOR_BUFFER_SIZE, read and write register - * deal with DWORD or 4 bytes, that should be should from now on - */ -static u32 b2c2_usb_read_dw(struct usb_b2c2_usb *b2c2, u16 wRegOffsPCI) -{ - u32 val; - u16 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) | 0x0080; - int len = usb_control_msg(b2c2->udev, - B2C2_USB_CTRL_PIPE_IN, - B2C2_USB_READ_REG, - RTYPE_READ_DW, - wAddress, - 0, - &val, - sizeof(u32), - B2C2_WAIT_FOR_OPERATION_RDW * 1000); - - if (len != sizeof(u32)) { - err("error while reading dword from %d (%d).",wAddress,wRegOffsPCI); - return -EIO; - } else - return val; -} - -/* - * DKT 020228 - from now on, we don't support anything older than firm 1.00 - * I eliminated the write register as a 2 trip of writing hi word and lo word - * and force this to write only 4 bytes at a time. - * NOTE: this should work with all the firmware from 1.00 and newer - */ -static int b2c2_usb_write_dw(struct usb_b2c2_usb *b2c2, u16 wRegOffsPCI, u32 val) -{ - u16 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI); - int len = usb_control_msg(b2c2->udev, - B2C2_USB_CTRL_PIPE_OUT, - B2C2_USB_WRITE_REG, - RTYPE_WRITE_DW_1, - wAddress, - 0, - &val, - sizeof(u32), - B2C2_WAIT_FOR_OPERATION_RDW * 1000); - - if (len != sizeof(u32)) { - err("error while reading dword from %d (%d).",wAddress,wRegOffsPCI); - return -EIO; - } else - return 0; -} - -/* - * DKT 010817 - add support for V8 memory read/write and flash update - */ -static int b2c2_usb_v8_memory_req(struct usb_b2c2_usb *b2c2, - b2c2_usb_request_t req, u8 page, u16 wAddress, - u16 buflen, u8 *pbBuffer) -{ - u8 dwRequestType; - u16 wIndex; - int nWaitTime,pipe,len; - - wIndex = page << 8; - - switch (req) { - case B2C2_USB_READ_V8_MEM: - nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ; - dwRequestType = (u8) RTYPE_READ_V8_MEMORY; - pipe = B2C2_USB_CTRL_PIPE_IN; - break; - case B2C2_USB_WRITE_V8_MEM: - wIndex |= pbBuffer[0]; - nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE; - dwRequestType = (u8) RTYPE_WRITE_V8_MEMORY; - pipe = B2C2_USB_CTRL_PIPE_OUT; - break; - case B2C2_USB_FLASH_BLOCK: - nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH; - dwRequestType = (u8) RTYPE_WRITE_V8_FLASH; - pipe = B2C2_USB_CTRL_PIPE_OUT; - break; - default: - deb_info("unsupported request for v8_mem_req %x.\n",req); - return -EINVAL; - } - len = usb_control_msg(b2c2->udev,pipe, - req, - dwRequestType, - wAddress, - wIndex, - pbBuffer, - buflen, - nWaitTime * 1000); - return len == buflen ? 0 : -EIO; -} - -static int b2c2_usb_i2c_req(struct usb_b2c2_usb *b2c2, - b2c2_usb_request_t req, b2c2_usb_i2c_function_t func, - u8 port, u8 chipaddr, u8 addr, u8 buflen, u8 *buf) -{ - u16 wValue, wIndex; - int nWaitTime,pipe,len; - u8 dwRequestType; - - switch (func) { - case USB_FUNC_I2C_WRITE: - case USB_FUNC_I2C_MULTIWRITE: - case USB_FUNC_I2C_REPEATWRITE: - /* DKT 020208 - add this to support special case of DiSEqC */ - case USB_FUNC_I2C_CHECKWRITE: - pipe = B2C2_USB_CTRL_PIPE_OUT; - nWaitTime = 2; - dwRequestType = (u8) RTYPE_GENERIC; - break; - case USB_FUNC_I2C_READ: - case USB_FUNC_I2C_REPEATREAD: - pipe = B2C2_USB_CTRL_PIPE_IN; - nWaitTime = 2; - dwRequestType = (u8) RTYPE_GENERIC; - break; - default: - deb_info("unsupported function for i2c_req %x\n",func); - return -EINVAL; - } - wValue = (func << 8 ) | port; - wIndex = (chipaddr << 8 ) | addr; - - len = usb_control_msg(b2c2->udev,pipe, - req, - dwRequestType, - addr, - wIndex, - buf, - buflen, - nWaitTime * 1000); - return len == buflen ? 0 : -EIO; -} - -int static b2c2_usb_utility_req(struct usb_b2c2_usb *b2c2, int set, - b2c2_usb_utility_function_t func, u8 extra, u16 wIndex, - u16 buflen, u8 *pvBuffer) -{ - u16 wValue; - int nWaitTime = 2, - pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN, - len; - - wValue = (func << 8) | extra; - - len = usb_control_msg(b2c2->udev,pipe, - B2C2_USB_UTILITY, - (u8) RTYPE_GENERIC, - wValue, - wIndex, - pvBuffer, - buflen, - nWaitTime * 1000); - return len == buflen ? 0 : -EIO; -} - - - -static void b2c2_dumpfourreg(struct usb_b2c2_usb *b2c2, u16 offs) -{ - u32 r0,r1,r2,r3; - r0 = r1 = r2 = r3 = 0; - r0 = b2c2_usb_read_dw(b2c2,offs); - r1 = b2c2_usb_read_dw(b2c2,offs + 0x04); - r2 = b2c2_usb_read_dw(b2c2,offs + 0x08); - r3 = b2c2_usb_read_dw(b2c2,offs + 0x0c); - deb_ctrl("dump: offset: %03x, %08x, %08x, %08x, %08x\n",offs,r0,r1,r2,r3); -} - -static void b2c2_urb_complete(struct urb *urb, struct pt_regs *ptregs) -{ - struct usb_b2c2_usb *b2c2 = urb->context; - deb_ts("urb completed, bufsize: %d\n",urb->transfer_buffer_length); - -// urb_submit_urb(urb,GFP_ATOMIC); enable for real action -} - -static void b2c2_exit_usb(struct usb_b2c2_usb *b2c2) -{ - int i; - for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) - if (b2c2->iso_urb[i] != NULL) { /* not sure about unlink_urb and iso-urbs TODO */ - deb_info("unlinking/killing urb no. %d\n",i); -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,7) - usb_unlink_urb(b2c2->iso_urb[i]); -#else - usb_kill_urb(b2c2->iso_urb[i]); -#endif - usb_free_urb(b2c2->iso_urb[i]); - } - - if (b2c2->iso_buffer != NULL) - pci_free_consistent(NULL,b2c2->buffer_size, b2c2->iso_buffer, b2c2->iso_dma_handle); - -} - -static int b2c2_init_usb(struct usb_b2c2_usb *b2c2) -{ - u16 frame_size = le16_to_cpu(b2c2->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize); - int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * frame_size,i,j,ret; - int buffer_offset = 0; - - deb_info("creating %d iso-urbs with %d frames each of %d bytes size = %d.\n", - B2C2_USB_NUM_ISO_URB, B2C2_USB_FRAMES_PER_ISO, frame_size,bufsize); - - b2c2->iso_buffer = pci_alloc_consistent(NULL,bufsize,&b2c2->iso_dma_handle); - if (b2c2->iso_buffer == NULL) - return -ENOMEM; - memset(b2c2->iso_buffer, 0, bufsize); - b2c2->buffer_size = bufsize; - - /* creating iso urbs */ - for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) - if (!(b2c2->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,GFP_ATOMIC))) { - ret = -ENOMEM; - goto urb_error; - } - /* initialising and submitting iso urbs */ - for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) { - int frame_offset = 0; - struct urb *urb = b2c2->iso_urb[i]; - deb_info("initializing and submitting urb no. %d (buf_offset: %d).\n",i,buffer_offset); - - urb->dev = b2c2->udev; - urb->context = b2c2; - urb->complete = b2c2_urb_complete; - urb->pipe = B2C2_USB_DATA_PIPE; - urb->transfer_flags = URB_ISO_ASAP; - urb->interval = 1; - urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO; - urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO; - urb->transfer_buffer = b2c2->iso_buffer + buffer_offset; - - buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO; - for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) { - deb_info("urb no: %d, frame: %d, frame_offset: %d\n",i,j,frame_offset); - urb->iso_frame_desc[j].offset = frame_offset; - urb->iso_frame_desc[j].length = frame_size; - frame_offset += frame_size; - } - - if ((ret = usb_submit_urb(b2c2->iso_urb[i],GFP_ATOMIC))) { - err("submitting urb %d failed with %d.",i,ret); - goto urb_error; - } - deb_info("submitted urb no. %d.\n",i); - } - - ret = 0; - goto success; -urb_error: - b2c2_exit_usb(b2c2); -success: - return ret; -} - -static int b2c2_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct usb_b2c2_usb *b2c2 = NULL; - int ret; - - b2c2 = kmalloc(sizeof(struct usb_b2c2_usb),GFP_KERNEL); - if (b2c2 == NULL) { - err("no memory"); - return -ENOMEM; - } - b2c2->udev = udev; - b2c2->uintf = intf; - - /* use the alternate setting with the larges buffer */ - usb_set_interface(udev,0,1); - - if ((ret = b2c2_init_usb(b2c2))) - goto usb_init_error; - - usb_set_intfdata(intf,b2c2); - - switch (udev->speed) { - case USB_SPEED_LOW: - err("cannot handle USB speed because it is to sLOW."); - break; - case USB_SPEED_FULL: - info("running at FULL speed."); - break; - case USB_SPEED_HIGH: - info("running at HIGH speed."); - break; - case USB_SPEED_UNKNOWN: /* fall through */ - default: - err("cannot handle USB speed because it is unkown."); - break; - } - - b2c2_dumpfourreg(b2c2,0x200); - b2c2_dumpfourreg(b2c2,0x300); - b2c2_dumpfourreg(b2c2,0x400); - b2c2_dumpfourreg(b2c2,0x700); - - - if (ret == 0) - info("%s successfully initialized and connected.",DRIVER_DESC); - else - info("%s error while loading driver (%d)",DRIVER_DESC,ret); - - ret = 0; - goto success; - -usb_init_error: - kfree(b2c2); -success: - return ret; -} - -static void b2c2_usb_disconnect(struct usb_interface *intf) -{ - struct usb_b2c2_usb *b2c2 = usb_get_intfdata(intf); - usb_set_intfdata(intf,NULL); - if (b2c2 != NULL) { - b2c2_exit_usb(b2c2); - kfree(b2c2); - } - info("%s successfully deinitialized and disconnected.",DRIVER_DESC); - -} - -static struct usb_device_id b2c2_usb_table [] = { - { USB_DEVICE(0x0af7, 0x0101) } -}; - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver b2c2_usb_driver = { - .owner = THIS_MODULE, - .name = "dvb_b2c2_usb", - .probe = b2c2_usb_probe, - .disconnect = b2c2_usb_disconnect, - .id_table = b2c2_usb_table, -}; - -/* module stuff */ -static int __init b2c2_usb_init(void) -{ - int result; - if ((result = usb_register(&b2c2_usb_driver))) { - err("usb_register failed. Error number %d",result); - return result; - } - - return 0; -} - -static void __exit b2c2_usb_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&b2c2_usb_driver); -} - -module_init (b2c2_usb_init); -module_exit (b2c2_usb_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(usb, b2c2_usb_table); -- cgit v1.2.3 From 2add87a95068d6457d4e5824d0417d39007665a4 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:10 -0700 Subject: [PATCH] dvb: b2c2/flexcop driver refactoring part 2: add modular Flexcop driver b2c2/flexcop driver refactoring to support PCI and USB based cards part 2: add modular Flexcop driver Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/dvb/README.flexcop | 279 ++++++++++++ drivers/media/dvb/Kconfig | 2 +- drivers/media/dvb/b2c2/Kconfig | 37 ++ drivers/media/dvb/b2c2/Makefile | 11 + drivers/media/dvb/b2c2/flexcop-common.h | 161 +++++++ drivers/media/dvb/b2c2/flexcop-dma.c | 149 ++++++ drivers/media/dvb/b2c2/flexcop-eeprom.c | 157 +++++++ drivers/media/dvb/b2c2/flexcop-fe-tuner.c | 403 +++++++++++++++++ drivers/media/dvb/b2c2/flexcop-hw-filter.c | 198 ++++++++ drivers/media/dvb/b2c2/flexcop-i2c.c | 204 +++++++++ drivers/media/dvb/b2c2/flexcop-misc.c | 66 +++ drivers/media/dvb/b2c2/flexcop-pci.c | 365 +++++++++++++++ drivers/media/dvb/b2c2/flexcop-reg.h | 700 +++++++++++++++++++++++++++++ drivers/media/dvb/b2c2/flexcop-sram.c | 403 +++++++++++++++++ drivers/media/dvb/b2c2/flexcop-usb.c | 530 ++++++++++++++++++++++ drivers/media/dvb/b2c2/flexcop-usb.h | 116 +++++ drivers/media/dvb/b2c2/flexcop.c | 288 ++++++++++++ drivers/media/dvb/b2c2/flexcop.h | 30 ++ 18 files changed, 4098 insertions(+), 1 deletion(-) create mode 100644 Documentation/dvb/README.flexcop create mode 100644 drivers/media/dvb/b2c2/flexcop-common.h create mode 100644 drivers/media/dvb/b2c2/flexcop-dma.c create mode 100644 drivers/media/dvb/b2c2/flexcop-eeprom.c create mode 100644 drivers/media/dvb/b2c2/flexcop-fe-tuner.c create mode 100644 drivers/media/dvb/b2c2/flexcop-hw-filter.c create mode 100644 drivers/media/dvb/b2c2/flexcop-i2c.c create mode 100644 drivers/media/dvb/b2c2/flexcop-misc.c create mode 100644 drivers/media/dvb/b2c2/flexcop-pci.c create mode 100644 drivers/media/dvb/b2c2/flexcop-reg.h create mode 100644 drivers/media/dvb/b2c2/flexcop-sram.c create mode 100644 drivers/media/dvb/b2c2/flexcop-usb.c create mode 100644 drivers/media/dvb/b2c2/flexcop-usb.h create mode 100644 drivers/media/dvb/b2c2/flexcop.c create mode 100644 drivers/media/dvb/b2c2/flexcop.h diff --git a/Documentation/dvb/README.flexcop b/Documentation/dvb/README.flexcop new file mode 100644 index 00000000000..9ec735714e4 --- /dev/null +++ b/Documentation/dvb/README.flexcop @@ -0,0 +1,279 @@ +This README escorted the skystar2-driver rewriting procedure. It describes the +state of the new flexcop-driver set and some internals are written down here +too. + +How to do something in here? +============================ + +make -f Makefile.t +make -C ../build-2.6 +./in.sh # load the drivers +./rm.sh # unload the drivers + +Please read this file, if you want to contribute. + +This document hopefully describes things about the flexcop and its +device-offsprings. Goal is to write a easy-to-write and easy-to-read set of +drivers based on the skystar2.c and other information. + +This directory is temporary. It is used for rewriting the skystar2.c and to +create shared code, which then can be used by the usb box as well. + +Remark: flexcop-pci.c was a copy of skystar2.c, but every line has been +touched and rewritten. + +General coding processing +========================= + +We should proceed as follows (as long as no one complains): + +0) Think before start writing code! + +1) rewriting the skystar2.c with the help of the flexcop register descriptions +and splitting up the files to a pci-bus-part and a flexcop-part. +The new driver will be called b2c2-flexcop-pci.ko/b2c2-flexcop-usb.ko for the +device-specific part and b2c2-flexcop.ko for the common flexcop-functions. + +2) Search for errors in the leftover of flexcop-pci.c (compare with pluto2.c +and other pci drivers) + +3) make some beautification (see 'Improvements when rewriting (refactoring) is +done') + +4) Testing the new driver and maybe substitute the skystar2.c with it, to reach +a wider tester audience. + +5) creating an usb-bus-part using the already written flexcop code for the pci +card. + +Idea: create a kernel-object for the flexcop and export all important +functions. This option saves kernel-memory, but maybe a lot of functions have +to be exported to kernel namespace. + + +Current situation +================= + +0) Done :) +1) Done (some minor issues left) +2) Done +3) Not ready yet, more information is necessary +4) next to be done (see the table below) +5) USB driver is working (yes, there are some minor issues) + +What seems to be ready? +----------------------- + +1) Rewriting +1a) i2c is cut off from the flexcop-pci.c and seems to work +1b) moved tuner and demod stuff from flexcop-pci.c to flexcop-tuner-fe.c +1c) moved lnb and diseqc stuff from flexcop-pci.c to flexcop-tuner-fe.c +1e) eeprom (reading MAC address) +1d) sram (no dynamic sll size detection (commented out) (using default as JJ told me)) +1f) misc. register accesses for reading parameters (e.g. resetting, revision) +1g) pid/mac filter (flexcop-hw-filter.c) +1i) dvb-stuff initialization in flexcop.c (done) +1h) dma stuff (now just using the size-irq, instead of all-together, to be done) +1j) remove flexcop initialization from flexcop-pci.c completely (done) +1l) use a well working dma IRQ method (done, see 'Known bugs and problems and TODO') +1k) cleanup flexcop-files (remove unused EXPORT_SYMBOLs, make static from +non-static where possible, moved code to proper places) + +2) Search for errors in the leftover of flexcop-pci.c (partially done) +5a) add MAC address reading + +What to do in the near future? +-------------------------------------- +(no special order here) + + +5) USB driver +5b) optimize isoc-transfer (submitting/killing isoc URBs when transfer is starting) +5c) feeding of ISOC data to the software demux (format of the isochronous data +and speed optimization, no real error) + +Testing changes +--------------- + +O = item is working +P = item is partially working +X = item is not working +N = item does not apply here + = item need to be examined + + | PCI | USB +item | mt352 | nxt2002 | stv0299 | mt312 | mt352 | nxt2002 | stv0299 | mt312 +-------+-------+---------+---------+-------+-------+---------+---------+------- +1a) | O | | | | N | N | N | N +1b) | O | | | | | | O | +1c) | N | N | | | N | N | O | +1d) | O | O +1e) | O | O +1f) | P +1g) | O +1h) | P | +1i) | O | N +1j) | O | N +1l) | O | N +2) | O | N +5a) | N | O +5b)* | N | +5c)* | N | + +* - not done yet + +Known bugs and problems and TODO +-------------------------------- + +1g/h/l) when pid filtering is enabled on the pci card + +DMA usage currently: + The DMA is splitted in 2 equal-sized subbuffers. The Flexcop writes to first + address and triggers an IRQ when it's full and starts writing to the second + address. When the second address is full, the IRQ is triggered again, and + the flexcop writes to first address again, and so on. + The buffersize of each address is currently 640*188 bytes. + + Problem is, when using hw-pid-filtering and doing some low-bandwidth + operation (like scanning) the buffers won't be filled enough to trigger + the IRQ. That's why: + + When PID filtering is activated, the timer IRQ is used. Every 1.97 ms the IRQ + is triggered. Is the current write address of DMA1 different to the one + during the last IRQ, then the data is passed to the demuxer. + + There is an additional DMA-IRQ-method: packet count IRQ. This isn't + implemented correctly yet. + + The solution is to disable HW PID filtering, but I don't know how the DVB + API software demux behaves on slow systems with 45MBit/s TS. + +Solved bugs :) +-------------- +1g) pid-filtering (somehow pid index 4 and 5 (EMM_PID and ECM_PID) aren't +working) +SOLUTION: also index 0 was affected, because net_translation is done for +these indexes by default + +5b) isochronous transfer does only work in the first attempt (for the Sky2PC USB, +Air2PC is working) +SOLUTION: the flexcop was going asleep and never really woke up again (don't +know if this need fixes, see flexcop-fe-tuner.c:flexcop_sleep) + +Improvements when rewriting (refactoring) is done +================================================= + +- split sleeping of the flexcop (misc_204.ACPI3_sig = 1;) from lnb_control + (enable sleeping for other demods than dvb-s) +- add support for CableStar (stv0297 Microtune 203x/ALPS) + +Debugging +--------- +- add verbose debugging to skystar2.c (dump the reg_dw_data) and compare it + with this flexcop, this is important, because i2c is now using the + flexcop_ibi_value union from flexcop-reg.h (do you have a better idea for + that, please tell us so). + +Everything which is identical in the following table, can be put into a common +flexcop-module. + + PCI USB +------------------------------------------------------------------------------- +Different: +Register access: accessing IO memory USB control message +I2C bus: I2C bus of the FC USB control message +Data transfer: DMA isochronous transfer +EEPROM transfer: through i2c bus not clear yet + +Identical: +Streaming: accessing registers +PID Filtering: accessing registers +Sram destinations: accessing registers +Tuner/Demod: I2C bus +DVB-stuff: can be written for common use + +Restrictions: +============ + +We need to create a bus-specific-struct and a flexcop-struct. + +bus-specific-struct: + +struct flexcop_pci +... + +struct flexcop_usb +... + + +struct flexcop_device { + void *bus_specific; /* container for bus-specific struct */ +... +} + +PCI i2c can read/write max 4 bytes at a time, USB can more + +Functions +========= + +Syntax +------ + +- Flexcop functions will be called "flexcop(_[a-z0-9]+)+" and exported as such + if needed. +- Flexcop-device functions will be called "flexcop_device(_[a-z0-9]+)+" and + exported as such if needed. +- Both will be compiled to b2c2-flexcop.ko and their source can be found in the + flexcop*.[hc] + +Callbacks and exports +--------------------- + +Bus-specific functions will be given as callbacks (function pointers) to the +flexcop-module. (within the flexcop_device-struct) + +Initialization process +====================== + +b2c2-flexcop.ko is loaded +b2c2-flexcop-.ko is loaded + +suppose a device is found: +malloc flexcop and the bus-specific variables (via flexcop_device_malloc) +fill the bus-specific variable +fill the flexcop variable (especially the bus-specific callbacks) +bus-specific initialization + - ... +do the common initialization (via flexcop_device_initialize) + - reset the card + - determine flexcop type (II, IIB, III) + - hw_filters (bus dependent) + - 0x204 + - set sram size + - create the dvb-stuff + - create i2c stuff + - frontend-initialization +done +bus specific: + - media_destination (this and the following 3 are bus specific) + - cai_dest + - cao_dest + - net_destination + +Bugs fixed while rewriting the driver +===================================== + +- EEPROM access (to read the MAC address) was fixed to death some time last + year. (fixed here and in skystar2.c) (Bjarne, this was the piece of code + (fix-chipaddr) we were wondering about) + + +Acknowledgements (just for the rewriting part) +================ + +Bjarne Steinsbo thought a lot in the first place of the pci part for this code +sharing idea. + +Andreas Oberritter for providing a recent PCI initialization template (pluto2.c). + +comments, critics and ideas to linux-dvb@linuxtv.org or patrick.boettcher@desy.de diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 883ec08490f..4983e1b1bb1 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -33,7 +33,7 @@ source "drivers/media/dvb/dibusb/Kconfig" source "drivers/media/dvb/cinergyT2/Kconfig" comment "Supported FlexCopII (B2C2) Adapters" - depends on DVB_CORE && PCI + depends on DVB_CORE && (PCI || USB) source "drivers/media/dvb/b2c2/Kconfig" comment "Supported BT878 Adapters" diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig index f1f6187b7c1..99bd675df95 100644 --- a/drivers/media/dvb/b2c2/Kconfig +++ b/drivers/media/dvb/b2c2/Kconfig @@ -1,3 +1,40 @@ +config DVB_B2C2_FLEXCOP + tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters" + depends on DVB_CORE + select DVB_STV0299 + select DVB_MT352 + select DVB_MT312 + select DVB_NXT2002 + select DVB_STV0297 + help + Support for the digital TV receiver chip made by B2C2 Inc. included in + Technisats PCI cards and USB boxes. + + Say Y if you own such a device and want to use it. + +config DVB_B2C2_FLEXCOP_PCI + tristate "Technisat/B2C2 Air/Sky/Cable2PC PCI" + depends on DVB_B2C2_FLEXCOP && PCI + help + Support for the Air/Sky/CableStar2 PCI card (DVB/ATSC) by Technisat/B2C2. + + Say Y if you own such a device and want to use it. + +config DVB_B2C2_FLEXCOP_USB + tristate "Technisat/B2C2 Air/Sky/Cable2PC USB" + depends on DVB_B2C2_FLEXCOP && USB + help + Support for the Air/Sky/Cable2PC USB1.1 box (DVB/ATSC) by Technisat/B2C2, + + Say Y if you own such a device and want to use it. + +config DVB_B2C2_FLEXCOP_DEBUG + bool "Enable debug for the B2C2 FlexCop drivers" + depends on DVB_B2C2_FLEXCOP + help + Say Y if you want to enable the module option to control debug messages + of all B2C2 FlexCop drivers. + config DVB_B2C2_SKYSTAR tristate "B2C2/Technisat Air/Sky/CableStar 2 PCI" depends on DVB_CORE && PCI diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile index f9cdc6f052d..7703812af34 100644 --- a/drivers/media/dvb/b2c2/Makefile +++ b/drivers/media/dvb/b2c2/Makefile @@ -1,3 +1,14 @@ +b2c2-flexcop-objs = flexcop.o flexcop-fe-tuner.o flexcop-i2c.o \ + flexcop-sram.o flexcop-eeprom.o flexcop-misc.o flexcop-hw-filter.o \ + flexcop-dma.o +obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o + +b2c2-flexcop-pci-objs = flexcop-pci.o +obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o + +b2c2-flexcop-usb-objs = flexcop-usb.o +obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o + obj-$(CONFIG_DVB_B2C2_SKYSTAR) += skystar2.o EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h new file mode 100644 index 00000000000..82b7f8fa7b9 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-common.h @@ -0,0 +1,161 @@ +/* + * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * flexcop-common.h - common header file for device-specific source files also. + * + * see flexcop.c for copyright information. + */ +#ifndef __FLEXCOP_COMMON_H__ +#define __FLEXCOP_COMMON_H__ + +#include +#include + +#include "flexcop-reg.h" + +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_filter.h" +#include "dvb_net.h" +#include "dvb_frontend.h" + +#define FC_MAX_FEED 256 + +#ifndef FC_LOG_PREFIX +#warning please define a log prefix for your file, using a default one +#define FC_LOG_PREFIX "b2c2-undef" +#endif + +/* Steal from usb.h */ +#undef err +#define err(format, arg...) printk(KERN_ERR FC_LOG_PREFIX ": " format "\n" , ## arg) +#undef info +#define info(format, arg...) printk(KERN_INFO FC_LOG_PREFIX ": " format "\n" , ## arg) +#undef warn +#define warn(format, arg...) printk(KERN_WARNING FC_LOG_PREFIX ": " format "\n" , ## arg) + +struct flexcop_dma { + struct pci_dev *pdev; + + u8 *cpu_addr0; + dma_addr_t dma_addr0; + u8 *cpu_addr1; + dma_addr_t dma_addr1; + u32 size; /* size of each address in bytes */ +}; + +/* Control structure for data definitions that are common to + * the B2C2-based PCI and USB devices. + */ +struct flexcop_device { + /* general */ + struct device *dev; /* for firmware_class */ + +#define FC_STATE_DVB_INIT 0x01 +#define FC_STATE_I2C_INIT 0x02 +#define FC_STATE_FE_INIT 0x04 + int init_state; + + /* device information */ + u8 mac_address[6]; + int has_32_hw_pid_filter; + flexcop_revision_t rev; + flexcop_device_type_t dev_type; + flexcop_bus_t bus_type; + + /* dvb stuff */ + struct dvb_adapter dvb_adapter; + struct dvb_frontend *fe; + struct dvb_net dvbnet; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + int (*fe_sleep) (struct dvb_frontend *); + + struct i2c_adapter i2c_adap; + struct semaphore i2c_sem; + + /* options and status */ + int feedcount; + int pid_filtering; + + /* bus specific callbacks */ + flexcop_ibi_value (*read_ibi_reg) (struct flexcop_device *, flexcop_ibi_register); + int (*write_ibi_reg) (struct flexcop_device *, flexcop_ibi_register, flexcop_ibi_value); + + + int (*i2c_request) (struct flexcop_device*, flexcop_access_op_t, flexcop_i2c_port_t, u8 chipaddr, u8 addr, u8 *buf, u16 len); + int (*stream_control) (struct flexcop_device*, int); + + int (*get_mac_addr) (struct flexcop_device *fc, int extended); + + void *bus_specific; +}; + +/* exported prototypes */ + +/* from flexcop.c */ +void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len); +void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no); + +struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len); +void flexcop_device_kfree(struct flexcop_device*); + +int flexcop_device_initialize(struct flexcop_device*); +void flexcop_device_exit(struct flexcop_device *fc); + +/* from flexcop-dma.c */ +int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size); +void flexcop_dma_free(struct flexcop_dma *dma); + +int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff); +int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff); +int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff); +int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index); +int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles); +int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets); + +/* from flexcop-eeprom.c */ +/* the PCI part uses this call to get the MAC address, the USB part has its own */ +int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended); + +/* from flexcop-i2c.c */ +/* the PCI part uses this a i2c_request callback, whereas the usb part has its own + * one. We have it in flexcop-i2c.c, because it is going via the actual + * I2C-channel of the flexcop. + */ +int flexcop_i2c_request(struct flexcop_device*, flexcop_access_op_t, + flexcop_i2c_port_t, u8 chipaddr, u8 addr, u8 *buf, u16 len); + +/* from flexcop-sram.c */ +int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target); +void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s); +void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill); + +/* global prototypes for the flexcop-chip */ +/* from flexcop-fe-tuner.c */ +int flexcop_frontend_init(struct flexcop_device *card); +void flexcop_frontend_exit(struct flexcop_device *fc); + +/* from flexcop-i2c.c */ +int flexcop_i2c_init(struct flexcop_device *fc); +void flexcop_i2c_exit(struct flexcop_device *fc); + +/* from flexcop-sram.c */ +int flexcop_sram_init(struct flexcop_device *fc); + +/* from flexcop-misc.c */ +void flexcop_determine_revision(struct flexcop_device *fc); +void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const char *suffix); + +/* from flexcop-hw-filter.c */ +int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff); +void flexcop_hw_filter_init(struct flexcop_device *fc); + +void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff); + +void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]); +void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff); + +#endif diff --git a/drivers/media/dvb/b2c2/flexcop-dma.c b/drivers/media/dvb/b2c2/flexcop-dma.c new file mode 100644 index 00000000000..8d270607536 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-dma.c @@ -0,0 +1,149 @@ +/* + * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * flexcop-dma.c - methods for configuring and controlling the DMA of the FlexCop. + * + * see flexcop.c for copyright information. + */ +#include "flexcop.h" + +int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size) +{ + u8 *tcpu; + dma_addr_t tdma; + + if (size % 2) { + err("dma buffersize has to be even."); + return -EINVAL; + } + + if ((tcpu = pci_alloc_consistent(pdev, size, &tdma)) != NULL) { + dma->pdev = pdev; + dma->cpu_addr0 = tcpu; + dma->dma_addr0 = tdma; + dma->cpu_addr1 = tcpu + size/2; + dma->dma_addr1 = tdma + size/2; + dma->size = size/2; + return 0; + } + return -ENOMEM; +} +EXPORT_SYMBOL(flexcop_dma_allocate); + +void flexcop_dma_free(struct flexcop_dma *dma) +{ + pci_free_consistent(dma->pdev, dma->size*2,dma->cpu_addr0, dma->dma_addr0); + memset(dma,0,sizeof(struct flexcop_dma)); +} +EXPORT_SYMBOL(flexcop_dma_free); + +int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff) +{ + flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); + + if (no & FC_DMA_1) + v.ctrl_208.DMA1_Timer_Enable_sig = onoff; + + if (no & FC_DMA_2) + v.ctrl_208.DMA2_Timer_Enable_sig = onoff; + + fc->write_ibi_reg(fc,ctrl_208,v); + return 0; +} +EXPORT_SYMBOL(flexcop_dma_control_timer_irq); + +int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff) +{ + flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); + + if (no & FC_DMA_1) + v.ctrl_208.DMA1_IRQ_Enable_sig = onoff; + + if (no & FC_DMA_2) + v.ctrl_208.DMA2_IRQ_Enable_sig = onoff; + + fc->write_ibi_reg(fc,ctrl_208,v); + return 0; +} +EXPORT_SYMBOL(flexcop_dma_control_size_irq); + +int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff) +{ + flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); + + if (no & FC_DMA_1) + v.ctrl_208.DMA1_Size_IRQ_Enable_sig = onoff; + + if (no & FC_DMA_2) + v.ctrl_208.DMA2_Size_IRQ_Enable_sig = onoff; + + fc->write_ibi_reg(fc,ctrl_208,v); + return 0; +} +EXPORT_SYMBOL(flexcop_dma_control_packet_irq); + +int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index) +{ + + flexcop_ibi_value v0x0,v0x4,v0xc; + v0x0.raw = v0x4.raw = v0xc.raw = 0; + + v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2; + v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2; + v0x4.dma_0x4_write.dma_addr_size = dma->size / 4; + + if (index & FC_DMA_SUBADDR_0) + v0x0.dma_0x0.dma_0start = 1; + + if (index & FC_DMA_SUBADDR_1) + v0xc.dma_0xc.dma_1start = 1; + + if (dma_idx & FC_DMA_1) { + fc->write_ibi_reg(fc,dma1_000,v0x0); + fc->write_ibi_reg(fc,dma1_004,v0x4); + fc->write_ibi_reg(fc,dma1_00c,v0xc); + } else { /* (dma_idx & FC_DMA_2) */ + fc->write_ibi_reg(fc,dma2_010,v0x0); + fc->write_ibi_reg(fc,dma2_014,v0x4); + fc->write_ibi_reg(fc,dma2_01c,v0xc); + } + + return 0; +} +EXPORT_SYMBOL(flexcop_dma_config); + +static int flexcop_dma_remap(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, int onoff) +{ + flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c; + flexcop_ibi_value v = fc->read_ibi_reg(fc,r); + v.dma_0xc.remap_enable = onoff; + fc->write_ibi_reg(fc,r,v); + return 0; +} + +/* 1 cycles = 1.97 msec */ +int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles) +{ + flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014; + flexcop_ibi_value v = fc->read_ibi_reg(fc,r); + + flexcop_dma_remap(fc,dma_idx,0); + + v.dma_0x4_write.dmatimer = cycles >> 1; + fc->write_ibi_reg(fc,r,v); + return 0; +} +EXPORT_SYMBOL(flexcop_dma_config_timer); + +int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets) +{ + flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014; + flexcop_ibi_value v = fc->read_ibi_reg(fc,r); + + flexcop_dma_remap(fc,dma_idx,1); + + v.dma_0x4_remap.DMA_maxpackets = packets; + fc->write_ibi_reg(fc,r,v); + return 0; +} +EXPORT_SYMBOL(flexcop_dma_config_packet_count); diff --git a/drivers/media/dvb/b2c2/flexcop-eeprom.c b/drivers/media/dvb/b2c2/flexcop-eeprom.c new file mode 100644 index 00000000000..4dbedd81973 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-eeprom.c @@ -0,0 +1,157 @@ +/* + * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * flexcop-eeprom.c - eeprom access methods (currently only MAC address reading is used) + * + * see flexcop.c for copyright information. + */ +#include "flexcop.h" + +#if 0 +/*EEPROM (Skystar2 has one "24LC08B" chip on board) */ +static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len) +{ + return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len); +} + +static int eeprom_lrc_write(struct adapter *adapter, u32 addr, u32 len, u8 *wbuf, u8 *rbuf, int retries) +{ + int i; + + for (i = 0; i < retries; i++) { + if (eeprom_write(adapter, addr, wbuf, len) == len) { + if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1) + return 1; + } + } + + return 0; +} + +/* These functions could be used to unlock SkyStar2 cards. */ + +static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len) +{ + u8 rbuf[20]; + u8 wbuf[20]; + + if (len != 16) + return 0; + + memcpy(wbuf, key, len); + + wbuf[16] = 0; + wbuf[17] = 0; + wbuf[18] = 0; + wbuf[19] = calc_lrc(wbuf, 19); + + return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4); +} + +static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len) +{ + u8 buf[20]; + + if (len != 16) + return 0; + + if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0) + return 0; + + memcpy(key, buf, len); + + return 1; +} + +static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac) +{ + u8 tmp[8]; + + if (type != 0) { + tmp[0] = mac[0]; + tmp[1] = mac[1]; + tmp[2] = mac[2]; + tmp[3] = mac[5]; + tmp[4] = mac[6]; + tmp[5] = mac[7]; + + } else { + + tmp[0] = mac[0]; + tmp[1] = mac[1]; + tmp[2] = mac[2]; + tmp[3] = mac[3]; + tmp[4] = mac[4]; + tmp[5] = mac[5]; + } + + tmp[6] = 0; + tmp[7] = calc_lrc(tmp, 7); + + if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8) + return 1; + + return 0; +} + +static int flexcop_eeprom_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len) +{ + return fc->i2c_request(fc,FC_READ,FC_I2C_PORT_EEPROM,0x50,addr,buf,len); +} + +#endif + +static u8 calc_lrc(u8 *buf, int len) +{ + int i; + u8 sum = 0; + for (i = 0; i < len; i++) + sum = sum ^ buf[i]; + return sum; +} + +static int flexcop_eeprom_request(struct flexcop_device *fc, flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries) +{ + int i,ret = 0; + u8 chipaddr = 0x50 | ((addr >> 8) & 3); + for (i = 0; i < retries; i++) + if ((ret = fc->i2c_request(fc,op,FC_I2C_PORT_EEPROM,chipaddr,addr & 0xff,buf,len)) == 0) + break; + return ret; +} + +static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len, int retries) +{ + int ret = flexcop_eeprom_request(fc,FC_READ,addr,buf,len,retries); + if (ret == 0) + if (calc_lrc(buf, len - 1) != buf[len - 1]) + ret = -EINVAL; + return ret; +} + +/* TODO how is it handled in USB */ + +/* JJ's comment about extended == 1: it is not presently used anywhere but was + * added to the low-level functions for possible support of EUI64 + */ +int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended) +{ + u8 buf[8]; + int ret = 0; + + memset(fc->mac_address,0,6); + + if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) { + if (extended != 0) { + err("TODO: extended (EUI64) MAC addresses aren't completely supported yet"); + ret = -EINVAL; +/* memcpy(fc->mac_address,buf,3); + mac[3] = 0xfe; + mac[4] = 0xff; + memcpy(&fc->mac_address[3],&buf[5],3); */ + } else + memcpy(fc->mac_address,buf,6); + } + return ret; +} +EXPORT_SYMBOL(flexcop_eeprom_check_mac_addr); diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c new file mode 100644 index 00000000000..b3dd16fb5bb --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -0,0 +1,403 @@ +/* + * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * flexcop-fe-tuner.c - methods for attaching a frontend and controlling DiSEqC. + * + * see flexcop.c for copyright information. + */ +#include "flexcop.h" + +#include "stv0299.h" +#include "mt352.h" +#include "nxt2002.h" +#include "stv0297.h" +#include "mt312.h" + +/* lnb control */ + +static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct flexcop_device *fc = fe->dvb->priv; + flexcop_ibi_value v; + deb_tuner("polarity/voltage = %u\n", voltage); + + v = fc->read_ibi_reg(fc, misc_204); + switch (voltage) { + case SEC_VOLTAGE_OFF: + v.misc_204.ACPI1_sig = 1; + break; + case SEC_VOLTAGE_13: + v.misc_204.ACPI1_sig = 0; + v.misc_204.LNB_L_H_sig = 0; + break; + case SEC_VOLTAGE_18: + v.misc_204.ACPI1_sig = 0; + v.misc_204.LNB_L_H_sig = 1; + break; + default: + err("unknown SEC_VOLTAGE value"); + return -EINVAL; + } + return fc->write_ibi_reg(fc, misc_204, v); +} + +static int flexcop_sleep(struct dvb_frontend* fe) +{ + struct flexcop_device *fc = fe->dvb->priv; +/* flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); */ + + if (fc->fe_sleep) + return fc->fe_sleep(fe); + +/* v.misc_204.ACPI3_sig = 1; + fc->write_ibi_reg(fc,misc_204,v);*/ + + return 0; +} + +static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ + /* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */ + struct flexcop_device *fc = fe->dvb->priv; + flexcop_ibi_value v; + u16 ax; + v.raw = 0; + + deb_tuner("tone = %u\n",tone); + + switch (tone) { + case SEC_TONE_ON: + ax = 0x01ff; + break; + case SEC_TONE_OFF: + ax = 0; + break; + default: + err("unknown SEC_TONE value"); + return -EINVAL; + } + + v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */ + + v.lnb_switch_freq_200.LNB_CTLHighCount_sig = + v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax; + + return fc->write_ibi_reg(fc,lnb_switch_freq_200,v); +} + +static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data) +{ + flexcop_set_tone(fe, SEC_TONE_ON); + udelay(data ? 500 : 1000); + flexcop_set_tone(fe, SEC_TONE_OFF); + udelay(data ? 1000 : 500); +} + +static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data) +{ + int i, par = 1, d; + + for (i = 7; i >= 0; i--) { + d = (data >> i) & 1; + par ^= d; + flexcop_diseqc_send_bit(fe, d); + } + + flexcop_diseqc_send_bit(fe, par); +} + +static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, unsigned long burst) +{ + int i; + + flexcop_set_tone(fe, SEC_TONE_OFF); + mdelay(16); + + for (i = 0; i < len; i++) + flexcop_diseqc_send_byte(fe,msg[i]); + + mdelay(16); + + if (burst != -1) { + if (burst) + flexcop_diseqc_send_byte(fe, 0xff); + else { + flexcop_set_tone(fe, SEC_TONE_ON); + udelay(12500); + flexcop_set_tone(fe, SEC_TONE_OFF); + } + msleep(20); + } + return 0; +} + +static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +{ + return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0); +} + +static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +{ + return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd); +} + +/* dvb-s stv0299 */ +static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + + if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } + else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } + else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; } + else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; } + else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; } + else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; } + + stv0299_writereg (fe, 0x13, aclk); + stv0299_writereg (fe, 0x14, bclk); + stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg (fe, 0x21, (ratio ) & 0xf0); + + return 0; +} + +static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + u8 buf[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + struct flexcop_device *fc = fe->dvb->priv; + + div = params->frequency / 125; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x84; /* 0xC4 */ + buf[3] = 0x08; + + if (params->frequency < 1500000) buf[3] |= 0x10; + + if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static u8 samsung_tbmu24112_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7D, + 0x05, 0x35, + 0x06, 0x02, + 0x07, 0x00, + 0x08, 0xC3, + 0x0C, 0x00, + 0x0D, 0x81, + 0x0E, 0x23, + 0x0F, 0x12, + 0x10, 0x7E, + 0x11, 0x84, + 0x12, 0xB9, + 0x13, 0x88, + 0x14, 0x89, + 0x15, 0xC9, + 0x16, 0x00, + 0x17, 0x5C, + 0x18, 0x00, + 0x19, 0x00, + 0x1A, 0x00, + 0x1C, 0x00, + 0x1D, 0x00, + 0x1E, 0x00, + 0x1F, 0x3A, + 0x20, 0x2E, + 0x21, 0x80, + 0x22, 0xFF, + 0x23, 0xC1, + 0x28, 0x00, + 0x29, 0x1E, + 0x2A, 0x14, + 0x2B, 0x0F, + 0x2C, 0x09, + 0x2D, 0x05, + 0x31, 0x1F, + 0x32, 0x19, + 0x33, 0xFE, + 0x34, 0x93, + 0xff, 0xff, +}; + +static struct stv0299_config samsung_tbmu24112_config = { + .demod_address = 0x68, + .inittab = samsung_tbmu24112_inittab, + .mclk = 88000000UL, + .invert = 0, + .enhanced_tuning = 0, + .skip_reinit = 0, + .lock_output = STV0229_LOCKOUTPUT_LK, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, + .pll_set = samsung_tbmu24112_pll_set, +}; + +/* dvb-t mt352 */ +static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) +{ + static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d }; + static u8 mt352_reset [] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 }; + static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); + + mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); + + return 0; +} + +static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf) +{ + u32 div; + unsigned char bs = 0; + + #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ + div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + + if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09; + if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a; + if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08; + + pllbuf[0] = 0xc2; /* Note: non-linux standard PLL i2c address */ + pllbuf[1] = div >> 8; + pllbuf[2] = div & 0xff; + pllbuf[3] = 0xcc; + pllbuf[4] = bs; + + return 0; +} + +static struct mt352_config samsung_tdtc9251dh0_config = { + + .demod_address = 0x0f, + .demod_init = samsung_tdtc9251dh0_demod_init, + .pll_set = samsung_tdtc9251dh0_pll_set, +}; + +static int nxt2002_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) +{ + struct flexcop_device *fc = fe->dvb->priv; + return request_firmware(fw, name, fc->dev); +} + +static struct nxt2002_config samsung_tbmv_config = { + .demod_address = 0x0a, + .request_firmware = nxt2002_request_firmware, +}; + +static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + u8 buf[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + struct flexcop_device *fc = fe->dvb->priv; + + div = (params->frequency + (125/2)) / 125; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = (div >> 0) & 0xff; + buf[2] = 0x84 | ((div >> 10) & 0x60); + buf[3] = 0x80; + + if (params->frequency < 1550000) + buf[3] |= 0x02; + + if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct mt312_config skystar23_samsung_tbdu18132_config = { + + .demod_address = 0x0e, + .pll_set = skystar23_samsung_tbdu18132_pll_set, +}; + +static struct stv0297_config alps_tdee4_stv0297_config = { + .demod_address = 0x1c, +// .invert = 1, +// .pll_set = alps_tdee4_stv0297_pll_set, +}; + +/* try to figure out the frontend, each card/box can have on of the following list */ +int flexcop_frontend_init(struct flexcop_device *fc) +{ + /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */ + if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) { + fc->fe->ops->set_voltage = flexcop_set_voltage; + + fc->fe_sleep = fc->fe->ops->sleep; + fc->fe->ops->sleep = flexcop_sleep; + + fc->dev_type = FC_SKY; + info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address); + } else + /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */ + if ((fc->fe = mt352_attach(&samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) { + fc->dev_type = FC_AIR_DVB; + info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address); + } else + /* try the air atsc (nxt2002) */ + if ((fc->fe = nxt2002_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) { + fc->dev_type = FC_AIR_ATSC; + info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address); + } else + /* try the cable dvb (stv0297) */ + if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap, 0xf8)) != NULL) { + fc->dev_type = FC_CABLE; + info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address); + } else + /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */ + if ((fc->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) { + fc->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; + fc->fe->ops->diseqc_send_burst = flexcop_diseqc_send_burst; + fc->fe->ops->set_tone = flexcop_set_tone; + fc->fe->ops->set_voltage = flexcop_set_voltage; + + fc->fe_sleep = fc->fe->ops->sleep; + fc->fe->ops->sleep = flexcop_sleep; + + fc->dev_type = FC_SKY_OLD; + info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address); + } + + if (fc->fe == NULL) { + err("no frontend driver found for this B2C2/FlexCop adapter"); + return -ENODEV; + } else { + if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) { + err("frontend registration failed!"); + if (fc->fe->ops->release != NULL) + fc->fe->ops->release(fc->fe); + fc->fe = NULL; + return -EINVAL; + } + } + fc->init_state |= FC_STATE_FE_INIT; + return 0; +} + +void flexcop_frontend_exit(struct flexcop_device *fc) +{ + if (fc->init_state & FC_STATE_FE_INIT) + dvb_unregister_frontend(fc->fe); + + fc->init_state &= ~FC_STATE_FE_INIT; +} diff --git a/drivers/media/dvb/b2c2/flexcop-hw-filter.c b/drivers/media/dvb/b2c2/flexcop-hw-filter.c new file mode 100644 index 00000000000..db983d704ff --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-hw-filter.c @@ -0,0 +1,198 @@ +/* + * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * flexcop-hw-filter.c - pid and mac address filtering and corresponding control functions. + * + * see flexcop.c for copyright information. + */ +#include "flexcop.h" + +static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff) +{ + flexcop_set_ibi_value(ctrl_208,Rcv_Data_sig,onoff); +} + +void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff) +{ + flexcop_set_ibi_value(ctrl_208,SMC_Enable_sig,onoff); +} + +void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff) +{ + flexcop_set_ibi_value(ctrl_208,Null_filter_sig,onoff); +} + +void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]) +{ + flexcop_ibi_value v418,v41c; + v41c = fc->read_ibi_reg(fc,mac_address_41c); + + v418.mac_address_418.MAC1 = mac[0]; + v418.mac_address_418.MAC2 = mac[1]; + v418.mac_address_418.MAC3 = mac[2]; + v418.mac_address_418.MAC6 = mac[3]; + v41c.mac_address_41c.MAC7 = mac[4]; + v41c.mac_address_41c.MAC8 = mac[5]; + + fc->write_ibi_reg(fc,mac_address_418,v418); + fc->write_ibi_reg(fc,mac_address_41c,v41c); +} + +void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff) +{ + flexcop_set_ibi_value(ctrl_208,MAC_filter_Mode_sig,onoff); +} + +static void flexcop_pid_group_filter(struct flexcop_device *fc, u16 pid, u16 mask) +{ + /* index_reg_310.extra_index_reg need to 0 or 7 to work */ + flexcop_ibi_value v30c; + v30c.pid_filter_30c_ext_ind_0_7.Group_PID = pid; + v30c.pid_filter_30c_ext_ind_0_7.Group_mask = mask; + fc->write_ibi_reg(fc,pid_filter_30c,v30c); +} + +static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff) +{ + flexcop_set_ibi_value(ctrl_208,Mask_filter_sig,onoff); +} + +/* this fancy define reduces the code size of the quite similar PID controlling of + * the first 6 PIDs + */ + +#define pid_ctrl(vregname,field,enablefield,trans_field,transval) \ + flexcop_ibi_value vpid = fc->read_ibi_reg(fc, vregname), \ + v208 = fc->read_ibi_reg(fc, ctrl_208); \ +\ + vpid.vregname.field = onoff ? pid : 0x1fff; \ + vpid.vregname.trans_field = transval; \ + v208.ctrl_208.enablefield = onoff; \ +\ + fc->write_ibi_reg(fc,vregname,vpid); \ + fc->write_ibi_reg(fc,ctrl_208,v208); + +static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff) +{ + pid_ctrl(pid_filter_300,Stream1_PID,Stream1_filter_sig,Stream1_trans,0); +} + +static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff) +{ + pid_ctrl(pid_filter_300,Stream2_PID,Stream2_filter_sig,Stream2_trans,0); +} + +static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff) +{ + pid_ctrl(pid_filter_304,PCR_PID,PCR_filter_sig,PCR_trans,0); +} + +static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff) +{ + pid_ctrl(pid_filter_304,PMT_PID,PMT_filter_sig,PMT_trans,0); +} + +static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff) +{ + pid_ctrl(pid_filter_308,EMM_PID,EMM_filter_sig,EMM_trans,0); +} + +static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff) +{ + pid_ctrl(pid_filter_308,ECM_PID,ECM_filter_sig,ECM_trans,0); +} + +static void flexcop_pid_control(struct flexcop_device *fc, int index, u16 pid,int onoff) +{ + deb_ts("setting pid: %5d %04x at index %d '%s'\n",pid,pid,index,onoff ? "on" : "off"); + + /* We could use bit magic here to reduce source code size. + * I decided against it, but to use the real register names */ + switch (index) { + case 0: flexcop_pid_Stream1_PID_ctrl(fc,pid,onoff); break; + case 1: flexcop_pid_Stream2_PID_ctrl(fc,pid,onoff); break; + case 2: flexcop_pid_PCR_PID_ctrl(fc,pid,onoff); break; + case 3: flexcop_pid_PMT_PID_ctrl(fc,pid,onoff); break; + case 4: flexcop_pid_EMM_PID_ctrl(fc,pid,onoff); break; + case 5: flexcop_pid_ECM_PID_ctrl(fc,pid,onoff); break; + default: + if (fc->has_32_hw_pid_filter && index < 38) { + flexcop_ibi_value vpid,vid; + + /* set the index */ + vid = fc->read_ibi_reg(fc,index_reg_310); + vid.index_reg_310.index_reg = index - 6; + fc->write_ibi_reg(fc,index_reg_310, vid); + + vpid = fc->read_ibi_reg(fc,pid_n_reg_314); + vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff; + vpid.pid_n_reg_314.PID_enable_bit = onoff; + fc->write_ibi_reg(fc,pid_n_reg_314, vpid); + } + break; + } +} + +int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff) +{ + int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32; + + fc->feedcount += (onoff ? 1 : -1); + + /* when doing hw pid filtering, set the pid */ + if (fc->pid_filtering) + flexcop_pid_control(fc,dvbdmxfeed->index,dvbdmxfeed->pid,onoff); + + /* if it was the first feed request */ + if (fc->feedcount == onoff && onoff) { + if (!fc->pid_filtering) { + deb_ts("enabling full TS transfer\n"); + flexcop_pid_group_filter(fc, 0,0); + flexcop_pid_group_filter_ctrl(fc,1); + } + + if (fc->stream_control) + fc->stream_control(fc,1); + flexcop_rcv_data_ctrl(fc,1); + + /* if there is no more feed left to feed */ + } else if (fc->feedcount == onoff && !onoff) { + if (!fc->pid_filtering) { + deb_ts("disabling full TS transfer\n"); + flexcop_pid_group_filter(fc, 0x1fe0,0); + flexcop_pid_group_filter_ctrl(fc,0); + } + + flexcop_rcv_data_ctrl(fc,0); + if (fc->stream_control) + fc->stream_control(fc,0); + } + + /* if pid_filtering is on and more pids than the hw-filter can provide are + * requested enable the whole bandwidth. + */ + if (fc->pid_filtering && fc->feedcount > max_pid_filter) { + flexcop_pid_group_filter(fc, 0,0); + flexcop_pid_group_filter_ctrl(fc,1); + } else if (fc->pid_filtering && fc->feedcount <= max_pid_filter) { + flexcop_pid_group_filter(fc, 0x1fe0,0); + flexcop_pid_group_filter_ctrl(fc,0); + } + + return 0; +} + +void flexcop_hw_filter_init(struct flexcop_device *fc) +{ + int i; + flexcop_ibi_value v; + for (i = 0; i < 6 + 32*fc->has_32_hw_pid_filter; i++) + flexcop_pid_control(fc,i,0x1fff,0); + + flexcop_pid_group_filter(fc, 0x1fe0,0); + + v = fc->read_ibi_reg(fc,pid_filter_308); + v.pid_filter_308.EMM_filter_4 = 1; + v.pid_filter_308.EMM_filter_6 = 0; + fc->write_ibi_reg(fc,pid_filter_308,v); +} diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c new file mode 100644 index 00000000000..736251f393c --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-i2c.c @@ -0,0 +1,204 @@ +/* + * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * flexcop-i2c.c - flexcop internal 2Wire bus (I2C) and dvb i2c initialization + * + * see flexcop.c for copyright information. + */ +#include "flexcop.h" + +#define FC_MAX_I2C_RETRIES 100000 + +static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r100, int max_ack_errors) +{ + int i,ack_errors = 0; + flexcop_ibi_value r; + + r100->tw_sm_c_100.working_start = 1; + deb_i2c("r100 before: %08x\n",r100->raw); + + fc->write_ibi_reg(fc, tw_sm_c_100, ibi_zero); + fc->write_ibi_reg(fc, tw_sm_c_100, *r100); /* initiating i2c operation */ + + for (i = 0; i < FC_MAX_I2C_RETRIES; i++) { + r = fc->read_ibi_reg(fc, tw_sm_c_100); + + if (!r.tw_sm_c_100.no_base_addr_ack_error) { + if (r.tw_sm_c_100.st_done) { /* && !r.tw_sm_c_100.working_start */ + *r100 = r; + deb_i2c("i2c success\n"); + return 0; + } + } else { + deb_i2c("suffering from an i2c ack_error\n"); + if (++ack_errors >= max_ack_errors) + break; + + fc->write_ibi_reg(fc, tw_sm_c_100, ibi_zero); + fc->write_ibi_reg(fc, tw_sm_c_100, *r100); + } + } + deb_i2c("tried %d times i2c operation, never finished or too many ack errors.\n",i); + return -EREMOTEIO; +} + +static int flexcop_i2c_read4(struct flexcop_device *fc, flexcop_ibi_value r100, u8 *buf) +{ + flexcop_ibi_value r104; + int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */ + ret; + + if ((ret = flexcop_i2c_operation(fc,&r100,30)) != 0) + return ret; + + r104 = fc->read_ibi_reg(fc,tw_sm_c_104); + + deb_i2c("read: r100: %08x, r104: %08x\n",r100.raw,r104.raw); + + /* there is at least one byte, otherwise we wouldn't be here */ + buf[0] = r100.tw_sm_c_100.data1_reg; + + if (len > 0) buf[1] = r104.tw_sm_c_104.data2_reg; + if (len > 1) buf[2] = r104.tw_sm_c_104.data3_reg; + if (len > 2) buf[3] = r104.tw_sm_c_104.data4_reg; + + return 0; +} + +static int flexcop_i2c_write4(struct flexcop_device *fc, flexcop_ibi_value r100, u8 *buf) +{ + flexcop_ibi_value r104; + int len = r100.tw_sm_c_100.total_bytes; /* remember total_bytes is buflen-1 */ + r104.raw = 0; + + /* there is at least one byte, otherwise we wouldn't be here */ + r100.tw_sm_c_100.data1_reg = buf[0]; + + r104.tw_sm_c_104.data2_reg = len > 0 ? buf[1] : 0; + r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0; + r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0; + + deb_i2c("write: r100: %08x, r104: %08x\n",r100.raw,r104.raw); + + /* write the additional i2c data before doing the actual i2c operation */ + fc->write_ibi_reg(fc,tw_sm_c_104,r104); + + return flexcop_i2c_operation(fc,&r100,30); +} + +/* master xfer callback for demodulator */ +static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) +{ + struct flexcop_device *fc = i2c_get_adapdata(i2c_adap); + int i, ret = 0; + + if (down_interruptible(&fc->i2c_sem)) + return -ERESTARTSYS; + + /* reading */ + if (num == 2 && + msgs[0].flags == 0 && + msgs[1].flags == I2C_M_RD && + msgs[0].buf != NULL && + msgs[1].buf != NULL) { + + ret = fc->i2c_request(fc, FC_READ, FC_I2C_PORT_DEMOD, msgs[0].addr, msgs[0].buf[0], msgs[1].buf, msgs[1].len); + + } else for (i = 0; i < num; i++) { /* writing command */ + if (msgs[i].flags != 0 || msgs[i].buf == NULL || msgs[i].len < 2) { + ret = -EINVAL; + break; + } + + ret = fc->i2c_request(fc, FC_WRITE, FC_I2C_PORT_DEMOD, msgs[i].addr, msgs[i].buf[0], &msgs[i].buf[1], msgs[i].len - 1); + } + + if (ret < 0) + err("i2c master_xfer failed"); + else + ret = num; + + up(&fc->i2c_sem); + + return ret; +} + +int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op, + flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len) +{ + int ret; + u16 bytes_to_transfer; + flexcop_ibi_value r100; + + deb_i2c("op = %d\n",op); + r100.raw = 0; + r100.tw_sm_c_100.chipaddr = chipaddr; + r100.tw_sm_c_100.twoWS_rw = op; + r100.tw_sm_c_100.twoWS_port_reg = port; + + while (len != 0) { + bytes_to_transfer = len > 4 ? 4 : len; + + r100.tw_sm_c_100.total_bytes = bytes_to_transfer - 1; + r100.tw_sm_c_100.baseaddr = addr; + + if (op == FC_READ) + ret = flexcop_i2c_read4(fc, r100, buf); + else + ret = flexcop_i2c_write4(fc,r100, buf); + + if (ret < 0) + return ret; + + buf += bytes_to_transfer; + addr += bytes_to_transfer; + len -= bytes_to_transfer; + }; + + return 0; +} +/* exported for PCI i2c */ +EXPORT_SYMBOL(flexcop_i2c_request); + +static u32 flexcop_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm flexcop_algo = { + .name = "FlexCop I2C algorithm", + .id = I2C_ALGO_BIT, + .master_xfer = flexcop_master_xfer, + .functionality = flexcop_i2c_func, +}; + +int flexcop_i2c_init(struct flexcop_device *fc) +{ + int ret; + + sema_init(&fc->i2c_sem,1); + + memset(&fc->i2c_adap, 0, sizeof(struct i2c_adapter)); + strncpy(fc->i2c_adap.name, "B2C2 FlexCop device",I2C_NAME_SIZE); + + i2c_set_adapdata(&fc->i2c_adap,fc); + + fc->i2c_adap.class = I2C_CLASS_TV_DIGITAL; + fc->i2c_adap.algo = &flexcop_algo; + fc->i2c_adap.algo_data = NULL; + fc->i2c_adap.id = I2C_ALGO_BIT; + + if ((ret = i2c_add_adapter(&fc->i2c_adap)) < 0) + return ret; + + fc->init_state |= FC_STATE_I2C_INIT; + return 0; +} + +void flexcop_i2c_exit(struct flexcop_device *fc) +{ + if (fc->init_state & FC_STATE_I2C_INIT) + i2c_del_adapter(&fc->i2c_adap); + + fc->init_state &= ~FC_STATE_I2C_INIT; +} diff --git a/drivers/media/dvb/b2c2/flexcop-misc.c b/drivers/media/dvb/b2c2/flexcop-misc.c new file mode 100644 index 00000000000..19e06da4677 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-misc.c @@ -0,0 +1,66 @@ +/* + * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * flexcop-misc.c - miscellaneous functions. + * + * see flexcop.c for copyright information. + */ +#include "flexcop.h" + +void flexcop_determine_revision(struct flexcop_device *fc) +{ + flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); + + switch (v.misc_204.Rev_N_sig_revision_hi) { + case 0x2: + deb_info("found a FlexCopII.\n"); + fc->rev = FLEXCOP_II; + break; + case 0x3: + deb_info("found a FlexCopIIb.\n"); + fc->rev = FLEXCOP_IIB; + break; + case 0x0: + deb_info("found a FlexCopIII.\n"); + fc->rev = FLEXCOP_III; + break; + default: + err("unkown FlexCop Revision: %x. Please report the linux-dvb@linuxtv.org.",v.misc_204.Rev_N_sig_revision_hi); + break; + } + + if ((fc->has_32_hw_pid_filter = v.misc_204.Rev_N_sig_caps)) + deb_info("this FlexCop has the additional 32 hardware pid filter.\n"); + else + deb_info("this FlexCop has only the 6 basic main hardware pid filter.\n"); + /* bus parts have to decide if hw pid filtering is used or not. */ +} + +const char *flexcop_revision_names[] = { + "Unkown chip", + "FlexCopII", + "FlexCopIIb", + "FlexCopIII", +}; + +const char *flexcop_device_names[] = { + "Unkown device", + "AirStar 2 DVB-T", + "AirStar 2 ATSC", + "SkyStar 2 DVB-S", + "SkyStar 2 DVB-S (old version)", + "CableStar 2 DVB-C", +}; + +const char *flexcop_bus_names[] = { + "USB", + "PCI", +}; + +void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const + char *suffix) +{ + info("%s '%s' at the '%s' bus controlled by a '%s' %s",prefix, + flexcop_device_names[fc->dev_type],flexcop_bus_names[fc->bus_type], + flexcop_revision_names[fc->rev],suffix); +} diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c new file mode 100644 index 00000000000..693af41f337 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-pci.c @@ -0,0 +1,365 @@ +/* + * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * flexcop-pci.c - covers the PCI part including DMA transfers. + * + * see flexcop.c for copyright information. + */ + +#define FC_LOG_PREFIX "flexcop-pci" +#include "flexcop-common.h" + +static int enable_pid_filtering = 0; +module_param(enable_pid_filtering, int, 0444); +MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1"); + +#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG +#define dprintk(level,args...) \ + do { if ((debug & level)) printk(args); } while (0) +#define DEBSTATUS "" +#else +#define dprintk(level,args...) +#define DEBSTATUS " (debugging is not enabled)" +#endif + +#define deb_info(args...) dprintk(0x01,args) +#define deb_reg(args...) dprintk(0x02,args) +#define deb_ts(args...) dprintk(0x04,args) +#define deb_irq(args...) dprintk(0x08,args) + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "set debug level (1=info,2=regs,4=TS,8=irqdma (|-able))." DEBSTATUS); + +#define DRIVER_VERSION "0.1" +#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver" +#define DRIVER_AUTHOR "Patrick Boettcher " + +struct flexcop_pci { + struct pci_dev *pdev; + +#define FC_PCI_INIT 0x01 +#define FC_PCI_DMA_INIT 0x02 + int init_state; + + void __iomem *io_mem; + u32 irq; +/* buffersize (at least for DMA1, need to be % 188 == 0, + * this is logic is required */ +#define FC_DEFAULT_DMA1_BUFSIZE (1280 * 188) +#define FC_DEFAULT_DMA2_BUFSIZE (10 * 188) + struct flexcop_dma dma[2]; + + int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */ + u32 last_dma1_cur_pos; /* position of the pointer last time the timer/packet irq occured */ + + struct flexcop_device *fc_dev; +}; + +static int lastwreg,lastwval,lastrreg,lastrval; + +static flexcop_ibi_value flexcop_pci_read_ibi_reg (struct flexcop_device *fc, flexcop_ibi_register r) +{ + struct flexcop_pci *fc_pci = fc->bus_specific; + flexcop_ibi_value v; + v.raw = readl(fc_pci->io_mem + r); + + if (lastrreg != r || lastrval != v.raw) { + lastrreg = r; lastrval = v.raw; + deb_reg("new rd: %3x: %08x\n",r,v.raw); + } + + return v; +} + +static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register r, flexcop_ibi_value v) +{ + struct flexcop_pci *fc_pci = fc->bus_specific; + + if (lastwreg != r || lastwval != v.raw) { + lastwreg = r; lastwval = v.raw; + deb_reg("new wr: %3x: %08x\n",r,v.raw); + } + + writel(v.raw, fc_pci->io_mem + r); + return 0; +} + +/* When PID filtering is turned on, we use the timer IRQ, because small amounts + * of data need to be passed to the user space instantly as well. When PID + * filtering is turned off, we use the page-change-IRQ */ +static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct flexcop_pci *fc_pci = dev_id; + struct flexcop_device *fc = fc_pci->fc_dev; + flexcop_ibi_value v = fc->read_ibi_reg(fc,irq_20c); + + deb_irq("irq: %08x cur_addr: %08x (%d), our addrs. 1: %08x 2: %08x; 0x000: " + "%08x, 0x00c: %08x\n",v.raw, + fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2, + fc_pci->active_dma1_addr, + fc_pci->dma[0].dma_addr0,fc_pci->dma[0].dma_addr1, + fc->read_ibi_reg(fc,dma1_000).raw, + fc->read_ibi_reg(fc,dma1_00c).raw); + + if (v.irq_20c.DMA1_IRQ_Status == 1) { + if (fc_pci->active_dma1_addr == 0) + flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr0,fc_pci->dma[0].size / 188); + else + flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr1,fc_pci->dma[0].size / 188); + + deb_irq("page change to page: %d\n",!fc_pci->active_dma1_addr); + fc_pci->active_dma1_addr = !fc_pci->active_dma1_addr; + } else if (v.irq_20c.DMA1_Timer_Status == 1) { + /* for the timer IRQ we only can use buffer dmx feeding, because we don't have + * complete TS packets when reading from the DMA memory */ + dma_addr_t cur_addr = + fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2; + u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0; + + /* buffer end was reached, restarted from the beginning + * pass the data from last_cur_pos to the buffer end to the demux + */ + if (cur_pos < fc_pci->last_dma1_cur_pos) { + flexcop_pass_dmx_data(fc_pci->fc_dev, + fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos, + (fc_pci->dma[0].size*2 - 1) - fc_pci->last_dma1_cur_pos); + fc_pci->last_dma1_cur_pos = 0; + } + + if (cur_pos > fc_pci->last_dma1_cur_pos) { + flexcop_pass_dmx_data(fc_pci->fc_dev, + fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos, + cur_pos - fc_pci->last_dma1_cur_pos); + } + + fc_pci->last_dma1_cur_pos = cur_pos; + } + +/* packet count would be ideal for hw filtering, but it isn't working. Either + * the data book is wrong, or I'm unable to read it correctly */ + +/* if (v.irq_20c.DMA1_Size_IRQ_Status == 1) { packet counter */ + + return IRQ_HANDLED; +} + +static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff) +{ + struct flexcop_pci *fc_pci = fc->bus_specific; + if (onoff) { + flexcop_dma_config(fc,&fc_pci->dma[0],FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1); + flexcop_dma_config(fc,&fc_pci->dma[1],FC_DMA_2,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1); + flexcop_dma_config_timer(fc,FC_DMA_1,1); + + if (fc_pci->fc_dev->pid_filtering) { + fc_pci->last_dma1_cur_pos = 0; + flexcop_dma_control_timer_irq(fc,FC_DMA_1,1); + } else { + fc_pci->active_dma1_addr = 0; + flexcop_dma_control_size_irq(fc,FC_DMA_1,1); + } + +/* flexcop_dma_config_packet_count(fc,FC_DMA_1,0xc0); + flexcop_dma_control_packet_irq(fc,FC_DMA_1,1); */ + + deb_irq("irqs enabled\n"); + } else { + if (fc_pci->fc_dev->pid_filtering) + flexcop_dma_control_timer_irq(fc,FC_DMA_1,0); + else + flexcop_dma_control_size_irq(fc,FC_DMA_1,0); + +// flexcop_dma_control_packet_irq(fc,FC_DMA_1,0); + deb_irq("irqs disabled\n"); + } + + return 0; +} + +static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci) +{ + int ret; + if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[0],FC_DEFAULT_DMA1_BUFSIZE)) != 0) + return ret; + + if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0) + goto dma1_free; + + flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1); + flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2); + + fc_pci->init_state |= FC_PCI_DMA_INIT; + goto success; +dma1_free: + flexcop_dma_free(&fc_pci->dma[0]); + +success: + return ret; +} + +static void flexcop_pci_dma_exit(struct flexcop_pci *fc_pci) +{ + if (fc_pci->init_state & FC_PCI_DMA_INIT) { + flexcop_dma_free(&fc_pci->dma[0]); + flexcop_dma_free(&fc_pci->dma[1]); + } + fc_pci->init_state &= ~FC_PCI_DMA_INIT; +} + +static int flexcop_pci_init(struct flexcop_pci *fc_pci) +{ + int ret; + u8 card_rev; + + pci_read_config_byte(fc_pci->pdev, PCI_CLASS_REVISION, &card_rev); + info("card revision %x", card_rev); + + if ((ret = pci_enable_device(fc_pci->pdev)) != 0) + return ret; + + pci_set_master(fc_pci->pdev); + + /* enable interrupts */ + // pci_write_config_dword(pdev, 0x6c, 0x8000); + + if ((ret = pci_request_regions(fc_pci->pdev, DRIVER_NAME)) != 0) + goto err_pci_disable_device; + + fc_pci->io_mem = pci_iomap(fc_pci->pdev, 0, 0x800); + + if (!fc_pci->io_mem) { + err("cannot map io memory\n"); + ret = -EIO; + goto err_pci_release_regions; + } + + pci_set_drvdata(fc_pci->pdev, fc_pci); + + if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_irq, + SA_SHIRQ, DRIVER_NAME, fc_pci)) != 0) + goto err_pci_iounmap; + + fc_pci->init_state |= FC_PCI_INIT; + goto success; + +err_pci_iounmap: + pci_iounmap(fc_pci->pdev, fc_pci->io_mem); + pci_set_drvdata(fc_pci->pdev, NULL); +err_pci_release_regions: + pci_release_regions(fc_pci->pdev); +err_pci_disable_device: + pci_disable_device(fc_pci->pdev); + +success: + return ret; +} + +static void flexcop_pci_exit(struct flexcop_pci *fc_pci) +{ + if (fc_pci->init_state & FC_PCI_INIT) { + free_irq(fc_pci->pdev->irq, fc_pci); + pci_iounmap(fc_pci->pdev, fc_pci->io_mem); + pci_set_drvdata(fc_pci->pdev, NULL); + pci_release_regions(fc_pci->pdev); + pci_disable_device(fc_pci->pdev); + } + fc_pci->init_state &= ~FC_PCI_INIT; +} + + +static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct flexcop_device *fc; + struct flexcop_pci *fc_pci; + int ret = -ENOMEM; + + if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_pci))) == NULL) { + err("out of memory\n"); + return -ENOMEM; + } + +/* general flexcop init */ + fc_pci = fc->bus_specific; + fc_pci->fc_dev = fc; + + fc->read_ibi_reg = flexcop_pci_read_ibi_reg; + fc->write_ibi_reg = flexcop_pci_write_ibi_reg; + fc->i2c_request = flexcop_i2c_request; + fc->get_mac_addr = flexcop_eeprom_check_mac_addr; + + fc->stream_control = flexcop_pci_stream_control; + + fc->pid_filtering = enable_pid_filtering; + fc->bus_type = FC_PCI; + + fc->dev = &pdev->dev; + +/* bus specific part */ + fc_pci->pdev = pdev; + if ((ret = flexcop_pci_init(fc_pci)) != 0) + goto err_kfree; + +/* init flexcop */ + if ((ret = flexcop_device_initialize(fc)) != 0) + goto err_pci_exit; + +/* init dma */ + if ((ret = flexcop_pci_dma_init(fc_pci)) != 0) + goto err_fc_exit; + + goto success; +err_fc_exit: + flexcop_device_exit(fc); +err_pci_exit: + flexcop_pci_exit(fc_pci); +err_kfree: + flexcop_device_kfree(fc); +success: + return ret; +} + +/* in theory every _exit function should be called exactly two times, + * here and in the bail-out-part of the _init-function + */ +static void flexcop_pci_remove(struct pci_dev *pdev) +{ + struct flexcop_pci *fc_pci = pci_get_drvdata(pdev); + + flexcop_pci_dma_exit(fc_pci); + flexcop_device_exit(fc_pci->fc_dev); + flexcop_pci_exit(fc_pci); + flexcop_device_kfree(fc_pci->fc_dev); +} + +static struct pci_device_id flexcop_pci_tbl[] = { + { PCI_DEVICE(0x13d0, 0x2103) }, +/* { PCI_DEVICE(0x13d0, 0x2200) }, PCI FlexCopIII ? */ + { }, +}; + +MODULE_DEVICE_TABLE(pci, flexcop_pci_tbl); + +static struct pci_driver flexcop_pci_driver = { + .name = "Technisat/B2C2 FlexCop II/IIb/III PCI", + .id_table = flexcop_pci_tbl, + .probe = flexcop_pci_probe, + .remove = flexcop_pci_remove, +}; + +static int __init flexcop_pci_module_init(void) +{ + return pci_register_driver(&flexcop_pci_driver); +} + +static void __exit flexcop_pci_module_exit(void) +{ + pci_unregister_driver(&flexcop_pci_driver); +} + +module_init(flexcop_pci_module_init); +module_exit(flexcop_pci_module_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_NAME); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h new file mode 100644 index 00000000000..41835c5280a --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-reg.h @@ -0,0 +1,700 @@ +/* + * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * flexcop-reg.h - register abstraction for FlexCopII, FlexCopIIb and FlexCopIII + * + * see flexcop.c for copyright information. + */ +#ifndef __FLEXCOP_REG_H__ +#define __FLEXCOP_REG_H__ + + +typedef enum { + FLEXCOP_UNK = 0, + FLEXCOP_II, + FLEXCOP_IIB, + FLEXCOP_III, +} flexcop_revision_t; + +extern const char *flexcop_revision_names[]; + +typedef enum { + FC_UNK = 0, + FC_AIR_DVB, + FC_AIR_ATSC, + FC_SKY, + FC_SKY_OLD, + FC_CABLE, +} flexcop_device_type_t; + +typedef enum { + FC_USB = 0, + FC_PCI, +} flexcop_bus_t; + +extern const char *flexcop_device_names[]; + +/* FlexCop IBI Registers */ + +/* flexcop_ibi_reg - a huge union representing the register structure */ +typedef union { + u32 raw; + +/* DMA 0x000 to 0x01c + * DMA1 0x000 to 0x00c + * DMA2 0x010 to 0x01c + */ + struct { + u32 dma_0start : 1; /* set: data will be delivered to dma1_address0 */ + u32 dma_0No_update : 1; /* set: dma1_cur_address will be updated, unset: no update */ + u32 dma_address0 :30; /* physical/virtual host memory address0 DMA */ + } dma_0x0; + + struct { + u32 DMA_maxpackets : 8; /* (remapped) PCI DMA1 Packet Count Interrupt. This variable + is able to be read and written while bit(1) of register + 0x00c (remap_enable) is set. This variable represents + the number of packets that will be transmitted to the PCI + host using PCI DMA1 before an interrupt to the PCI is + asserted. This functionality may be enabled using bit(20) + of register 0x208. N=0 disables the IRQ. */ + u32 dma_addr_size :24; /* size of memory buffer in DWORDs (bytesize / 4) for DMA */ + } dma_0x4_remap; + + struct { + u32 dma1timer : 7; /* reading PCI DMA1 timer ... when remap_enable is 0 */ + u32 unused : 1; + u32 dma_addr_size :24; + } dma_0x4_read; + + struct { + u32 unused : 1; + u32 dmatimer : 7; /* writing PCI DMA1 timer ... when remap_enable is 0 */ + u32 dma_addr_size :24; + } dma_0x4_write; + + struct { + u32 unused : 2; + u32 dma_cur_addr :30; /* current physical host memory address pointer for DMA */ + } dma_0x8; + + struct { + u32 dma_1start : 1; /* set: data will be delivered to dma_address1, when dma_address0 is full */ + u32 remap_enable : 1; /* remap enable for 0x0x4(7:0) */ + u32 dma_address1 :30; /* Physical/virtual address 1 on DMA */ + } dma_0xc; + +/* Two-wire Serial Master and Clock 0x100-0x110 */ + struct { +// u32 slave_transmitter : 1; /* ???*/ + u32 chipaddr : 7; /* two-line serial address of the target slave */ + u32 reserved1 : 1; + u32 baseaddr : 8; /* address of the location of the read/write operation */ + u32 data1_reg : 8; /* first byte in two-line serial read/write operation */ + u32 working_start : 1; /* when doing a write operation this indicator is 0 when ready + * set to 1 when doing a write operation */ + u32 twoWS_rw : 1; /* read/write indicator (1 = read, 0 write) */ + u32 total_bytes : 2; /* number of data bytes in each two-line serial transaction (0 = 1 byte, 11 = 4byte)*/ + u32 twoWS_port_reg : 2; /* port selection: 01 - Front End/Demod, 10 - EEPROM, 11 - Tuner */ + u32 no_base_addr_ack_error : 1; /* writing: write-req: frame is produced w/o baseaddr, read-req: read-cycles w/o + * preceding address assignment write frame + * ACK_ERROR = 1 when no ACK from slave in the last transaction */ + u32 st_done : 1; /* indicator for transaction is done */ + } tw_sm_c_100; + + struct { + u32 data2_reg : 8; /* 2nd data byte */ + u32 data3_reg : 8; /* 3rd data byte */ + u32 data4_reg : 8; /* 4th data byte */ + u32 exlicit_stops : 1; /* when set, transactions are produced w/o trailing STOP flag, then send isolated STOP flags */ + u32 force_stop : 1; /* isolated stop flag */ + u32 unused : 6; + } tw_sm_c_104; + +/* Clock. The register allows the FCIII to convert an incoming Master clock + * (MCLK) signal into a lower frequency clock through the use of a LowCounter + * (TLO) and a High- Counter (THI). The time counts for THI and TLO are + * measured in MCLK; each count represents 4 MCLK input clock cycles. + * + * The default output for port #1 is set for Front End Demod communication. (0x108) + * The default output for port #2 is set for EEPROM communication. (0x10c) + * The default output for port #3 is set for Tuner communication. (0x110) + */ + struct { + u32 thi1 : 6; /* Thi for port #1 (def: 100110b; 38) */ + u32 reserved1 : 2; + u32 tlo1 : 5; /* Tlo for port #1 (def: 11100b; 28) */ + u32 reserved2 :19; + } tw_sm_c_108; + + struct { + u32 thi1 : 6; /* Thi for port #2 (def: 111001b; 57) */ + u32 reserved1 : 2; + u32 tlo1 : 5; /* Tlo for port #2 (def: 11100b; 28) */ + u32 reserved2 :19; + } tw_sm_c_10c; + + struct { + u32 thi1 : 6; /* Thi for port #3 (def: 111001b; 57) */ + u32 reserved1 : 2; + u32 tlo1 : 5; /* Tlo for port #3 (def: 11100b; 28) */ + u32 reserved2 :19; + } tw_sm_c_110; + +/* LNB Switch Frequency 0x200 + * Clock that creates the LNB switch tone. The default is set to have a fixed + * low output (not oscillating) to the LNB_CTL line. + */ + struct { + u32 LNB_CTLHighCount_sig :15; /* It is the number of pre-scaled clock cycles that will be low. */ + u32 LNB_CTLLowCount_sig :15; /* For example, to obtain a 22KHz output given a 45 Mhz Master + Clock signal (MCLK), set PreScalar=01 and LowCounter value to 0x1ff. */ + u32 LNB_CTLPrescaler_sig : 2; /* pre-scaler divides MCLK: 00 (no division), 01 by 2, 10 by 4, 11 by 12 */ + } lnb_switch_freq_200; + +/* ACPI, Peripheral Reset, LNB Polarity + * ACPI power conservation mode, LNB polarity selection (low or high voltage), + * and peripheral reset. + */ + struct { + u32 ACPI1_sig : 1; /* turn of the power of tuner and LNB, not implemented in FCIII */ + u32 ACPI3_sig : 1; /* turn of power of the complete satelite receiver board (except FCIII) */ + u32 LNB_L_H_sig : 1; /* low or high voltage for LNB. (0 = low, 1 = high) */ + u32 Per_reset_sig : 1; /* misc. init reset (default: 1), to reset set to low and back to high */ + u32 reserved :20; + u32 Rev_N_sig_revision_hi : 4;/* 0xc in case of FCIII */ + u32 Rev_N_sig_reserved1 : 2; + u32 Rev_N_sig_caps : 1; /* if 1, FCIII has 32 PID- and MAC-filters and is capable of IP multicast */ + u32 Rev_N_sig_reserved2 : 1; + } misc_204; + +/* Control and Status 0x208 to 0x21c */ +/* Gross enable and disable control */ + struct { + u32 Stream1_filter_sig : 1; /* Stream1 PID filtering */ + u32 Stream2_filter_sig : 1; /* Stream2 PID filtering */ + u32 PCR_filter_sig : 1; /* PCR PID filter */ + u32 PMT_filter_sig : 1; /* PMT PID filter */ + + u32 EMM_filter_sig : 1; /* EMM PID filter */ + u32 ECM_filter_sig : 1; /* ECM PID filter */ + u32 Null_filter_sig : 1; /* Filters null packets, PID=0x1fff. */ + u32 Mask_filter_sig : 1; /* mask PID filter */ + + u32 WAN_Enable_sig : 1; /* WAN output line through V8 memory space is activated. */ + u32 WAN_CA_Enable_sig : 1; /* not in FCIII */ + u32 CA_Enable_sig : 1; /* not in FCIII */ + u32 SMC_Enable_sig : 1; /* CI stream data (CAI) goes directly to the smart card intf (opposed IBI 0x600 or SC-cmd buf). */ + + u32 Per_CA_Enable_sig : 1; /* not in FCIII */ + u32 Multi2_Enable_sig : 1; /* ? */ + u32 MAC_filter_Mode_sig : 1; /* (MAC_filter_enable) Globally enables MAC filters for Net PID filteres. */ + u32 Rcv_Data_sig : 1; /* PID filtering module enable. When this bit is a one, the PID filter will + examine and process packets according to all other (individual) PID + filtering controls. If it a zero, no packet processing of any kind will + take place. All data from the tuner will be thrown away. */ + + u32 DMA1_IRQ_Enable_sig : 1; /* When set, a DWORD counter is enabled on PCI DMA1 that asserts the PCI + * interrupt after the specified count for filling the buffer. */ + u32 DMA1_Timer_Enable_sig : 1; /* When set, a timer is enabled on PCI DMA1 that asserts the PCI interrupt + after a specified amount of time. */ + u32 DMA2_IRQ_Enable_sig : 1; /* same as DMA1_IRQ_Enable_sig but for DMA2 */ + u32 DMA2_Timer_Enable_sig : 1; /* same as DMA1_Timer_Enable_sig but for DMA2 */ + + u32 DMA1_Size_IRQ_Enable_sig : 1; /* When set, a packet count detector is enabled on PCI DMA1 that asserts the PCI interrupt. */ + u32 DMA2_Size_IRQ_Enable_sig : 1; /* When set, a packet count detector is enabled on PCI DMA2 that asserts the PCI interrupt. */ + u32 Mailbox_from_V8_Enable_sig: 1; /* When set, writes to the mailbox register produce an interrupt to the + PCI host to indicate that mailbox data is available. */ + + u32 unused : 9; + } ctrl_208; + +/* General status. When a PCI interrupt occurs, this register is read to + * discover the reason for the interrupt. + */ + struct { + u32 DMA1_IRQ_Status : 1; /* When set(1) the DMA1 counter had generated an IRQ. Read Only. */ + u32 DMA1_Timer_Status : 1; /* When set(1) the DMA1 timer had generated an IRQ. Read Only. */ + u32 DMA2_IRQ_Status : 1; /* When set(1) the DMA2 counter had generated an IRQ. Read Only. */ + u32 DMA2_Timer_Status : 1; /* When set(1) the DMA2 timer had generated an IRQ. Read Only. */ + u32 DMA1_Size_IRQ_Status : 1; /* (Read only). This register is read after an interrupt to */ + u32 DMA2_Size_IRQ_Status : 1; /* find out why we had an IRQ. Reading this register will clear this bit. Packet count*/ + u32 Mailbox_from_V8_Status_sig: 1; /* Same as above. Reading this register will clear this bit. */ + u32 Data_receiver_error : 1; /* 1 indicate an error in the receiver Front End (Tuner module) */ + u32 Continuity_error_flag : 1; /* 1 indicates a continuity error in the TS stream. */ + u32 LLC_SNAP_FLAG_set : 1; /* 1 indicates that the LCC_SNAP_FLAG was set. */ + u32 Transport_Error : 1; /* When set indicates that an unexpected packet was received. */ + u32 reserved :21; + } irq_20c; + + +/* Software reset register */ + struct { + u32 reset_blocks : 8; /* Enabled when Block_reset_enable = 0xB2 and 0x208 bits 15:8 = 0x00. + Each bit location represents a 0x100 block of registers. Writing + a one in a bit location resets that block of registers and the logic + that it controls. */ + u32 Block_reset_enable : 8; /* This variable is set to 0xB2 when the register is written. */ + u32 Special_controls :16; /* Asserts Reset_V8 => 0xC258; Turns on pci encryption => 0xC25A; + Turns off pci encryption => 0xC259 Note: pci_encryption default + at power-up is ON. */ + } sw_reset_210; + + struct { + u32 vuart_oe_sig : 1; /* When clear, the V8 processor has sole control of the serial UART + (RS-232 Smart Card interface). When set, the IBI interface + defined by register 0x600 controls the serial UART. */ + u32 v2WS_oe_sig : 1; /* When clear, the V8 processor has direct control of the Two-line + Serial Master EEPROM target. When set, the Two-line Serial Master + EEPROM target interface is controlled by IBI register 0x100. */ + u32 halt_V8_sig : 1; /* When set, contiguous wait states are applied to the V8-space + bus masters. Once this signal is cleared, normal V8-space + operations resume. */ + u32 section_pkg_enable_sig: 1; /* When set, this signal enables the front end translation circuitry + to process section packed transport streams. */ + u32 s2p_sel_sig : 1; /* Serial to parallel conversion. When set, polarized transport data + within the FlexCop3 front end circuitry is converted from a serial + stream into parallel data before downstream processing otherwise + interprets the data. */ + u32 unused1 : 3; + u32 polarity_PS_CLK_sig: 1; /* This signal is used to invert the input polarity of the tranport + stream CLOCK signal before any processing occurs on the transport + stream within FlexCop3. */ + u32 polarity_PS_VALID_sig: 1; /* This signal is used to invert the input polarity of the tranport + stream VALID signal before any processing occurs on the transport + stream within FlexCop3. */ + u32 polarity_PS_SYNC_sig: 1; /* This signal is used to invert the input polarity of the tranport + stream SYNC signal before any processing occurs on the transport + stream within FlexCop3. */ + u32 polarity_PS_ERR_sig: 1; /* This signal is used to invert the input polarity of the tranport + stream ERROR signal before any processing occurs on the transport + stream within FlexCop3. */ + u32 unused2 :20; + } misc_214; + +/* Mailbox from V8 to host */ + struct { + u32 Mailbox_from_V8 :32; /* When this register is written by either the V8 processor or by an + end host, an interrupt is generated to the PCI host to indicate + that mailbox data is available. Reading register 20c will clear + the IRQ. */ + } mbox_v8_to_host_218; + +/* Mailbox from host to v8 Mailbox_to_V8 + * Mailbox_to_V8 mailbox storage register + * used to send messages from PCI to V8. Writing to this register will send an + * IRQ to the V8. Then it can read the data from here. Reading this register + * will clear the IRQ. If the V8 is halted and bit 31 of this register is set, + * then this register is used instead as a direct interface to access the + * V8space memory. + */ + struct { + u32 sysramaccess_data : 8; /* Data byte written or read from the specified address in V8 SysRAM. */ + u32 sysramaccess_addr :15; /* 15 bit address used to access V8 Sys-RAM. */ + u32 unused : 7; + u32 sysramaccess_write: 1; /* Write flag used to latch data into the V8 SysRAM. */ + u32 sysramaccess_busmuster: 1; /* Setting this bit when the V8 is halted at 0x214 Bit(2) allows + this IBI register interface to directly drive the V8-space memory. */ + } mbox_host_to_v8_21c; + + +/* PIDs, Translation Bit, SMC Filter Select 0x300 to 0x31c */ + struct { + u32 Stream1_PID :13; /* Primary use is receiving Net data, so these 13 bits normally + hold the PID value for the desired network stream. */ + u32 Stream1_trans : 1; /* When set, Net translation will take place for Net data ferried in TS packets. */ + u32 MAC_Multicast_filter : 1; /* When clear, multicast MAC filtering is not allowed for Stream1 and PID_n filters. */ + u32 debug_flag_pid_saved : 1; + u32 Stream2_PID :13; /* 13 bits for Stream 2 PID filter value. General use. */ + u32 Stream2_trans : 1; /* When set Tables/CAI translation will take place for the data ferried in + Stream2_PID TS packets. */ + u32 debug_flag_write_status00 : 1; + u32 debug_fifo_problem : 1; + } pid_filter_300; + + struct { + u32 PCR_PID :13; /* PCR stream PID filter value. Primary use is Program Clock Reference stream filtering. */ + u32 PCR_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ + u32 debug_overrun3 : 1; + u32 debug_overrun2 : 1; + u32 PMT_PID :13; /* stream PID filter value. Primary use is Program Management Table segment filtering. */ + u32 PMT_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ + u32 reserved : 2; + } pid_filter_304; + + struct { + u32 EMM_PID :13; /* EMM PID filter value. Primary use is Entitlement Management Messaging for + conditional access-related data. */ + u32 EMM_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ + u32 EMM_filter_4 : 1; /* When set will pass only EMM data possessing the same ID code as the + first four bytes (32 bits) of the end-user s 6-byte Smart Card ID number Select */ + u32 EMM_filter_6 : 1; /* When set will pass only EMM data possessing the same 6-byte code as the end-users + complete 6-byte Smart Card ID number. */ + u32 ECM_PID :13; /* ECM PID filter value. Primary use is Entitlement Control Messaging for conditional + access-related data. */ + u32 ECM_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ + u32 reserved : 2; + } pid_filter_308; + + struct { + u32 Group_PID :13; /* PID value for group filtering. */ + u32 Group_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ + u32 unused1 : 2; + u32 Group_mask :13; /* Mask value used in logical "and" equation that defines group filtering */ + u32 unused2 : 3; + } pid_filter_30c_ext_ind_0_7; + + struct { + u32 net_master_read :17; + u32 unused :15; + } pid_filter_30c_ext_ind_1; + + struct { + u32 net_master_write :17; + u32 unused :15; + } pid_filter_30c_ext_ind_2; + + struct { + u32 next_net_master_write :17; + u32 unused :15; + } pid_filter_30c_ext_ind_3; + + struct { + u32 unused1 : 1; + u32 state_write :10; + u32 reserved1 : 6; /* default: 000100 */ + u32 stack_read :10; + u32 reserved2 : 5; /* default: 00100 */ + } pid_filter_30c_ext_ind_4; + + struct { + u32 stack_cnt :10; + u32 unused :22; + } pid_filter_30c_ext_ind_5; + + struct { + u32 pid_fsm_save_reg0 : 2; + u32 pid_fsm_save_reg1 : 2; + u32 pid_fsm_save_reg2 : 2; + u32 pid_fsm_save_reg3 : 2; + u32 pid_fsm_save_reg4 : 2; + u32 pid_fsm_save_reg300 : 2; + u32 write_status1 : 2; + u32 write_status4 : 2; + u32 data_size_reg :12; + u32 unused : 4; + } pid_filter_30c_ext_ind_6; + + struct { + u32 index_reg : 5; /* (Index pointer) Points at an internal PIDn register. A binary code + representing one of 32 internal PIDn registers as well as its + corresponding internal MAC_lown register. */ + u32 extra_index_reg : 3; /* This vector is used to select between sets of debug signals routed to register 0x30c. */ + u32 AB_select : 1; /* Used in conjunction with 0x31c. read/write to the MAC_highA or MAC_highB register + 0=MAC_highB register, 1=MAC_highA */ + u32 pass_alltables : 1; /* 1=Net packets are not filtered against the Network Table ID found in register 0x400. + All types of networks (DVB, ATSC, ISDB) are passed. */ + u32 unused :22; + } index_reg_310; + + struct { + u32 PID :13; /* PID value */ + u32 PID_trans : 1; /* translation will take place for packets filtered */ + u32 PID_enable_bit : 1; /* When set this PID filter is enabled */ + u32 reserved :17; + } pid_n_reg_314; + + struct { + u32 A4_byte : 8; + u32 A5_byte : 8; + u32 A6_byte : 8; + u32 Enable_bit : 1; /* enabled (1) or disabled (1) */ + u32 HighAB_bit : 1; /* use MAC_highA (1) or MAC_highB (0) as MSB */ + u32 reserved : 6; + } mac_low_reg_318; + + struct { + u32 A1_byte : 8; + u32 A2_byte : 8; + u32 A3_byte : 8; + u32 reserved : 8; + } mac_high_reg_31c; + +/* Table, SMCID,MACDestination Filters 0x400 to 0x41c */ + struct { + u32 reserved :16; +#define fc_data_Tag_ID_DVB 0x3e +#define fc_data_Tag_ID_ATSC 0x3f +#define fc_data_Tag_ID_IDSB 0x8b + u32 data_Tag_ID :16; + } data_tag_400; + + struct { + u32 Card_IDbyte6 : 8; + u32 Card_IDbyte5 : 8; + u32 Card_IDbyte4 : 8; + u32 Card_IDbyte3 : 8; + } card_id_408; + + struct { + u32 Card_IDbyte2 : 8; + u32 Card_IDbyte1 : 8; + } card_id_40c; + + /* holding the unique mac address of the receiver which houses the FlexCopIII */ + struct { + u32 MAC1 : 8; + u32 MAC2 : 8; + u32 MAC3 : 8; + u32 MAC6 : 8; + } mac_address_418; + + struct { + u32 MAC7 : 8; + u32 MAC8 : 8; + u32 reserved : 16; + } mac_address_41c; + + struct { + u32 transmitter_data_byte : 8; + u32 ReceiveDataReady : 1; + u32 ReceiveByteFrameError: 1; + u32 txbuffempty : 1; + u32 reserved :21; + } ci_600; + + struct { + u32 pi_d : 8; + u32 pi_ha :20; + u32 pi_rw : 1; + u32 pi_component_reg : 3; + } pi_604; + + struct { + u32 serialReset : 1; + u32 oncecycle_read : 1; + u32 Timer_Read_req : 1; + u32 Timer_Load_req : 1; + u32 timer_data : 7; + u32 unused : 1; /* ??? not mentioned in data book */ + u32 Timer_addr : 5; + u32 reserved : 3; + u32 pcmcia_a_mod_pwr_n : 1; + u32 pcmcia_b_mod_pwr_n : 1; + u32 config_Done_stat : 1; + u32 config_Init_stat : 1; + u32 config_Prog_n : 1; + u32 config_wr_n : 1; + u32 config_cs_n : 1; + u32 config_cclk : 1; + u32 pi_CiMax_IRQ_n : 1; + u32 pi_timeout_status : 1; + u32 pi_wait_n : 1; + u32 pi_busy_n : 1; + } pi_608; + + struct { + u32 PID :13; + u32 key_enable : 1; +#define fc_key_code_default 0x1 +#define fc_key_code_even 0x2 +#define fc_key_code_odd 0x3 + u32 key_code : 2; + u32 key_array_col : 3; + u32 key_array_row : 5; + u32 dvb_en : 1; /* 0=TS bypasses the Descrambler */ + u32 rw_flag : 1; + u32 reserved : 6; + } dvb_reg_60c; + +/* SRAM and Output Destination 0x700 to 0x714 */ + struct { + u32 sram_addr :15; + u32 sram_rw : 1; /* 0=write, 1=read */ + u32 sram_data : 8; + u32 sc_xfer_bit : 1; + u32 reserved1 : 3; + u32 oe_pin_reg : 1; + u32 ce_pin_reg : 1; + u32 reserved2 : 1; + u32 start_sram_ibi : 1; + } sram_ctrl_reg_700; + + struct { + u32 net_addr_read :16; + u32 net_addr_write :16; + } net_buf_reg_704; + + struct { + u32 cai_read :11; + u32 reserved1 : 5; + u32 cai_write :11; + u32 reserved2 : 6; + u32 cai_cnt : 4; + } cai_buf_reg_708; + + struct { + u32 cao_read :11; + u32 reserved1 : 5; + u32 cap_write :11; + u32 reserved2 : 6; + u32 cao_cnt : 4; + } cao_buf_reg_70c; + + struct { + u32 media_read :11; + u32 reserved1 : 5; + u32 media_write :11; + u32 reserved2 : 6; + u32 media_cnt : 4; + } media_buf_reg_710; + + struct { + u32 NET_Dest : 2; + u32 CAI_Dest : 2; + u32 CAO_Dest : 2; + u32 MEDIA_Dest : 2; + u32 net_ovflow_error : 1; + u32 media_ovflow_error : 1; + u32 cai_ovflow_error : 1; + u32 cao_ovflow_error : 1; + u32 ctrl_usb_wan : 1; + u32 ctrl_sramdma : 1; + u32 ctrl_maximumfill : 1; + u32 reserved :17; + } sram_dest_reg_714; + + struct { + u32 net_cnt :12; + u32 reserved1 : 4; + u32 net_addr_read : 1; + u32 reserved2 : 3; + u32 net_addr_write : 1; + u32 reserved3 :11; + } net_buf_reg_718; + + struct { + u32 wan_speed_sig : 2; + u32 reserved1 : 6; + u32 wan_wait_state : 8; + u32 sram_chip : 2; + u32 sram_memmap : 2; + u32 reserved2 : 4; + u32 wan_pkt_frame : 4; + u32 reserved3 : 4; + } wan_ctrl_reg_71c; +} flexcop_ibi_value; + +extern flexcop_ibi_value ibi_zero; + +typedef enum { + FC_I2C_PORT_DEMOD = 1, + FC_I2C_PORT_EEPROM = 2, + FC_I2C_PORT_TUNER = 3, +} flexcop_i2c_port_t; + +typedef enum { + FC_WRITE = 0, + FC_READ = 1, +} flexcop_access_op_t; + +typedef enum { + FC_SRAM_DEST_NET = 1, + FC_SRAM_DEST_CAI = 2, + FC_SRAM_DEST_CAO = 4, + FC_SRAM_DEST_MEDIA = 8 +} flexcop_sram_dest_t; + +typedef enum { + FC_SRAM_DEST_TARGET_WAN_USB = 0, + FC_SRAM_DEST_TARGET_DMA1 = 1, + FC_SRAM_DEST_TARGET_DMA2 = 2, + FC_SRAM_DEST_TARGET_FC3_CA = 3 +} flexcop_sram_dest_target_t; + +typedef enum { + FC_SRAM_2_32KB = 0, /* 64KB */ + FC_SRAM_1_32KB = 1, /* 32KB - default fow FCII */ + FC_SRAM_1_128KB = 2, /* 128KB */ + FC_SRAM_1_48KB = 3, /* 48KB - default for FCIII */ +} flexcop_sram_type_t; + +typedef enum { + FC_WAN_SPEED_4MBITS = 0, + FC_WAN_SPEED_8MBITS = 1, + FC_WAN_SPEED_12MBITS = 2, + FC_WAN_SPEED_16MBITS = 3, +} flexcop_wan_speed_t; + +typedef enum { + FC_DMA_1 = 1, + FC_DMA_2 = 2, +} flexcop_dma_index_t; + +typedef enum { + FC_DMA_SUBADDR_0 = 1, + FC_DMA_SUBADDR_1 = 2, +} flexcop_dma_addr_index_t; + +/* names of the particular registers */ +typedef enum { + dma1_000 = 0x000, + dma1_004 = 0x004, + dma1_008 = 0x008, + dma1_00c = 0x00c, + dma2_010 = 0x010, + dma2_014 = 0x014, + dma2_018 = 0x018, + dma2_01c = 0x01c, + + tw_sm_c_100 = 0x100, + tw_sm_c_104 = 0x104, + tw_sm_c_108 = 0x108, + tw_sm_c_10c = 0x10c, + tw_sm_c_110 = 0x110, + + lnb_switch_freq_200 = 0x200, + misc_204 = 0x204, + ctrl_208 = 0x208, + irq_20c = 0x20c, + sw_reset_210 = 0x210, + misc_214 = 0x214, + mbox_v8_to_host_218 = 0x218, + mbox_host_to_v8_21c = 0x21c, + + pid_filter_300 = 0x300, + pid_filter_304 = 0x304, + pid_filter_308 = 0x308, + pid_filter_30c = 0x30c, + index_reg_310 = 0x310, + pid_n_reg_314 = 0x314, + mac_low_reg_318 = 0x318, + mac_high_reg_31c = 0x31c, + + data_tag_400 = 0x400, + card_id_408 = 0x408, + card_id_40c = 0x40c, + mac_address_418 = 0x418, + mac_address_41c = 0x41c, + + ci_600 = 0x600, + pi_604 = 0x604, + pi_608 = 0x608, + dvb_reg_60c = 0x60c, + + sram_ctrl_reg_700 = 0x700, + net_buf_reg_704 = 0x704, + cai_buf_reg_708 = 0x708, + cao_buf_reg_70c = 0x70c, + media_buf_reg_710 = 0x710, + sram_dest_reg_714 = 0x714, + net_buf_reg_718 = 0x718, + wan_ctrl_reg_71c = 0x71c, +} flexcop_ibi_register; + +#define flexcop_set_ibi_value(reg,attr,val) \ + flexcop_ibi_value v = fc->read_ibi_reg(fc,reg); \ + v.reg.attr = val; \ + fc->write_ibi_reg(fc,reg,v); \ + +#endif diff --git a/drivers/media/dvb/b2c2/flexcop-sram.c b/drivers/media/dvb/b2c2/flexcop-sram.c new file mode 100644 index 00000000000..01570ec8096 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-sram.c @@ -0,0 +1,403 @@ +/* + * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * flexcop-sram.c - functions for controlling the SRAM. + * + * see flexcop.c for copyright information. + */ +#include "flexcop.h" + +static void flexcop_sram_set_chip (struct flexcop_device *fc, flexcop_sram_type_t type) +{ + flexcop_set_ibi_value(wan_ctrl_reg_71c,sram_chip,type); +} + +int flexcop_sram_init(struct flexcop_device *fc) +{ + switch (fc->rev) { + case FLEXCOP_II: + case FLEXCOP_IIB: + flexcop_sram_set_chip(fc,FC_SRAM_1_32KB); + break; + case FLEXCOP_III: + flexcop_sram_set_chip(fc,FC_SRAM_1_48KB); + break; + default: + return -EINVAL; + } + return 0; +} + +int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target) +{ + flexcop_ibi_value v; + + v = fc->read_ibi_reg(fc,sram_dest_reg_714); + + if (fc->rev != FLEXCOP_III && target == FC_SRAM_DEST_TARGET_FC3_CA) { + err("SRAM destination target to available on FlexCopII(b)\n"); + return -EINVAL; + } + + deb_sram("sram dest: %x target: %x\n",dest, target); + + if (dest & FC_SRAM_DEST_NET) + v.sram_dest_reg_714.NET_Dest = target; + if (dest & FC_SRAM_DEST_CAI) + v.sram_dest_reg_714.CAI_Dest = target; + if (dest & FC_SRAM_DEST_CAO) + v.sram_dest_reg_714.CAO_Dest = target; + if (dest & FC_SRAM_DEST_MEDIA) + v.sram_dest_reg_714.MEDIA_Dest = target; + + fc->write_ibi_reg(fc,sram_dest_reg_714,v); + udelay(1000); /* TODO delay really necessary */ + + return 0; +} +EXPORT_SYMBOL(flexcop_sram_set_dest); + +void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s) +{ + flexcop_set_ibi_value(wan_ctrl_reg_71c,wan_speed_sig,s); +} +EXPORT_SYMBOL(flexcop_wan_set_speed); + +void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill) +{ + flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714); + v.sram_dest_reg_714.ctrl_usb_wan = usb_wan; + v.sram_dest_reg_714.ctrl_sramdma = sramdma; + v.sram_dest_reg_714.ctrl_maximumfill = maximumfill; + fc->write_ibi_reg(fc,sram_dest_reg_714,v); +} +EXPORT_SYMBOL(flexcop_sram_ctrl); + +#if 0 +static void flexcop_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len) +{ + int i, retries; + u32 command; + + for (i = 0; i < len; i++) { + command = bank | addr | 0x04000000 | (*buf << 0x10); + + retries = 2; + + while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { + mdelay(1); + retries--; + }; + + if (retries == 0) + printk("%s: SRAM timeout\n", __FUNCTION__); + + write_reg_dw(adapter, 0x700, command); + + buf++; + addr++; + } +} + +static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len) +{ + int i, retries; + u32 command, value; + + for (i = 0; i < len; i++) { + command = bank | addr | 0x04008000; + + retries = 10000; + + while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { + mdelay(1); + retries--; + }; + + if (retries == 0) + printk("%s: SRAM timeout\n", __FUNCTION__); + + write_reg_dw(adapter, 0x700, command); + + retries = 10000; + + while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { + mdelay(1); + retries--; + }; + + if (retries == 0) + printk("%s: SRAM timeout\n", __FUNCTION__); + + value = read_reg_dw(adapter, 0x700) >> 0x10; + + *buf = (value & 0xff); + + addr++; + buf++; + } +} + +static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len) +{ + u32 bank; + + bank = 0; + + if (adapter->dw_sram_type == 0x20000) { + bank = (addr & 0x18000) << 0x0d; + } + + if (adapter->dw_sram_type == 0x00000) { + if ((addr >> 0x0f) == 0) + bank = 0x20000000; + else + bank = 0x10000000; + } + + flex_sram_write(adapter, bank, addr & 0x7fff, buf, len); +} + +static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len) +{ + u32 bank; + + bank = 0; + + if (adapter->dw_sram_type == 0x20000) { + bank = (addr & 0x18000) << 0x0d; + } + + if (adapter->dw_sram_type == 0x00000) { + if ((addr >> 0x0f) == 0) + bank = 0x20000000; + else + bank = 0x10000000; + } + + flex_sram_read(adapter, bank, addr & 0x7fff, buf, len); +} + +static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len) +{ + u32 length; + + while (len != 0) { + length = len; + + // check if the address range belongs to the same + // 32K memory chip. If not, the data is read from + // one chip at a time. + if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) { + length = (((addr >> 0x0f) + 1) << 0x0f) - addr; + } + + sram_read_chunk(adapter, addr, buf, length); + + addr = addr + length; + buf = buf + length; + len = len - length; + } +} + +static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len) +{ + u32 length; + + while (len != 0) { + length = len; + + // check if the address range belongs to the same + // 32K memory chip. If not, the data is written to + // one chip at a time. + if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) { + length = (((addr >> 0x0f) + 1) << 0x0f) - addr; + } + + sram_write_chunk(adapter, addr, buf, length); + + addr = addr + length; + buf = buf + length; + len = len - length; + } +} + +static void sram_set_size(struct adapter *adapter, u32 mask) +{ + write_reg_dw(adapter, 0x71c, (mask | (~0x30000 & read_reg_dw(adapter, 0x71c)))); +} + +static void sram_init(struct adapter *adapter) +{ + u32 tmp; + + tmp = read_reg_dw(adapter, 0x71c); + + write_reg_dw(adapter, 0x71c, 1); + + if (read_reg_dw(adapter, 0x71c) != 0) { + write_reg_dw(adapter, 0x71c, tmp); + + adapter->dw_sram_type = tmp & 0x30000; + + ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type); + + } else { + + adapter->dw_sram_type = 0x10000; + + ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type); + } + + /* return value is never used? */ +/* return adapter->dw_sram_type; */ +} + +static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr) +{ + u8 tmp1, tmp2; + + dprintk("%s: mask = %x, addr = %x\n", __FUNCTION__, mask, addr); + + sram_set_size(adapter, mask); + sram_init(adapter); + + tmp2 = 0xa5; + tmp1 = 0x4f; + + sram_write(adapter, addr, &tmp2, 1); + sram_write(adapter, addr + 4, &tmp1, 1); + + tmp2 = 0; + + mdelay(20); + + sram_read(adapter, addr, &tmp2, 1); + sram_read(adapter, addr, &tmp2, 1); + + dprintk("%s: wrote 0xa5, read 0x%2x\n", __FUNCTION__, tmp2); + + if (tmp2 != 0xa5) + return 0; + + tmp2 = 0x5a; + tmp1 = 0xf4; + + sram_write(adapter, addr, &tmp2, 1); + sram_write(adapter, addr + 4, &tmp1, 1); + + tmp2 = 0; + + mdelay(20); + + sram_read(adapter, addr, &tmp2, 1); + sram_read(adapter, addr, &tmp2, 1); + + dprintk("%s: wrote 0x5a, read 0x%2x\n", __FUNCTION__, tmp2); + + if (tmp2 != 0x5a) + return 0; + + return 1; +} + +static u32 sram_length(struct adapter *adapter) +{ + if (adapter->dw_sram_type == 0x10000) + return 32768; // 32K + if (adapter->dw_sram_type == 0x00000) + return 65536; // 64K + if (adapter->dw_sram_type == 0x20000) + return 131072; // 128K + + return 32768; // 32K +} + +/* FlexcopII can work with 32K, 64K or 128K of external SRAM memory. + - for 128K there are 4x32K chips at bank 0,1,2,3. + - for 64K there are 2x32K chips at bank 1,2. + - for 32K there is one 32K chip at bank 0. + + FlexCop works only with one bank at a time. The bank is selected + by bits 28-29 of the 0x700 register. + + bank 0 covers addresses 0x00000-0x07fff + bank 1 covers addresses 0x08000-0x0ffff + bank 2 covers addresses 0x10000-0x17fff + bank 3 covers addresses 0x18000-0x1ffff +*/ + +static int flexcop_sram_detect(struct flexcop_device *fc) +{ + flexcop_ibi_value r208,r71c_0,vr71c_1; + + r208 = fc->read_ibi_reg(fc, ctrl_208); + fc->write_ibi_reg(fc, ctrl_208, ibi_zero); + + r71c_0 = fc->read_ibi_reg(fc, wan_ctrl_reg_71c); + + write_reg_dw(adapter, 0x71c, 1); + + tmp3 = read_reg_dw(adapter, 0x71c); + + dprintk("%s: tmp3 = %x\n", __FUNCTION__, tmp3); + + write_reg_dw(adapter, 0x71c, tmp2); + + // check for internal SRAM ??? + tmp3--; + if (tmp3 != 0) { + sram_set_size(adapter, 0x10000); + sram_init(adapter); + write_reg_dw(adapter, 0x208, tmp); + + dprintk("%s: sram size = 32K\n", __FUNCTION__); + + return 32; + } + + if (sram_test_location(adapter, 0x20000, 0x18000) != 0) { + sram_set_size(adapter, 0x20000); + sram_init(adapter); + write_reg_dw(adapter, 0x208, tmp); + + dprintk("%s: sram size = 128K\n", __FUNCTION__); + + return 128; + } + + if (sram_test_location(adapter, 0x00000, 0x10000) != 0) { + sram_set_size(adapter, 0x00000); + sram_init(adapter); + write_reg_dw(adapter, 0x208, tmp); + + dprintk("%s: sram size = 64K\n", __FUNCTION__); + + return 64; + } + + if (sram_test_location(adapter, 0x10000, 0x00000) != 0) { + sram_set_size(adapter, 0x10000); + sram_init(adapter); + write_reg_dw(adapter, 0x208, tmp); + + dprintk("%s: sram size = 32K\n", __FUNCTION__); + + return 32; + } + + sram_set_size(adapter, 0x10000); + sram_init(adapter); + write_reg_dw(adapter, 0x208, tmp); + + dprintk("%s: SRAM detection failed. Set to 32K \n", __FUNCTION__); + + return 0; +} + +static void sll_detect_sram_size(struct adapter *adapter) +{ + sram_detect_for_flex2(adapter); +} + +#endif diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c new file mode 100644 index 00000000000..5fa68febf3a --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-usb.c @@ -0,0 +1,530 @@ +/* + * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * flexcop-usb.c - covers the USB part. + * + * see flexcop.c for copyright information. + */ + +#define FC_LOG_PREFIX "flexcop_usb" +#include "flexcop-usb.h" +#include "flexcop-common.h" + +/* Version information */ +#define DRIVER_VERSION "0.1" +#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV USB Driver" +#define DRIVER_AUTHOR "Patrick Boettcher " + +/* debug */ +#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG +#define dprintk(level,args...) \ + do { if ((debug & level)) { printk(args); } } while (0) +#define debug_dump(b,l,method) {\ + int i; \ + for (i = 0; i < l; i++) method("%02x ", b[i]); \ + method("\n");\ +} + +#define DEBSTATUS "" +#else +#define dprintk(level,args...) +#define debug_dump(b,l,method) +#define DEBSTATUS " (debugging is not enabled)" +#endif + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS); +#undef DEBSTATUS + +#define deb_info(args...) dprintk(0x01,args) +#define deb_ts(args...) dprintk(0x02,args) +#define deb_ctrl(args...) dprintk(0x04,args) +#define deb_i2c(args...) dprintk(0x08,args) +#define deb_v8(args...) dprintk(0x10,args) + +/* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits + * in the IBI address, to make the V8 code simpler. + * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (these are the six bits used) + * in general: 0000 0HHH 000L LL00 + * IBI ADDRESS FORMAT: RHHH BLLL + * + * where R is the read(1)/write(0) bit, B is the busy bit + * and HHH and LLL are the two sets of three bits from the PCI address. + */ +#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70)) +#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4)) + +/* + * DKT 020228 + * - forget about this VENDOR_BUFFER_SIZE, read and write register + * deal with DWORD or 4 bytes, that should be should from now on + * - from now on, we don't support anything older than firm 1.00 + * I eliminated the write register as a 2 trip of writing hi word and lo word + * and force this to write only 4 bytes at a time. + * NOTE: this should work with all the firmware from 1.00 and newer + */ +static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI, u32 *val, u8 read) +{ + struct flexcop_usb *fc_usb = fc->bus_specific; + u8 request = read ? B2C2_USB_READ_REG : B2C2_USB_WRITE_REG; + u8 request_type = (read ? USB_DIR_IN : USB_DIR_OUT) | USB_TYPE_VENDOR; + u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) | (read ? 0x80 : 0); + + int len = usb_control_msg(fc_usb->udev, + read ? B2C2_USB_CTRL_PIPE_IN : B2C2_USB_CTRL_PIPE_OUT, + request, + request_type, /* 0xc0 read or 0x40 write*/ + wAddress, + 0, + val, + sizeof(u32), + B2C2_WAIT_FOR_OPERATION_RDW * HZ); + + if (len != sizeof(u32)) { + err("error while %s dword from %d (%d).",read ? "reading" : "writing", + wAddress,wRegOffsPCI); + return -EIO; + } + return 0; +} + +/* + * DKT 010817 - add support for V8 memory read/write and flash update + */ +static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb, + flexcop_usb_request_t req, u8 page, u16 wAddress, + u8 *pbBuffer,u32 buflen) +{ +// u8 dwRequestType; + u8 request_type = USB_TYPE_VENDOR; + u16 wIndex; + int nWaitTime,pipe,len; + + wIndex = page << 8; + + switch (req) { + case B2C2_USB_READ_V8_MEM: + nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ; + request_type |= USB_DIR_IN; +// dwRequestType = (u8) RTYPE_READ_V8_MEMORY; + pipe = B2C2_USB_CTRL_PIPE_IN; + break; + case B2C2_USB_WRITE_V8_MEM: + wIndex |= pbBuffer[0]; + request_type |= USB_DIR_OUT; + nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE; +// dwRequestType = (u8) RTYPE_WRITE_V8_MEMORY; + pipe = B2C2_USB_CTRL_PIPE_OUT; + break; + case B2C2_USB_FLASH_BLOCK: + request_type |= USB_DIR_OUT; + nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH; +// dwRequestType = (u8) RTYPE_WRITE_V8_FLASH; + pipe = B2C2_USB_CTRL_PIPE_OUT; + break; + default: + deb_info("unsupported request for v8_mem_req %x.\n",req); + return -EINVAL; + } + deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n",request_type,req, + wAddress,wIndex,buflen); + + len = usb_control_msg(fc_usb->udev,pipe, + req, + request_type, + wAddress, + wIndex, + pbBuffer, + buflen, + nWaitTime * HZ); + + debug_dump(pbBuffer,len,deb_v8); + + return len == buflen ? 0 : -EIO; +} + +#define bytes_left_to_read_on_page(paddr,buflen) \ + ((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \ + ? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK))) + +static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,flexcop_usb_request_t req, + flexcop_usb_mem_page_t page_start, u32 addr, int extended, u8 *buf, u32 len) +{ + int i,ret = 0; + u16 wMax; + u32 pagechunk = 0; + + switch(req) { + case B2C2_USB_READ_V8_MEM: wMax = USB_MEM_READ_MAX; break; + case B2C2_USB_WRITE_V8_MEM: wMax = USB_MEM_WRITE_MAX; break; + case B2C2_USB_FLASH_BLOCK: wMax = USB_FLASH_MAX; break; + default: + return -EINVAL; + break; + } + for (i = 0; i < len;) { + pagechunk = wMax < bytes_left_to_read_on_page(addr,len) ? wMax : bytes_left_to_read_on_page(addr,len); + deb_info("%x\n",(addr & V8_MEMORY_PAGE_MASK) | (V8_MEMORY_EXTENDED*extended)); + if ((ret = flexcop_usb_v8_memory_req(fc_usb,req, + page_start + (addr / V8_MEMORY_PAGE_SIZE), /* actual page */ + (addr & V8_MEMORY_PAGE_MASK) | (V8_MEMORY_EXTENDED*extended), + &buf[i],pagechunk)) < 0) + return ret; + + addr += pagechunk; + len -= pagechunk; + } + return 0; +} + +static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended) +{ + return flexcop_usb_memory_req(fc->bus_specific,B2C2_USB_READ_V8_MEM,V8_MEMORY_PAGE_FLASH,0x1f010,1,fc->mac_address,6); +} + +#if 0 +static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set, + flexcop_usb_utility_function_t func, u8 extra, u16 wIndex, + u16 buflen, u8 *pvBuffer) +{ + u16 wValue; + u8 request_type = (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR; +// u8 dwRequestType = (u8) RTYPE_GENERIC, + int nWaitTime = 2, + pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN, + len; + + wValue = (func << 8) | extra; + + len = usb_control_msg(fc_usb->udev,pipe, + B2C2_USB_UTILITY, + request_type, + wValue, + wIndex, + pvBuffer, + buflen, + nWaitTime * HZ); + return len == buflen ? 0 : -EIO; +} +#endif + +/* usb i2c stuff */ +static int flexcop_usb_i2c_req(struct flexcop_usb *fc_usb, + flexcop_usb_request_t req, flexcop_usb_i2c_function_t func, + flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u8 buflen) +{ + u16 wValue, wIndex; + int nWaitTime,pipe,len; +// u8 dwRequestType; + u8 request_type = USB_TYPE_VENDOR; + + switch (func) { + case USB_FUNC_I2C_WRITE: + case USB_FUNC_I2C_MULTIWRITE: + case USB_FUNC_I2C_REPEATWRITE: + /* DKT 020208 - add this to support special case of DiSEqC */ + case USB_FUNC_I2C_CHECKWRITE: + pipe = B2C2_USB_CTRL_PIPE_OUT; + nWaitTime = 2; +// dwRequestType = (u8) RTYPE_GENERIC; + request_type |= USB_DIR_OUT; + break; + case USB_FUNC_I2C_READ: + case USB_FUNC_I2C_REPEATREAD: + pipe = B2C2_USB_CTRL_PIPE_IN; + nWaitTime = 2; +// dwRequestType = (u8) RTYPE_GENERIC; + request_type |= USB_DIR_IN; + break; + default: + deb_info("unsupported function for i2c_req %x\n",func); + return -EINVAL; + } + wValue = (func << 8 ) | (port << 4); + wIndex = (chipaddr << 8 ) | addr; + + deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",func,request_type,req, + ((wValue && 0xff) << 8),wValue >> 8,((wIndex && 0xff) << 8),wIndex >> 8); + + len = usb_control_msg(fc_usb->udev,pipe, + req, + request_type, + wValue, + wIndex, + buf, + buflen, + nWaitTime * HZ); + + return len == buflen ? 0 : -EREMOTEIO; +} + +/* actual bus specific access functions, make sure prototype are/will be equal to pci */ +static flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register reg) +{ + flexcop_ibi_value val; + val.raw = 0; + flexcop_usb_readwrite_dw(fc,reg, &val.raw, 1); + return val; +} + +static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register reg, flexcop_ibi_value val) +{ + return flexcop_usb_readwrite_dw(fc,reg, &val.raw, 0); +} + +static int flexcop_usb_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op, + flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len) +{ + if (op == FC_READ) + return flexcop_usb_i2c_req(fc->bus_specific,B2C2_USB_I2C_REQUEST,USB_FUNC_I2C_READ,port,chipaddr,addr,buf,len); + else + return flexcop_usb_i2c_req(fc->bus_specific,B2C2_USB_I2C_REQUEST,USB_FUNC_I2C_WRITE,port,chipaddr,addr,buf,len); +} + +static void flexcop_usb_urb_complete(struct urb *urb, struct pt_regs *ptregs) +{ + struct flexcop_usb *fc_usb = urb->context; + int i; + + if (urb->actual_length > 0) + deb_ts("urb completed, bufsize: %d actlen; %d\n",urb->transfer_buffer_length, urb->actual_length); + + for (i = 0; i < urb->number_of_packets; i++) { + if (urb->iso_frame_desc[i].status < 0) { + err("iso frame descriptor %d has an error: %d\n",i,urb->iso_frame_desc[i].status); + } else + if (urb->iso_frame_desc[i].actual_length > 0) { + deb_ts("passed %d bytes to the demux\n",urb->iso_frame_desc[i].actual_length); + + flexcop_pass_dmx_data(fc_usb->fc_dev, + urb->transfer_buffer + urb->iso_frame_desc[i].offset, + urb->iso_frame_desc[i].actual_length); + } + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + + usb_submit_urb(urb,GFP_ATOMIC); +} + +static int flexcop_usb_stream_control(struct flexcop_device *fc, int onoff) +{ + /* submit/kill iso packets */ + return 0; +} + +static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb) +{ + int i; + for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) + if (fc_usb->iso_urb[i] != NULL) { + deb_ts("unlinking/killing urb no. %d\n",i); + usb_kill_urb(fc_usb->iso_urb[i]); + usb_free_urb(fc_usb->iso_urb[i]); + } + + if (fc_usb->iso_buffer != NULL) + pci_free_consistent(NULL,fc_usb->buffer_size, fc_usb->iso_buffer, fc_usb->dma_addr); +} + +static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb) +{ + u16 frame_size = fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize; + int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * frame_size,i,j,ret; + int buffer_offset = 0; + + deb_ts("creating %d iso-urbs with %d frames each of %d bytes size = %d.\n", + B2C2_USB_NUM_ISO_URB, B2C2_USB_FRAMES_PER_ISO, frame_size,bufsize); + + fc_usb->iso_buffer = pci_alloc_consistent(NULL,bufsize,&fc_usb->dma_addr); + if (fc_usb->iso_buffer == NULL) + return -ENOMEM; + memset(fc_usb->iso_buffer, 0, bufsize); + fc_usb->buffer_size = bufsize; + + /* creating iso urbs */ + for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) + if (!(fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,GFP_ATOMIC))) { + ret = -ENOMEM; + goto urb_error; + } + /* initialising and submitting iso urbs */ + for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) { + int frame_offset = 0; + struct urb *urb = fc_usb->iso_urb[i]; + deb_ts("initializing and submitting urb no. %d (buf_offset: %d).\n",i,buffer_offset); + + urb->dev = fc_usb->udev; + urb->context = fc_usb; + urb->complete = flexcop_usb_urb_complete; + urb->pipe = B2C2_USB_DATA_PIPE; + urb->transfer_flags = URB_ISO_ASAP; + urb->interval = 1; + urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO; + urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO; + urb->transfer_buffer = fc_usb->iso_buffer + buffer_offset; + + buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO; + for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) { + deb_ts("urb no: %d, frame: %d, frame_offset: %d\n",i,j,frame_offset); + urb->iso_frame_desc[j].offset = frame_offset; + urb->iso_frame_desc[j].length = frame_size; + frame_offset += frame_size; + } + + if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) { + err("submitting urb %d failed with %d.",i,ret); + goto urb_error; + } + deb_ts("submitted urb no. %d.\n",i); + } + +/* SRAM */ + + flexcop_sram_set_dest(fc_usb->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET | + FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_WAN_USB); + flexcop_wan_set_speed(fc_usb->fc_dev,FC_WAN_SPEED_8MBITS); + flexcop_sram_ctrl(fc_usb->fc_dev,1,1,1); + + ret = 0; + goto success; +urb_error: + flexcop_usb_transfer_exit(fc_usb); +success: + return ret; +} + +static int flexcop_usb_init(struct flexcop_usb *fc_usb) +{ + /* use the alternate setting with the larges buffer */ + usb_set_interface(fc_usb->udev,0,1); + switch (fc_usb->udev->speed) { + case USB_SPEED_LOW: + err("cannot handle USB speed because it is to sLOW."); + return -ENODEV; + break; + case USB_SPEED_FULL: + info("running at FULL speed."); + break; + case USB_SPEED_HIGH: + info("running at HIGH speed."); + break; + case USB_SPEED_UNKNOWN: /* fall through */ + default: + err("cannot handle USB speed because it is unkown."); + return -ENODEV; + } + usb_set_intfdata(fc_usb->uintf, fc_usb); + return 0; +} + +static void flexcop_usb_exit(struct flexcop_usb *fc_usb) +{ + usb_set_intfdata(fc_usb->uintf, NULL); +} + +static int flexcop_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct flexcop_usb *fc_usb = NULL; + struct flexcop_device *fc = NULL; + int ret; + + if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) { + err("out of memory\n"); + return -ENOMEM; + } + +/* general flexcop init */ + fc_usb = fc->bus_specific; + fc_usb->fc_dev = fc; + + fc->read_ibi_reg = flexcop_usb_read_ibi_reg; + fc->write_ibi_reg = flexcop_usb_write_ibi_reg; + fc->i2c_request = flexcop_usb_i2c_request; + fc->get_mac_addr = flexcop_usb_get_mac_addr; + + fc->stream_control = flexcop_usb_stream_control; + + fc->pid_filtering = 1; + fc->bus_type = FC_USB; + + fc->dev = &udev->dev; + +/* bus specific part */ + fc_usb->udev = udev; + fc_usb->uintf = intf; + if ((ret = flexcop_usb_init(fc_usb)) != 0) + goto err_kfree; + +/* init flexcop */ + if ((ret = flexcop_device_initialize(fc)) != 0) + goto err_usb_exit; + +/* xfer init */ + if ((ret = flexcop_usb_transfer_init(fc_usb)) != 0) + goto err_fc_exit; + + info("%s successfully initialized and connected.",DRIVER_NAME); + ret = 0; + goto success; +err_fc_exit: + flexcop_device_exit(fc); +err_usb_exit: + flexcop_usb_exit(fc_usb); +err_kfree: + flexcop_device_kfree(fc); +success: + return ret; +} + +static void flexcop_usb_disconnect(struct usb_interface *intf) +{ + struct flexcop_usb *fc_usb = usb_get_intfdata(intf); + flexcop_usb_transfer_exit(fc_usb); + flexcop_device_exit(fc_usb->fc_dev); + flexcop_usb_exit(fc_usb); + flexcop_device_kfree(fc_usb->fc_dev); + info("%s successfully deinitialized and disconnected.",DRIVER_NAME); +} + +static struct usb_device_id flexcop_usb_table [] = { + { USB_DEVICE(0x0af7, 0x0101) }, + { } +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver flexcop_usb_driver = { + .owner = THIS_MODULE, + .name = "Technisat/B2C2 FlexCop II/IIb/III USB", + .probe = flexcop_usb_probe, + .disconnect = flexcop_usb_disconnect, + .id_table = flexcop_usb_table, +}; + +/* module stuff */ +static int __init flexcop_usb_module_init(void) +{ + int result; + if ((result = usb_register(&flexcop_usb_driver))) { + err("usb_register failed. (%d)",result); + return result; + } + + return 0; +} + +static void __exit flexcop_usb_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&flexcop_usb_driver); +} + +module_init(flexcop_usb_module_init); +module_exit(flexcop_usb_module_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_NAME); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/b2c2/flexcop-usb.h b/drivers/media/dvb/b2c2/flexcop-usb.h new file mode 100644 index 00000000000..bfcec25ff2d --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-usb.h @@ -0,0 +1,116 @@ +#ifndef __FLEXCOP_USB_H_INCLUDED__ +#define __FLEXCOP_USB_H_INCLUDED__ + +#include + +/* transfer parameters */ +#define B2C2_USB_FRAMES_PER_ISO 4 +#define B2C2_USB_NUM_ISO_URB 4 + +#define B2C2_USB_CTRL_PIPE_IN usb_rcvctrlpipe(fc_usb->udev,0) +#define B2C2_USB_CTRL_PIPE_OUT usb_sndctrlpipe(fc_usb->udev,0) +#define B2C2_USB_DATA_PIPE usb_rcvisocpipe(fc_usb->udev,0x81) + +struct flexcop_usb { + struct usb_device *udev; + struct usb_interface *uintf; + + u8 *iso_buffer; + int buffer_size; + dma_addr_t dma_addr; + struct urb *iso_urb[B2C2_USB_NUM_ISO_URB]; + + struct flexcop_device *fc_dev; +}; + +#if 0 +/* request types TODO What is its use?*/ +typedef enum { + +/* something is wrong with this part + RTYPE_READ_DW = (1 << 6), + RTYPE_WRITE_DW_1 = (3 << 6), + RTYPE_READ_V8_MEMORY = (6 << 6), + RTYPE_WRITE_V8_MEMORY = (7 << 6), + RTYPE_WRITE_V8_FLASH = (8 << 6), + RTYPE_GENERIC = (9 << 6), +*/ +} flexcop_usb_request_type_t; +#endif + +/* request */ +typedef enum { + B2C2_USB_WRITE_V8_MEM = 0x04, + B2C2_USB_READ_V8_MEM = 0x05, + B2C2_USB_READ_REG = 0x08, + B2C2_USB_WRITE_REG = 0x0A, +/* B2C2_USB_WRITEREGLO = 0x0A, */ + B2C2_USB_WRITEREGHI = 0x0B, + B2C2_USB_FLASH_BLOCK = 0x10, + B2C2_USB_I2C_REQUEST = 0x11, + B2C2_USB_UTILITY = 0x12, +} flexcop_usb_request_t; + +/* function definition for I2C_REQUEST */ +typedef enum { + USB_FUNC_I2C_WRITE = 0x01, + USB_FUNC_I2C_MULTIWRITE = 0x02, + USB_FUNC_I2C_READ = 0x03, + USB_FUNC_I2C_REPEATWRITE = 0x04, + USB_FUNC_GET_DESCRIPTOR = 0x05, + USB_FUNC_I2C_REPEATREAD = 0x06, +/* DKT 020208 - add this to support special case of DiSEqC */ + USB_FUNC_I2C_CHECKWRITE = 0x07, + USB_FUNC_I2C_CHECKRESULT = 0x08, +} flexcop_usb_i2c_function_t; + +/* + * function definition for UTILITY request 0x12 + * DKT 020304 - new utility function + */ +typedef enum { + UTILITY_SET_FILTER = 0x01, + UTILITY_DATA_ENABLE = 0x02, + UTILITY_FLEX_MULTIWRITE = 0x03, + UTILITY_SET_BUFFER_SIZE = 0x04, + UTILITY_FLEX_OPERATOR = 0x05, + UTILITY_FLEX_RESET300_START = 0x06, + UTILITY_FLEX_RESET300_STOP = 0x07, + UTILITY_FLEX_RESET300 = 0x08, + UTILITY_SET_ISO_SIZE = 0x09, + UTILITY_DATA_RESET = 0x0A, + UTILITY_GET_DATA_STATUS = 0x10, + UTILITY_GET_V8_REG = 0x11, +/* DKT 020326 - add function for v1.14 */ + UTILITY_SRAM_WRITE = 0x12, + UTILITY_SRAM_READ = 0x13, + UTILITY_SRAM_TESTFILL = 0x14, + UTILITY_SRAM_TESTSET = 0x15, + UTILITY_SRAM_TESTVERIFY = 0x16, +} flexcop_usb_utility_function_t; + +#define B2C2_WAIT_FOR_OPERATION_RW 1*HZ /* 1 s */ +#define B2C2_WAIT_FOR_OPERATION_RDW 3*HZ /* 3 s */ +#define B2C2_WAIT_FOR_OPERATION_WDW 1*HZ /* 1 s */ + +#define B2C2_WAIT_FOR_OPERATION_V8READ 3*HZ /* 3 s */ +#define B2C2_WAIT_FOR_OPERATION_V8WRITE 3*HZ /* 3 s */ +#define B2C2_WAIT_FOR_OPERATION_V8FLASH 3*HZ /* 3 s */ + +typedef enum { + V8_MEMORY_PAGE_DVB_CI = 0x20, + V8_MEMORY_PAGE_DVB_DS = 0x40, + V8_MEMORY_PAGE_MULTI2 = 0x60, + V8_MEMORY_PAGE_FLASH = 0x80 +} flexcop_usb_mem_page_t; + +#define V8_MEMORY_EXTENDED (1 << 15) + +#define USB_MEM_READ_MAX 32 +#define USB_MEM_WRITE_MAX 1 +#define USB_FLASH_MAX 8 + +#define V8_MEMORY_PAGE_SIZE 0x8000 // 32K +#define V8_MEMORY_PAGE_MASK 0x7FFF + +#endif diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c new file mode 100644 index 00000000000..1998267207f --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop.c @@ -0,0 +1,288 @@ +/* + * flexcop.c - driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * Copyright (C) 2004-5 Patrick Boettcher + * + * based on the skystar2-driver + * Copyright (C) 2003 Vadim Catana, skystar@moldova.cc + * + * Acknowledgements: + * John Jurrius from BBTI, Inc. for extensive support with + * code examples and data books + * + * Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting) + * + * Contributions to the skystar2-driver have been done by + * Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes) + * Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code) + * Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac filtering) + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser 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 "flexcop.h" + +#define DRIVER_NAME "B2C2 FlexcopII/II(b)/III digital TV receiver chip" +#define DRIVER_AUTHOR "Patrick Boettcher demux->priv; + return flexcop_pid_feed_control(fc,dvbdmxfeed,1); +} + +static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct flexcop_device *fc = dvbdmxfeed->demux->priv; + return flexcop_pid_feed_control(fc,dvbdmxfeed,0); +} + +static int flexcop_dvb_init(struct flexcop_device *fc) +{ + int ret; + if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",THIS_MODULE)) < 0) { + err("error registering DVB adapter"); + return ret; + } + fc->dvb_adapter.priv = fc; + + fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); + fc->demux.priv = fc; + + fc->demux.filternum = fc->demux.feednum = FC_MAX_FEED; + + fc->demux.start_feed = flexcop_dvb_start_feed; + fc->demux.stop_feed = flexcop_dvb_stop_feed; + fc->demux.write_to_decoder = NULL; + + if ((ret = dvb_dmx_init(&fc->demux)) < 0) { + err("dvb_dmx failed: error %d",ret); + goto err_dmx; + } + + fc->hw_frontend.source = DMX_FRONTEND_0; + + fc->dmxdev.filternum = fc->demux.feednum; + fc->dmxdev.demux = &fc->demux.dmx; + fc->dmxdev.capabilities = 0; + if ((ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter)) < 0) { + err("dvb_dmxdev_init failed: error %d",ret); + goto err_dmx_dev; + } + + if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) { + err("adding hw_frontend to dmx failed: error %d",ret); + goto err_dmx_add_hw_frontend; + } + + fc->mem_frontend.source = DMX_MEMORY_FE; + if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend)) < 0) { + err("adding mem_frontend to dmx failed: error %d",ret); + goto err_dmx_add_mem_frontend; + } + + if ((ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) { + err("connect frontend failed: error %d",ret); + goto err_connect_frontend; + } + + dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx); + + fc->init_state |= FC_STATE_DVB_INIT; + goto success; + +err_connect_frontend: + fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->mem_frontend); +err_dmx_add_mem_frontend: + fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->hw_frontend); +err_dmx_add_hw_frontend: + dvb_dmxdev_release(&fc->dmxdev); +err_dmx_dev: + dvb_dmx_release(&fc->demux); +err_dmx: + dvb_unregister_adapter(&fc->dvb_adapter); + return ret; + +success: + return 0; +} + +static void flexcop_dvb_exit(struct flexcop_device *fc) +{ + if (fc->init_state & FC_STATE_DVB_INIT) { + dvb_net_release(&fc->dvbnet); + + fc->demux.dmx.close(&fc->demux.dmx); + fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->mem_frontend); + fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->hw_frontend); + dvb_dmxdev_release(&fc->dmxdev); + dvb_dmx_release(&fc->demux); + dvb_unregister_adapter(&fc->dvb_adapter); + + deb_info("deinitialized dvb stuff\n"); + } + fc->init_state &= ~FC_STATE_DVB_INIT; +} + +/* these methods are necessary to achieve the long-term-goal of hiding the + * struct flexcop_device from the bus-parts */ +void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len) +{ + dvb_dmx_swfilter(&fc->demux, buf, len); +} +EXPORT_SYMBOL(flexcop_pass_dmx_data); + +void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no) +{ + dvb_dmx_swfilter_packets(&fc->demux, buf, no); +} +EXPORT_SYMBOL(flexcop_pass_dmx_packets); + +static void flexcop_reset(struct flexcop_device *fc) +{ + flexcop_ibi_value v210,v204; + +/* reset the flexcop itself */ + fc->write_ibi_reg(fc,ctrl_208,ibi_zero); + + v210.raw = 0; + v210.sw_reset_210.reset_blocks = 0xff; + v210.sw_reset_210.Block_reset_enable = 0xb2; + fc->write_ibi_reg(fc,sw_reset_210,v210); + +/* reset the periphical devices */ + + v204 = fc->read_ibi_reg(fc,misc_204); + v204.misc_204.Per_reset_sig = 0; + fc->write_ibi_reg(fc,misc_204,v204); + v204.misc_204.Per_reset_sig = 1; + fc->write_ibi_reg(fc,misc_204,v204); + +/* v208.raw = 0; + v208.ctrl_208.Null_filter_sig = 1; + fc->write_ibi_reg(fc,ctrl_208,v208);*/ +} + +struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len) +{ + void *bus; + struct flexcop_device *fc = kmalloc(sizeof(struct flexcop_device), GFP_KERNEL); + if (!fc) { + err("no memory"); + return NULL; + } + memset(fc, 0, sizeof(struct flexcop_device)); + + bus = kmalloc(bus_specific_len, GFP_KERNEL); + if (!bus) { + err("no memory"); + kfree(fc); + return NULL; + } + memset(bus, 0, bus_specific_len); + + fc->bus_specific = bus; + + return fc; +} +EXPORT_SYMBOL(flexcop_device_kmalloc); + +void flexcop_device_kfree(struct flexcop_device *fc) +{ + kfree(fc->bus_specific); + kfree(fc); +} +EXPORT_SYMBOL(flexcop_device_kfree); + +int flexcop_device_initialize(struct flexcop_device *fc) +{ + int ret; + ibi_zero.raw = 0; + + flexcop_reset(fc); + flexcop_determine_revision(fc); + flexcop_sram_init(fc); + flexcop_hw_filter_init(fc); + + flexcop_smc_ctrl(fc, 0); + + if (fc->get_mac_addr(fc, 0) == 0) { + u8 *b = fc->mac_address; + info("MAC address = %02x:%02x:%02x:%02x:%02x:%02x", b[0],b[1],b[2],b[3],b[4],b[5]); + flexcop_set_mac_filter(fc,fc->mac_address); + flexcop_mac_filter_ctrl(fc,1); + } else + warn("reading of MAC address failed.\n"); + + if ((ret = flexcop_dvb_init(fc))) + goto error; + + if ((ret = flexcop_i2c_init(fc))) + goto error; + + if ((ret = flexcop_frontend_init(fc))) + goto error; + + flexcop_device_name(fc,"initialization of","complete"); + + ret = 0; + goto success; +error: + flexcop_device_exit(fc); +success: + return ret; +} +EXPORT_SYMBOL(flexcop_device_initialize); + +void flexcop_device_exit(struct flexcop_device *fc) +{ + flexcop_frontend_exit(fc); + flexcop_i2c_exit(fc); + flexcop_dvb_exit(fc); +} +EXPORT_SYMBOL(flexcop_device_exit); + +static int flexcop_module_init(void) +{ + info(DRIVER_NAME " loaded successfully"); + return 0; +} + +static void flexcop_module_cleanup(void) +{ + info(DRIVER_NAME " unloaded successfully"); +} + +module_init(flexcop_module_init); +module_exit(flexcop_module_cleanup); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_NAME); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/b2c2/flexcop.h b/drivers/media/dvb/b2c2/flexcop.h new file mode 100644 index 00000000000..caa343a97bd --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop.h @@ -0,0 +1,30 @@ +/* + * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * flexcop.h - private header file for all flexcop-chip-source files. + * + * see flexcop.c for copyright information. + */ +#ifndef __FLEXCOP_H__ +#define __FLEXCOP_H___ + +#define FC_LOG_PREFIX "b2c2-flexcop" +#include "flexcop-common.h" + +extern int b2c2_flexcop_debug; + +/* debug */ +#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG +#define dprintk(level,args...) \ + do { if ((b2c2_flexcop_debug & level)) printk(args); } while (0) +#else +#define dprintk(level,args...) +#endif + +#define deb_info(args...) dprintk(0x01,args) +#define deb_tuner(args...) dprintk(0x02,args) +#define deb_i2c(args...) dprintk(0x04,args) +#define deb_ts(args...) dprintk(0x08,args) +#define deb_sram(args...) dprintk(0x10,args) + +#endif -- cgit v1.2.3 From 7635acd2d927578495c692056d0e7dabd06afc89 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:12 -0700 Subject: [PATCH] dvb: flexcop: fix USB transfer handling - driver receives many null TS packets (pid=0x1fff). They occupy the limited USB bandwidth and this leads to loss of video packets. Enabling the null packet filter fixes this. - packets that flexcop sends to USB have a 2 byte header that has to be removed. - sometimes a TS packet is split between different urbs. These parts have to be combined in a temporary buffer. Signed-off-by: Vadim Catana Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/b2c2/flexcop-hw-filter.c | 9 ++++-- drivers/media/dvb/b2c2/flexcop-usb.c | 47 +++++++++++++++++++++++++++++- drivers/media/dvb/b2c2/flexcop-usb.h | 3 ++ 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/b2c2/flexcop-hw-filter.c b/drivers/media/dvb/b2c2/flexcop-hw-filter.c index db983d704ff..7a5399b569c 100644 --- a/drivers/media/dvb/b2c2/flexcop-hw-filter.c +++ b/drivers/media/dvb/b2c2/flexcop-hw-filter.c @@ -159,7 +159,7 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d } else if (fc->feedcount == onoff && !onoff) { if (!fc->pid_filtering) { deb_ts("disabling full TS transfer\n"); - flexcop_pid_group_filter(fc, 0x1fe0,0); + flexcop_pid_group_filter(fc, 0, 0x1fe0); flexcop_pid_group_filter_ctrl(fc,0); } @@ -175,7 +175,7 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d flexcop_pid_group_filter(fc, 0,0); flexcop_pid_group_filter_ctrl(fc,1); } else if (fc->pid_filtering && fc->feedcount <= max_pid_filter) { - flexcop_pid_group_filter(fc, 0x1fe0,0); + flexcop_pid_group_filter(fc, 0,0x1fe0); flexcop_pid_group_filter_ctrl(fc,0); } @@ -189,10 +189,13 @@ void flexcop_hw_filter_init(struct flexcop_device *fc) for (i = 0; i < 6 + 32*fc->has_32_hw_pid_filter; i++) flexcop_pid_control(fc,i,0x1fff,0); - flexcop_pid_group_filter(fc, 0x1fe0,0); + flexcop_pid_group_filter(fc, 0, 0x1fe0); + flexcop_pid_group_filter_ctrl(fc,0); v = fc->read_ibi_reg(fc,pid_filter_308); v.pid_filter_308.EMM_filter_4 = 1; v.pid_filter_308.EMM_filter_6 = 0; fc->write_ibi_reg(fc,pid_filter_308,v); + + flexcop_null_filter_ctrl(fc, 1); } diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c index 5fa68febf3a..98470ce9a05 100644 --- a/drivers/media/dvb/b2c2/flexcop-usb.c +++ b/drivers/media/dvb/b2c2/flexcop-usb.c @@ -282,6 +282,51 @@ static int flexcop_usb_i2c_request(struct flexcop_device *fc, flexcop_access_op_ return flexcop_usb_i2c_req(fc->bus_specific,B2C2_USB_I2C_REQUEST,USB_FUNC_I2C_WRITE,port,chipaddr,addr,buf,len); } +static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb, u8 *buffer, int buffer_length) +{ + u8 *b; + int l; + + deb_ts("tmp_buffer_length=%d, buffer_length=%d\n", fc_usb->tmp_buffer_length, buffer_length); + + if (fc_usb->tmp_buffer_length > 0) { + memcpy(fc_usb->tmp_buffer+fc_usb->tmp_buffer_length, buffer, buffer_length); + fc_usb->tmp_buffer_length += buffer_length; + b = fc_usb->tmp_buffer; + l = fc_usb->tmp_buffer_length; + } else { + b=buffer; + l=buffer_length; + } + + while (l >= 190) { + if (*b == 0xff) + switch (*(b+1) & 0x03) { + case 0x01: /* media packet */ + if ( *(b+2) == 0x47 ) + flexcop_pass_dmx_packets(fc_usb->fc_dev, b+2, 1); + else + deb_ts("not ts packet %02x %02x %02x %02x \n", *(b+2), *(b+3), *(b+4), *(b+5) ); + + b += 190; + l -= 190; + break; + default: + deb_ts("wrong packet type\n"); + l = 0; + break; + } + else { + deb_ts("wrong header\n"); + l = 0; + } + } + + if (l>0) + memcpy(fc_usb->tmp_buffer, b, l); + fc_usb->tmp_buffer_length = l; +} + static void flexcop_usb_urb_complete(struct urb *urb, struct pt_regs *ptregs) { struct flexcop_usb *fc_usb = urb->context; @@ -297,7 +342,7 @@ static void flexcop_usb_urb_complete(struct urb *urb, struct pt_regs *ptregs) if (urb->iso_frame_desc[i].actual_length > 0) { deb_ts("passed %d bytes to the demux\n",urb->iso_frame_desc[i].actual_length); - flexcop_pass_dmx_data(fc_usb->fc_dev, + flexcop_usb_process_frame(fc_usb, urb->transfer_buffer + urb->iso_frame_desc[i].offset, urb->iso_frame_desc[i].actual_length); } diff --git a/drivers/media/dvb/b2c2/flexcop-usb.h b/drivers/media/dvb/b2c2/flexcop-usb.h index bfcec25ff2d..630e647a2ca 100644 --- a/drivers/media/dvb/b2c2/flexcop-usb.h +++ b/drivers/media/dvb/b2c2/flexcop-usb.h @@ -21,6 +21,9 @@ struct flexcop_usb { struct urb *iso_urb[B2C2_USB_NUM_ISO_URB]; struct flexcop_device *fc_dev; + + u8 tmp_buffer[1023+190]; + int tmp_buffer_length; }; #if 0 -- cgit v1.2.3 From 3ed8a31cb387b2ae3e4ca508f973931b61e6f6bd Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:13 -0700 Subject: [PATCH] dvb: flexcop: add acknowledgements add acknowledgements Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/dvb/README.flexcop | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/dvb/README.flexcop b/Documentation/dvb/README.flexcop index 9ec735714e4..8036faa1ead 100644 --- a/Documentation/dvb/README.flexcop +++ b/Documentation/dvb/README.flexcop @@ -274,6 +274,11 @@ Acknowledgements (just for the rewriting part) Bjarne Steinsbo thought a lot in the first place of the pci part for this code sharing idea. -Andreas Oberritter for providing a recent PCI initialization template (pluto2.c). +Andreas Oberritter for providing a recent PCI initialization template +(pluto2.c). + +Boleslaw Ciesielski for pointing out a problem with firmware loader. + +Vadim Catana for correcting the USB transfer. comments, critics and ideas to linux-dvb@linuxtv.org or patrick.boettcher@desy.de -- cgit v1.2.3 From 778241313819e17de3bdf91523c724b4704402c6 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:14 -0700 Subject: [PATCH] dvb: flexcop: fix MAC address reading read MAC address directly into dvb_adapter->proposed_mac Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/b2c2/flexcop-common.h | 1 - drivers/media/dvb/b2c2/flexcop-eeprom.c | 10 +++------- drivers/media/dvb/b2c2/flexcop-usb.c | 3 ++- drivers/media/dvb/b2c2/flexcop.c | 10 ++++++---- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h index 82b7f8fa7b9..534876d616b 100644 --- a/drivers/media/dvb/b2c2/flexcop-common.h +++ b/drivers/media/dvb/b2c2/flexcop-common.h @@ -57,7 +57,6 @@ struct flexcop_device { int init_state; /* device information */ - u8 mac_address[6]; int has_32_hw_pid_filter; flexcop_revision_t rev; flexcop_device_type_t dev_type; diff --git a/drivers/media/dvb/b2c2/flexcop-eeprom.c b/drivers/media/dvb/b2c2/flexcop-eeprom.c index 4dbedd81973..bbcf070a178 100644 --- a/drivers/media/dvb/b2c2/flexcop-eeprom.c +++ b/drivers/media/dvb/b2c2/flexcop-eeprom.c @@ -129,8 +129,6 @@ static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, u8 *buf, return ret; } -/* TODO how is it handled in USB */ - /* JJ's comment about extended == 1: it is not presently used anywhere but was * added to the low-level functions for possible support of EUI64 */ @@ -139,18 +137,16 @@ int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended) u8 buf[8]; int ret = 0; - memset(fc->mac_address,0,6); - if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) { if (extended != 0) { err("TODO: extended (EUI64) MAC addresses aren't completely supported yet"); ret = -EINVAL; -/* memcpy(fc->mac_address,buf,3); +/* memcpy(fc->dvb_adapter.proposed_mac,buf,3); mac[3] = 0xfe; mac[4] = 0xff; - memcpy(&fc->mac_address[3],&buf[5],3); */ + memcpy(&fc->dvb_adapter.proposed_mac[3],&buf[5],3); */ } else - memcpy(fc->mac_address,buf,6); + memcpy(fc->dvb_adapter.proposed_mac,buf,6); } return ret; } diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c index 98470ce9a05..20db6329a68 100644 --- a/drivers/media/dvb/b2c2/flexcop-usb.c +++ b/drivers/media/dvb/b2c2/flexcop-usb.c @@ -180,7 +180,8 @@ static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,flexcop_usb_request static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended) { - return flexcop_usb_memory_req(fc->bus_specific,B2C2_USB_READ_V8_MEM,V8_MEMORY_PAGE_FLASH,0x1f010,1,fc->mac_address,6); + return flexcop_usb_memory_req(fc->bus_specific,B2C2_USB_READ_V8_MEM, + V8_MEMORY_PAGE_FLASH,0x1f010,1,fc->dvb_adapter.proposed_mac,6); } #if 0 diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c index 1998267207f..ad590875064 100644 --- a/drivers/media/dvb/b2c2/flexcop.c +++ b/drivers/media/dvb/b2c2/flexcop.c @@ -233,16 +233,18 @@ int flexcop_device_initialize(struct flexcop_device *fc) flexcop_smc_ctrl(fc, 0); + if ((ret = flexcop_dvb_init(fc))) + goto error; + + /* do the MAC address reading after initializing the dvb_adapter */ if (fc->get_mac_addr(fc, 0) == 0) { - u8 *b = fc->mac_address; + u8 *b = fc->dvb_adapter.proposed_mac; info("MAC address = %02x:%02x:%02x:%02x:%02x:%02x", b[0],b[1],b[2],b[3],b[4],b[5]); - flexcop_set_mac_filter(fc,fc->mac_address); + flexcop_set_mac_filter(fc,b); flexcop_mac_filter_ctrl(fc,1); } else warn("reading of MAC address failed.\n"); - if ((ret = flexcop_dvb_init(fc))) - goto error; if ((ret = flexcop_i2c_init(fc))) goto error; -- cgit v1.2.3 From 4853f16ad881194ec4c49f73287ef1999b2585ea Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:15 -0700 Subject: [PATCH] dvb: flexcop: fixed interrupt-sharing fixed interrupt-sharing and added a spinlock to the irq-callback (thanks to Pascal Riekenberg) Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/b2c2/flexcop-pci.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c index 693af41f337..c52286ea669 100644 --- a/drivers/media/dvb/b2c2/flexcop-pci.c +++ b/drivers/media/dvb/b2c2/flexcop-pci.c @@ -53,6 +53,8 @@ struct flexcop_pci { int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */ u32 last_dma1_cur_pos; /* position of the pointer last time the timer/packet irq occured */ + spinlock_t irq_lock; + struct flexcop_device *fc_dev; }; @@ -93,6 +95,9 @@ static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs) struct flexcop_pci *fc_pci = dev_id; struct flexcop_device *fc = fc_pci->fc_dev; flexcop_ibi_value v = fc->read_ibi_reg(fc,irq_20c); + irqreturn_t ret = IRQ_HANDLED; + + spin_lock_irq(&fc_pci->irq_lock); deb_irq("irq: %08x cur_addr: %08x (%d), our addrs. 1: %08x 2: %08x; 0x000: " "%08x, 0x00c: %08x\n",v.raw, @@ -102,6 +107,7 @@ static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs) fc->read_ibi_reg(fc,dma1_000).raw, fc->read_ibi_reg(fc,dma1_00c).raw); + if (v.irq_20c.DMA1_IRQ_Status == 1) { if (fc_pci->active_dma1_addr == 0) flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr0,fc_pci->dma[0].size / 188); @@ -134,14 +140,17 @@ static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs) } fc_pci->last_dma1_cur_pos = cur_pos; - } + } else + ret = IRQ_NONE; + + spin_unlock_irq(&fc_pci->irq_lock); /* packet count would be ideal for hw filtering, but it isn't working. Either * the data book is wrong, or I'm unable to read it correctly */ /* if (v.irq_20c.DMA1_Size_IRQ_Status == 1) { packet counter */ - return IRQ_HANDLED; + return ret; } static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff) @@ -240,6 +249,8 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci) SA_SHIRQ, DRIVER_NAME, fc_pci)) != 0) goto err_pci_iounmap; + spin_lock_init(&fc_pci->irq_lock); + fc_pci->init_state |= FC_PCI_INIT; goto success; -- cgit v1.2.3 From c4ee3fd469302884dda95e1f310d5ffcd9f5acf9 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:15 -0700 Subject: [PATCH] dvb: flexcop: use hw pid filter - enabled the HW PID by default for the PCI cards - correct the TS demux parsing when PID filter is enabled (and thus the timer IRQ) - rewrote the PID-filter and FULLTS control part in flexcop-hw-filter (thanks to Krzysztof Matula for pointing that out) Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/b2c2/flexcop-common.h | 2 + drivers/media/dvb/b2c2/flexcop-hw-filter.c | 73 ++++++++++++++++-------------- drivers/media/dvb/b2c2/flexcop-pci.c | 28 +++++++----- 3 files changed, 56 insertions(+), 47 deletions(-) diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h index 534876d616b..79e8581b4fb 100644 --- a/drivers/media/dvb/b2c2/flexcop-common.h +++ b/drivers/media/dvb/b2c2/flexcop-common.h @@ -76,8 +76,10 @@ struct flexcop_device { struct semaphore i2c_sem; /* options and status */ + int extra_feedcount; int feedcount; int pid_filtering; + int fullts_streaming_state; /* bus specific callbacks */ flexcop_ibi_value (*read_ibi_reg) (struct flexcop_device *, flexcop_ibi_register); diff --git a/drivers/media/dvb/b2c2/flexcop-hw-filter.c b/drivers/media/dvb/b2c2/flexcop-hw-filter.c index 7a5399b569c..2baf43d3ce8 100644 --- a/drivers/media/dvb/b2c2/flexcop-hw-filter.c +++ b/drivers/media/dvb/b2c2/flexcop-hw-filter.c @@ -104,6 +104,9 @@ static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc, u16 pid, int ono static void flexcop_pid_control(struct flexcop_device *fc, int index, u16 pid,int onoff) { + if (pid == 0x2000) + return; + deb_ts("setting pid: %5d %04x at index %d '%s'\n",pid,pid,index,onoff ? "on" : "off"); /* We could use bit magic here to reduce source code size. @@ -133,50 +136,50 @@ static void flexcop_pid_control(struct flexcop_device *fc, int index, u16 pid,in } } +static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc,int onoff) +{ + if (fc->fullts_streaming_state != onoff) { + deb_ts("%s full TS transfer\n",onoff ? "enabling" : "disabling"); + flexcop_pid_group_filter(fc, 0, 0x1fe0 * (!onoff)); + flexcop_pid_group_filter_ctrl(fc,onoff); + fc->fullts_streaming_state = onoff; + } + return 0; +} + int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff) { int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32; - fc->feedcount += (onoff ? 1 : -1); + fc->feedcount += onoff ? 1 : -1; + if (dvbdmxfeed->index >= max_pid_filter) + fc->extra_feedcount += onoff ? 1 : -1; - /* when doing hw pid filtering, set the pid */ - if (fc->pid_filtering) - flexcop_pid_control(fc,dvbdmxfeed->index,dvbdmxfeed->pid,onoff); + /* toggle complete-TS-streaming when: + * - pid_filtering is not enabled and it is the first or last feed requested + * - pid_filtering is enabled, + * - but the number of requested feeds is exceeded + * - or the requested pid is 0x2000 */ - /* if it was the first feed request */ - if (fc->feedcount == onoff && onoff) { - if (!fc->pid_filtering) { - deb_ts("enabling full TS transfer\n"); - flexcop_pid_group_filter(fc, 0,0); - flexcop_pid_group_filter_ctrl(fc,1); - } + if (!fc->pid_filtering && fc->feedcount == onoff) + flexcop_toggle_fullts_streaming(fc,onoff); - if (fc->stream_control) - fc->stream_control(fc,1); - flexcop_rcv_data_ctrl(fc,1); - - /* if there is no more feed left to feed */ - } else if (fc->feedcount == onoff && !onoff) { - if (!fc->pid_filtering) { - deb_ts("disabling full TS transfer\n"); - flexcop_pid_group_filter(fc, 0, 0x1fe0); - flexcop_pid_group_filter_ctrl(fc,0); - } - - flexcop_rcv_data_ctrl(fc,0); - if (fc->stream_control) - fc->stream_control(fc,0); + if (fc->pid_filtering) { + flexcop_pid_control(fc,dvbdmxfeed->index,dvbdmxfeed->pid,onoff); + + if (fc->extra_feedcount > 0) + flexcop_toggle_fullts_streaming(fc,1); + else if (dvbdmxfeed->pid == 0x2000) + flexcop_toggle_fullts_streaming(fc,onoff); + else + flexcop_toggle_fullts_streaming(fc,0); } - /* if pid_filtering is on and more pids than the hw-filter can provide are - * requested enable the whole bandwidth. - */ - if (fc->pid_filtering && fc->feedcount > max_pid_filter) { - flexcop_pid_group_filter(fc, 0,0); - flexcop_pid_group_filter_ctrl(fc,1); - } else if (fc->pid_filtering && fc->feedcount <= max_pid_filter) { - flexcop_pid_group_filter(fc, 0,0x1fe0); - flexcop_pid_group_filter_ctrl(fc,0); + /* if it was the first or last feed request change the stream-status */ + if (fc->feedcount == onoff) { + flexcop_rcv_data_ctrl(fc,onoff); + if (fc->stream_control) + fc->stream_control(fc,onoff); } return 0; diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c index c52286ea669..78952096fb7 100644 --- a/drivers/media/dvb/b2c2/flexcop-pci.c +++ b/drivers/media/dvb/b2c2/flexcop-pci.c @@ -9,7 +9,7 @@ #define FC_LOG_PREFIX "flexcop-pci" #include "flexcop-common.h" -static int enable_pid_filtering = 0; +static int enable_pid_filtering = 1; module_param(enable_pid_filtering, int, 0444); MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1"); @@ -45,13 +45,14 @@ struct flexcop_pci { void __iomem *io_mem; u32 irq; /* buffersize (at least for DMA1, need to be % 188 == 0, - * this is logic is required */ + * this logic is required */ #define FC_DEFAULT_DMA1_BUFSIZE (1280 * 188) #define FC_DEFAULT_DMA2_BUFSIZE (10 * 188) struct flexcop_dma dma[2]; int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */ u32 last_dma1_cur_pos; /* position of the pointer last time the timer/packet irq occured */ + int count; spinlock_t irq_lock; @@ -99,15 +100,6 @@ static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs) spin_lock_irq(&fc_pci->irq_lock); - deb_irq("irq: %08x cur_addr: %08x (%d), our addrs. 1: %08x 2: %08x; 0x000: " - "%08x, 0x00c: %08x\n",v.raw, - fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2, - fc_pci->active_dma1_addr, - fc_pci->dma[0].dma_addr0,fc_pci->dma[0].dma_addr1, - fc->read_ibi_reg(fc,dma1_000).raw, - fc->read_ibi_reg(fc,dma1_00c).raw); - - if (v.irq_20c.DMA1_IRQ_Status == 1) { if (fc_pci->active_dma1_addr == 0) flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr0,fc_pci->dma[0].size / 188); @@ -123,21 +115,28 @@ static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs) fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2; u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0; + deb_irq("irq: %08x cur_addr: %08x: cur_pos: %08x, last_cur_pos: %08x ", + v.raw,cur_addr,cur_pos,fc_pci->last_dma1_cur_pos); + /* buffer end was reached, restarted from the beginning * pass the data from last_cur_pos to the buffer end to the demux */ if (cur_pos < fc_pci->last_dma1_cur_pos) { + deb_irq(" end was reached: passing %d bytes ",(fc_pci->dma[0].size*2 - 1) - fc_pci->last_dma1_cur_pos); flexcop_pass_dmx_data(fc_pci->fc_dev, fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos, - (fc_pci->dma[0].size*2 - 1) - fc_pci->last_dma1_cur_pos); + (fc_pci->dma[0].size*2) - fc_pci->last_dma1_cur_pos); fc_pci->last_dma1_cur_pos = 0; + fc_pci->count = 0; } if (cur_pos > fc_pci->last_dma1_cur_pos) { + deb_irq(" passing %d bytes ",cur_pos - fc_pci->last_dma1_cur_pos); flexcop_pass_dmx_data(fc_pci->fc_dev, fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos, cur_pos - fc_pci->last_dma1_cur_pos); } + deb_irq("\n"); fc_pci->last_dma1_cur_pos = cur_pos; } else @@ -301,6 +300,11 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e fc->stream_control = flexcop_pci_stream_control; + if (enable_pid_filtering) + info("will use the HW PID filter."); + else + info("will pass the complete TS to the demuxer."); + fc->pid_filtering = enable_pid_filtering; fc->bus_type = FC_PCI; -- cgit v1.2.3 From 59a7ad6c1ed3a058d375d2e679d73805e4f851ac Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:16 -0700 Subject: [PATCH] dvb: flexcop: fix module refcount handling Corrected the THIS_MODULE handling for the flexcop-stuff and dvb-usb which lead to oopses because of misorganized module dependencies. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/b2c2/flexcop-common.h | 2 ++ drivers/media/dvb/b2c2/flexcop-pci.c | 1 + drivers/media/dvb/b2c2/flexcop-usb.c | 1 + drivers/media/dvb/b2c2/flexcop.c | 2 +- 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h index 79e8581b4fb..773d158032d 100644 --- a/drivers/media/dvb/b2c2/flexcop-common.h +++ b/drivers/media/dvb/b2c2/flexcop-common.h @@ -75,6 +75,8 @@ struct flexcop_device { struct i2c_adapter i2c_adap; struct semaphore i2c_sem; + struct module *owner; + /* options and status */ int extra_feedcount; int feedcount; diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c index 78952096fb7..ed717c0073d 100644 --- a/drivers/media/dvb/b2c2/flexcop-pci.c +++ b/drivers/media/dvb/b2c2/flexcop-pci.c @@ -309,6 +309,7 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e fc->bus_type = FC_PCI; fc->dev = &pdev->dev; + fc->owner = THIS_MODULE; /* bus specific part */ fc_pci->pdev = pdev; diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c index 20db6329a68..0113449abd1 100644 --- a/drivers/media/dvb/b2c2/flexcop-usb.c +++ b/drivers/media/dvb/b2c2/flexcop-usb.c @@ -498,6 +498,7 @@ static int flexcop_usb_probe(struct usb_interface *intf, fc->bus_type = FC_USB; fc->dev = &udev->dev; + fc->owner = THIS_MODULE; /* bus specific part */ fc_usb->udev = udev; diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c index ad590875064..df55e4c8ecd 100644 --- a/drivers/media/dvb/b2c2/flexcop.c +++ b/drivers/media/dvb/b2c2/flexcop.c @@ -67,7 +67,7 @@ static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) static int flexcop_dvb_init(struct flexcop_device *fc) { int ret; - if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",THIS_MODULE)) < 0) { + if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",fc->owner)) < 0) { err("error registering DVB adapter"); return ret; } -- cgit v1.2.3 From c6ee197ccf4af454638c044706f0ba7ef6c1bb76 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:17 -0700 Subject: [PATCH] dvb: flexcop: readme update readme update Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/dvb/README.flexcop | 121 +++++++-------------------------------- 1 file changed, 21 insertions(+), 100 deletions(-) diff --git a/Documentation/dvb/README.flexcop b/Documentation/dvb/README.flexcop index 8036faa1ead..a50c70f9ca7 100644 --- a/Documentation/dvb/README.flexcop +++ b/Documentation/dvb/README.flexcop @@ -2,26 +2,20 @@ This README escorted the skystar2-driver rewriting procedure. It describes the state of the new flexcop-driver set and some internals are written down here too. -How to do something in here? -============================ - -make -f Makefile.t -make -C ../build-2.6 -./in.sh # load the drivers -./rm.sh # unload the drivers - -Please read this file, if you want to contribute. - This document hopefully describes things about the flexcop and its -device-offsprings. Goal is to write a easy-to-write and easy-to-read set of +device-offsprings. Goal was to write an easy-to-write and easy-to-read set of drivers based on the skystar2.c and other information. -This directory is temporary. It is used for rewriting the skystar2.c and to -create shared code, which then can be used by the usb box as well. - Remark: flexcop-pci.c was a copy of skystar2.c, but every line has been touched and rewritten. +History & News +============== + 2005-04-01 - correct USB ISOC transfers (thanks to Vadim Catana) + + + + General coding processing ========================= @@ -81,16 +75,15 @@ non-static where possible, moved code to proper places) 2) Search for errors in the leftover of flexcop-pci.c (partially done) 5a) add MAC address reading +5c) feeding of ISOC data to the software demux (format of the isochronous data +and speed optimization, no real error) (thanks to Vadim Catana) What to do in the near future? -------------------------------------- (no special order here) - 5) USB driver 5b) optimize isoc-transfer (submitting/killing isoc URBs when transfer is starting) -5c) feeding of ISOC data to the software demux (format of the isochronous data -and speed optimization, no real error) Testing changes --------------- @@ -118,7 +111,7 @@ item | mt352 | nxt2002 | stv0299 | mt312 | mt352 | nxt2002 | stv0299 | mt312 2) | O | N 5a) | N | O 5b)* | N | -5c)* | N | +5c) | N | O * - not done yet @@ -155,17 +148,21 @@ working) SOLUTION: also index 0 was affected, because net_translation is done for these indexes by default -5b) isochronous transfer does only work in the first attempt (for the Sky2PC USB, -Air2PC is working) -SOLUTION: the flexcop was going asleep and never really woke up again (don't -know if this need fixes, see flexcop-fe-tuner.c:flexcop_sleep) +5b) isochronous transfer does only work in the first attempt (for the Sky2PC +USB, Air2PC is working) SOLUTION: the flexcop was going asleep and never really +woke up again (don't know if this need fixes, see +flexcop-fe-tuner.c:flexcop_sleep) + +NEWS: when the driver is loaded and unloaded and loaded again (w/o doing +anything in the while the driver is loaded the first time), no transfers take +place anymore. Improvements when rewriting (refactoring) is done ================================================= - split sleeping of the flexcop (misc_204.ACPI3_sig = 1;) from lnb_control (enable sleeping for other demods than dvb-s) -- add support for CableStar (stv0297 Microtune 203x/ALPS) +- add support for CableStar (stv0297 Microtune 203x/ALPS) (almost done, incompatibilities with the Nexus-CA) Debugging --------- @@ -192,82 +189,6 @@ Sram destinations: accessing registers Tuner/Demod: I2C bus DVB-stuff: can be written for common use -Restrictions: -============ - -We need to create a bus-specific-struct and a flexcop-struct. - -bus-specific-struct: - -struct flexcop_pci -... - -struct flexcop_usb -... - - -struct flexcop_device { - void *bus_specific; /* container for bus-specific struct */ -... -} - -PCI i2c can read/write max 4 bytes at a time, USB can more - -Functions -========= - -Syntax ------- - -- Flexcop functions will be called "flexcop(_[a-z0-9]+)+" and exported as such - if needed. -- Flexcop-device functions will be called "flexcop_device(_[a-z0-9]+)+" and - exported as such if needed. -- Both will be compiled to b2c2-flexcop.ko and their source can be found in the - flexcop*.[hc] - -Callbacks and exports ---------------------- - -Bus-specific functions will be given as callbacks (function pointers) to the -flexcop-module. (within the flexcop_device-struct) - -Initialization process -====================== - -b2c2-flexcop.ko is loaded -b2c2-flexcop-.ko is loaded - -suppose a device is found: -malloc flexcop and the bus-specific variables (via flexcop_device_malloc) -fill the bus-specific variable -fill the flexcop variable (especially the bus-specific callbacks) -bus-specific initialization - - ... -do the common initialization (via flexcop_device_initialize) - - reset the card - - determine flexcop type (II, IIB, III) - - hw_filters (bus dependent) - - 0x204 - - set sram size - - create the dvb-stuff - - create i2c stuff - - frontend-initialization -done -bus specific: - - media_destination (this and the following 3 are bus specific) - - cai_dest - - cao_dest - - net_destination - -Bugs fixed while rewriting the driver -===================================== - -- EEPROM access (to read the MAC address) was fixed to death some time last - year. (fixed here and in skystar2.c) (Bjarne, this was the piece of code - (fix-chipaddr) we were wondering about) - - Acknowledgements (just for the rewriting part) ================ @@ -281,4 +202,4 @@ Boleslaw Ciesielski for pointing out a problem with firmware loader. Vadim Catana for correcting the USB transfer. -comments, critics and ideas to linux-dvb@linuxtv.org or patrick.boettcher@desy.de +comments, critics and ideas to linux-dvb@linuxtv.org. -- cgit v1.2.3 From bdc7800122da0b6b008aa9bdafc01e32b6a4576a Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:18 -0700 Subject: [PATCH] dvb: flexcop: i2c read fixes rewrote the i2c-reading-part (no more ack-error ignoring, which was inherited from the skystar2-driver) Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/b2c2/flexcop-i2c.c | 116 ++++++++++++++++++----------------- drivers/media/dvb/b2c2/flexcop-reg.h | 3 +- drivers/media/dvb/b2c2/flexcop.c | 4 -- 3 files changed, 63 insertions(+), 60 deletions(-) diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c index 736251f393c..be4266d4ae9 100644 --- a/drivers/media/dvb/b2c2/flexcop-i2c.c +++ b/drivers/media/dvb/b2c2/flexcop-i2c.c @@ -9,9 +9,9 @@ #define FC_MAX_I2C_RETRIES 100000 -static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r100, int max_ack_errors) +static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r100) { - int i,ack_errors = 0; + int i; flexcop_ibi_value r; r100->tw_sm_c_100.working_start = 1; @@ -31,11 +31,7 @@ static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r } } else { deb_i2c("suffering from an i2c ack_error\n"); - if (++ack_errors >= max_ack_errors) - break; - - fc->write_ibi_reg(fc, tw_sm_c_100, ibi_zero); - fc->write_ibi_reg(fc, tw_sm_c_100, *r100); + return -EREMOTEIO; } } deb_i2c("tried %d times i2c operation, never finished or too many ack errors.\n",i); @@ -48,19 +44,30 @@ static int flexcop_i2c_read4(struct flexcop_device *fc, flexcop_ibi_value r100, int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */ ret; - if ((ret = flexcop_i2c_operation(fc,&r100,30)) != 0) - return ret; - - r104 = fc->read_ibi_reg(fc,tw_sm_c_104); - - deb_i2c("read: r100: %08x, r104: %08x\n",r100.raw,r104.raw); + if ((ret = flexcop_i2c_operation(fc,&r100)) != 0) { + /* The Cablestar needs a different kind of i2c-transfer (does not + * support "Repeat Start"): + * wait for the ACK failure, + * and do a subsequent read with the Bit 30 enabled + */ + r100.tw_sm_c_100.no_base_addr_ack_error = 1; + if ((ret = flexcop_i2c_operation(fc,&r100)) != 0) { + deb_i2c("no_base_addr read failed. %d\n",ret); + return ret; + } + } - /* there is at least one byte, otherwise we wouldn't be here */ buf[0] = r100.tw_sm_c_100.data1_reg; - if (len > 0) buf[1] = r104.tw_sm_c_104.data2_reg; - if (len > 1) buf[2] = r104.tw_sm_c_104.data3_reg; - if (len > 2) buf[3] = r104.tw_sm_c_104.data4_reg; + if (len > 0) { + r104 = fc->read_ibi_reg(fc,tw_sm_c_104); + deb_i2c("read: r100: %08x, r104: %08x\n",r100.raw,r104.raw); + + /* there is at least one more byte, otherwise we wouldn't be here */ + buf[1] = r104.tw_sm_c_104.data2_reg; + if (len > 1) buf[2] = r104.tw_sm_c_104.data3_reg; + if (len > 2) buf[3] = r104.tw_sm_c_104.data4_reg; + } return 0; } @@ -82,9 +89,45 @@ static int flexcop_i2c_write4(struct flexcop_device *fc, flexcop_ibi_value r100, /* write the additional i2c data before doing the actual i2c operation */ fc->write_ibi_reg(fc,tw_sm_c_104,r104); + return flexcop_i2c_operation(fc,&r100); +} + +int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op, + flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len) +{ + int ret; + u16 bytes_to_transfer; + flexcop_ibi_value r100; + + deb_i2c("op = %d\n",op); + r100.raw = 0; + r100.tw_sm_c_100.chipaddr = chipaddr; + r100.tw_sm_c_100.twoWS_rw = op; + r100.tw_sm_c_100.twoWS_port_reg = port; + + while (len != 0) { + bytes_to_transfer = len > 4 ? 4 : len; - return flexcop_i2c_operation(fc,&r100,30); + r100.tw_sm_c_100.total_bytes = bytes_to_transfer - 1; + r100.tw_sm_c_100.baseaddr = addr; + + if (op == FC_READ) + ret = flexcop_i2c_read4(fc, r100, buf); + else + ret = flexcop_i2c_write4(fc,r100, buf); + + if (ret < 0) + return ret; + + buf += bytes_to_transfer; + addr += bytes_to_transfer; + len -= bytes_to_transfer; + }; + + return 0; } +/* exported for PCI i2c */ +EXPORT_SYMBOL(flexcop_i2c_request); /* master xfer callback for demodulator */ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) @@ -123,43 +166,6 @@ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs return ret; } -int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op, - flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len) -{ - int ret; - u16 bytes_to_transfer; - flexcop_ibi_value r100; - - deb_i2c("op = %d\n",op); - r100.raw = 0; - r100.tw_sm_c_100.chipaddr = chipaddr; - r100.tw_sm_c_100.twoWS_rw = op; - r100.tw_sm_c_100.twoWS_port_reg = port; - - while (len != 0) { - bytes_to_transfer = len > 4 ? 4 : len; - - r100.tw_sm_c_100.total_bytes = bytes_to_transfer - 1; - r100.tw_sm_c_100.baseaddr = addr; - - if (op == FC_READ) - ret = flexcop_i2c_read4(fc, r100, buf); - else - ret = flexcop_i2c_write4(fc,r100, buf); - - if (ret < 0) - return ret; - - buf += bytes_to_transfer; - addr += bytes_to_transfer; - len -= bytes_to_transfer; - }; - - return 0; -} -/* exported for PCI i2c */ -EXPORT_SYMBOL(flexcop_i2c_request); - static u32 flexcop_i2c_func(struct i2c_adapter *adapter) { return I2C_FUNC_I2C; diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h index 41835c5280a..5e131be55cb 100644 --- a/drivers/media/dvb/b2c2/flexcop-reg.h +++ b/drivers/media/dvb/b2c2/flexcop-reg.h @@ -692,9 +692,10 @@ typedef enum { wan_ctrl_reg_71c = 0x71c, } flexcop_ibi_register; -#define flexcop_set_ibi_value(reg,attr,val) \ +#define flexcop_set_ibi_value(reg,attr,val) { \ flexcop_ibi_value v = fc->read_ibi_reg(fc,reg); \ v.reg.attr = val; \ fc->write_ibi_reg(fc,reg,v); \ +} #endif diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c index df55e4c8ecd..8b5d14dd36e 100644 --- a/drivers/media/dvb/b2c2/flexcop.c +++ b/drivers/media/dvb/b2c2/flexcop.c @@ -184,10 +184,6 @@ static void flexcop_reset(struct flexcop_device *fc) fc->write_ibi_reg(fc,misc_204,v204); v204.misc_204.Per_reset_sig = 1; fc->write_ibi_reg(fc,misc_204,v204); - -/* v208.raw = 0; - v208.ctrl_208.Null_filter_sig = 1; - fc->write_ibi_reg(fc,ctrl_208,v208);*/ } struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len) -- cgit v1.2.3 From 958706c12d7e1b21ac46a8b3bc7eabb157b20bb7 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:19 -0700 Subject: [PATCH] dvb: flexcop: DiSeqC fix Fixed DiSeqC switching, which was wrongly taking over from skystar2.c. Thanks to Joerg Riechardt for finding the bug and testing the Fix. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/b2c2/flexcop-fe-tuner.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index b3dd16fb5bb..71be400e9ae 100644 --- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -79,8 +79,8 @@ static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */ - v.lnb_switch_freq_200.LNB_CTLHighCount_sig = - v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax; + v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax; + v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax == 0 ? 0x1ff : ax; return fc->write_ibi_reg(fc,lnb_switch_freq_200,v); } -- cgit v1.2.3 From 3dfaebdaa2a14c7ca1fbbafff08992489087e7f1 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:19 -0700 Subject: [PATCH] dvb: support for TT/Hauppauge Nexus-S Rev 2.3 Support for TT/Hauppauge Nexus-S Rev 2.3 (Oliver Endriss) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110.c | 116 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 922c205a265..e3f7bd68591 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -1673,6 +1673,106 @@ static struct stv0299_config alps_bsru6_config = { }; +static u8 alps_bsbe1_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ + 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ + 0x06, 0x40, /* DAC not used, set to high impendance mode */ + 0x07, 0x00, /* DAC LSB */ + 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ + 0x09, 0x00, /* FIFO */ + 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ + 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ + 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ + 0x10, 0x3f, // AGC2 0x3d + 0x11, 0x84, + 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on + 0x15, 0xc9, // lock detector threshold + 0x16, 0x00, + 0x17, 0x00, + 0x18, 0x00, + 0x19, 0x00, + 0x1a, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 + 0x29, 0x1e, // 1/2 threshold + 0x2a, 0x14, // 2/3 threshold + 0x2b, 0x0f, // 3/4 threshold + 0x2c, 0x09, // 5/6 threshold + 0x2d, 0x05, // 7/8 threshold + 0x2e, 0x01, + 0x31, 0x1f, // test all FECs + 0x32, 0x19, // viterbi and synchro search + 0x33, 0xfc, // rs control + 0x34, 0x93, // error control + 0x0f, 0x92, + 0xff, 0xff +}; + +static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; + int ret; + u8 data[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + if ((params->frequency < 950000) || (params->frequency > 2150000)) + return -EINVAL; + + div = (params->frequency + (125 - 1)) / 125; // round correctly + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x80 | ((div & 0x18000) >> 10) | 4; + data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4; + + ret = i2c_transfer(&av7110->i2c_adap, &msg, 1); + return (ret != 1) ? -EIO : 0; +} + +static struct stv0299_config alps_bsbe1_config = { + .demod_address = 0x68, + .inittab = alps_bsbe1_inittab, + .mclk = 88000000UL, + .invert = 1, + .enhanced_tuning = 0, + .skip_reinit = 0, + .min_delay_ms = 100, + .set_symbol_rate = alps_bsru6_set_symbol_rate, + .pll_set = alps_bsbe1_pll_set, +}; + +static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; + int ret; + u8 data[1]; + struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = data, .len = sizeof(data) }; + + switch(voltage) { + case SEC_VOLTAGE_OFF: + data[0] = 0x00; + break; + case SEC_VOLTAGE_13: + data[0] = 0x44; + break; + case SEC_VOLTAGE_18: + data[0] = 0x4c; + break; + default: + return -EINVAL; + }; + + ret = i2c_transfer(&av7110->i2c_adap, &msg, 1); + return (ret != 1) ? -EIO : 0; +} + static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { @@ -2116,6 +2216,14 @@ static int frontend_init(struct av7110 *av7110) av7110->dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; break; } + break; + + case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */ + /* ALPS BSBE1 */ + av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap); + if (av7110->fe) + av7110->fe->ops->set_voltage = lnbp21_set_voltage; + break; } } @@ -2672,21 +2780,23 @@ MAKE_AV7110_INFO(ttt_1_X, "Technotrend/Hauppauge WinTV DVB-T rev1.X"); MAKE_AV7110_INFO(ttc_1_X, "Technotrend/Hauppauge WinTV Nexus-CA rev1.X"); MAKE_AV7110_INFO(ttc_2_X, "Technotrend/Hauppauge WinTV DVB-C rev2.X"); MAKE_AV7110_INFO(tts_2_X, "Technotrend/Hauppauge WinTV Nexus-S rev2.X"); +MAKE_AV7110_INFO(tts_2_3, "Technotrend/Hauppauge WinTV Nexus-S rev2.3"); MAKE_AV7110_INFO(tts_1_3se, "Technotrend/Hauppauge WinTV DVB-S rev1.3 SE"); MAKE_AV7110_INFO(ttt, "Technotrend/Hauppauge DVB-T"); MAKE_AV7110_INFO(fsc, "Fujitsu Siemens DVB-C"); MAKE_AV7110_INFO(fss, "Fujitsu Siemens DVB-S rev1.6"); static struct pci_device_id pci_tbl[] = { + MAKE_EXTENSION_PCI(fsc, 0x110a, 0x0000), MAKE_EXTENSION_PCI(tts_1_X, 0x13c2, 0x0000), MAKE_EXTENSION_PCI(ttt_1_X, 0x13c2, 0x0001), MAKE_EXTENSION_PCI(ttc_2_X, 0x13c2, 0x0002), MAKE_EXTENSION_PCI(tts_2_X, 0x13c2, 0x0003), - MAKE_EXTENSION_PCI(tts_1_3se, 0x13c2, 0x1002), - MAKE_EXTENSION_PCI(fsc, 0x110a, 0x0000), - MAKE_EXTENSION_PCI(ttc_1_X, 0x13c2, 0x000a), MAKE_EXTENSION_PCI(fss, 0x13c2, 0x0006), MAKE_EXTENSION_PCI(ttt, 0x13c2, 0x0008), + MAKE_EXTENSION_PCI(ttc_1_X, 0x13c2, 0x000a), + MAKE_EXTENSION_PCI(tts_2_3, 0x13c2, 0x000e), + MAKE_EXTENSION_PCI(tts_1_3se, 0x13c2, 0x1002), /* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0004), UNDEFINED CARD */ // Galaxis DVB PC-Sat-Carte /* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */ // Technisat SkyStar1 -- cgit v1.2.3 From c2c62d81430e907b6599d4be43a7ee6f74d2bd69 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:20 -0700 Subject: [PATCH] dvb: saa7146: no need to initialize static/global variables to 0 no need to initialize static/global variables to 0 Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/common/saa7146_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index 9f6c19ac128..50e8b865401 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -23,9 +23,9 @@ LIST_HEAD(saa7146_devices); DECLARE_MUTEX(saa7146_devices_lock); -static int saa7146_num = 0; +static int saa7146_num; -unsigned int saa7146_debug = 0; +unsigned int saa7146_debug; module_param(saa7146_debug, int, 0644); MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)"); -- cgit v1.2.3 From f4f009a776c1db9b27346846b0db052e04a6d5ad Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:21 -0700 Subject: [PATCH] dvb: dvb_frontend: fix module param Remove incorrect "dvb_"-prefix from parameter description. Error detected with section2text.rb, see autoparam patch. Signed-off-by: Magnus Damm Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-core/dvb_frontend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 59a9adfae1e..3f94afb02c6 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -48,7 +48,7 @@ static int dvb_override_tune_delay; static int dvb_powerdown_on_sleep = 1; module_param_named(frontend_debug, dvb_frontend_debug, int, 0644); -MODULE_PARM_DESC(dvb_frontend_debug, "Turn on/off frontend core debugging (default:off)."); +MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off)."); module_param(dvb_shutdown_timeout, int, 0444); MODULE_PARM_DESC(dvb_shutdown_timeout, "wait seconds after close() before suspending hardware"); module_param(dvb_force_auto_inversion, int, 0444); -- cgit v1.2.3 From 6074b36715f036f56beb688f49a2a2fb5b28ad72 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:22 -0700 Subject: [PATCH] dvb: av7110: audio out fix Switch analog output of the Crystal sound chip to left/stereo/right mode. This will fix problems with some (most?) channels which do not encode 2-channel audio correctly. (Oliver Endriss) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110_av.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index d77e8a00688..2c3b0b32b8d 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -1230,14 +1230,20 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, switch(av7110->audiostate.channel_select) { case AUDIO_STEREO: audcom(av7110, AUDIO_CMD_STEREO); + if (av7110->adac_type == DVB_ADAC_CRYSTAL) + i2c_writereg(av7110, 0x20, 0x02, 0x49); break; case AUDIO_MONO_LEFT: audcom(av7110, AUDIO_CMD_MONO_L); + if (av7110->adac_type == DVB_ADAC_CRYSTAL) + i2c_writereg(av7110, 0x20, 0x02, 0x4a); break; case AUDIO_MONO_RIGHT: audcom(av7110, AUDIO_CMD_MONO_R); + if (av7110->adac_type == DVB_ADAC_CRYSTAL) + i2c_writereg(av7110, 0x20, 0x02, 0x45); break; default: -- cgit v1.2.3 From 2d4f2c2e15795b93fa4da7a7cfac5e82df51b1f1 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:23 -0700 Subject: [PATCH] dvb: add support for KNC-1 cards Support KNC-1 Plus DVB-T and similar KNC-1 cards (Alexander Riedel) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/budget-av.c | 14 ++++++++++++++ drivers/media/dvb/ttpci/budget.h | 3 +++ 2 files changed, 17 insertions(+) diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 14e963206b8..9860caf3249 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -701,7 +701,10 @@ static u8 read_pwm(struct budget_av *budget_av) static void frontend_init(struct budget_av *budget_av) { switch (budget_av->budget.dev->pci->subsystem_device) { + case 0x0011: // KNC1 DVB-S Plus budget with AV IN (stv0299/Philips SU1278(tsa5059)) + saa7146_write(budget_av->budget.dev, GPIO_CTRL, 0x50000000); // Enable / PowerON Frontend case 0x4f56: // Typhoon/KNC1 DVB-S budget (stv0299/Philips SU1278(tsa5059)) + case 0x0010: // KNC1 DVB-S budget (stv0299/Philips SU1278(tsa5059)) budget_av->budget.dvb_frontend = stv0299_attach(&typhoon_config, &budget_av->budget.i2c_adap); if (budget_av->budget.dvb_frontend != NULL) { @@ -709,6 +712,8 @@ static void frontend_init(struct budget_av *budget_av) } break; + case 0x0021: // KNC1 DVB-C Plus budget with AV IN (tda10021/Philips CU1216(tua6034)) + saa7146_write(budget_av->budget.dev, GPIO_CTRL, 0x50000000); // Enable / PowerON Frontend case 0x0020: // KNC1 DVB-C budget (tda10021/Philips CU1216(tua6034)) budget_av->budget.dvb_frontend = tda10021_attach(&philips_cu1216_config, @@ -718,6 +723,8 @@ static void frontend_init(struct budget_av *budget_av) } break; + case 0x0031: // KNC1 DVB-T Plus budget with AV IN (tda10046/Philips TU1216(tda6651tt)) + saa7146_write(budget_av->budget.dev, GPIO_CTRL, 0x50000000); // Enable / PowerON Frontend case 0x0030: // KNC1 DVB-T budget (tda10046/Philips TU1216(tda6651tt)) budget_av->budget.dvb_frontend = tda10046_attach(&philips_tu1216_config, &budget_av->budget.i2c_adap); @@ -963,14 +970,21 @@ static struct saa7146_extension budget_extension; MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S); MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C); MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T); +MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP); +MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP); +MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP); MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C); MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T); static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56), + MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010), + MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011), MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020), + MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021), MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030), + MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031), MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154), MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156), MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157), diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h index 10bd41f0363..6d82a6f4e43 100644 --- a/drivers/media/dvb/ttpci/budget.h +++ b/drivers/media/dvb/ttpci/budget.h @@ -92,6 +92,9 @@ static struct saa7146_pci_extension_data x_var = { \ #define BUDGET_KNC1S 8 #define BUDGET_KNC1C 9 #define BUDGET_KNC1T 10 +#define BUDGET_KNC1SP 11 +#define BUDGET_KNC1CP 12 +#define BUDGET_KNC1TP 13 #define BUDGET_VIDEO_PORTA 0 #define BUDGET_VIDEO_PORTB 1 -- cgit v1.2.3 From 0c53c70f6afa2d3f4d416d8c0e9a219c2f6b7cb6 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:24 -0700 Subject: [PATCH] dvb: remove unnecessary casts in dvb-core remove unnecessary casts in dvb-core (Kenneth Aafloy) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-core/dmxdev.c | 32 +++++++++++------------ drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 38 +++++++++++++-------------- drivers/media/dvb/dvb-core/dvb_frontend.c | 34 ++++++++++++------------ drivers/media/dvb/dvb-core/dvb_net.c | 40 ++++++++++++++--------------- 4 files changed, 72 insertions(+), 72 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 1863f1dfb00..c225de7ffd8 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -175,8 +175,8 @@ static inline void dvb_dmxdev_dvr_state_set(struct dmxdev_dvr *dmxdevdvr, int st static int dvb_dvr_open(struct inode *inode, struct file *file) { - struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; - struct dmxdev *dmxdev=(struct dmxdev *) dvbdev->priv; + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; struct dmx_frontend *front; dprintk ("function : %s\n", __FUNCTION__); @@ -224,8 +224,8 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) static int dvb_dvr_release(struct inode *inode, struct file *file) { - struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; - struct dmxdev *dmxdev=(struct dmxdev *) dvbdev->priv; + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; if (down_interruptible (&dmxdev->mutex)) return -ERESTARTSYS; @@ -252,8 +252,8 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) static ssize_t dvb_dvr_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; - struct dmxdev *dmxdev=(struct dmxdev *) dvbdev->priv; + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; int ret; if (!dmxdev->demux->write) @@ -270,8 +270,8 @@ static ssize_t dvb_dvr_write(struct file *file, const char __user *buf, static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; - struct dmxdev *dmxdev=(struct dmxdev *) dvbdev->priv; + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; int ret; //down(&dmxdev->mutex); @@ -345,7 +345,7 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, const u8 *buffer2, size_t buffer2_len, struct dmx_section_filter *filter, enum dmx_success success) { - struct dmxdev_filter *dmxdevfilter=(struct dmxdev_filter *) filter->priv; + struct dmxdev_filter *dmxdevfilter = filter->priv; int ret; if (dmxdevfilter->buffer.error) { @@ -381,7 +381,7 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, const u8 *buffer2, size_t buffer2_len, struct dmx_ts_feed *feed, enum dmx_success success) { - struct dmxdev_filter *dmxdevfilter=(struct dmxdev_filter *) feed->priv; + struct dmxdev_filter *dmxdevfilter = feed->priv; struct dmxdev_buffer *buffer; int ret; @@ -684,8 +684,8 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) static int dvb_demux_open(struct inode *inode, struct file *file) { - struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; - struct dmxdev *dmxdev=(struct dmxdev *) dvbdev->priv; + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; int i; struct dmxdev_filter *dmxdevfilter; @@ -1013,8 +1013,8 @@ static struct dvb_device dvbdev_demux = { static int dvb_dvr_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { - struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; - struct dmxdev *dmxdev=(struct dmxdev *) dvbdev->priv; + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; int ret=0; @@ -1044,8 +1044,8 @@ static int dvb_dvr_ioctl(struct inode *inode, struct file *file, static unsigned int dvb_dvr_poll (struct file *file, poll_table *wait) { - struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; - struct dmxdev *dmxdev = (struct dmxdev *) dvbdev->priv; + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; unsigned int mask = 0; dprintk ("function : %s\n", __FUNCTION__); diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index c1ea89f2880..0eb9aa711fb 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -829,7 +829,7 @@ EXPORT_SYMBOL(dvb_ca_en50221_camready_irq); */ void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221 *pubca, int slot, int change_type) { - struct dvb_ca_private *ca = (struct dvb_ca_private *) pubca->private; + struct dvb_ca_private *ca = pubca->private; dprintk("CAMCHANGE IRQ slot:%i change_type:%i\n", slot, change_type); @@ -857,7 +857,7 @@ EXPORT_SYMBOL(dvb_ca_en50221_frda_irq); */ void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot) { - struct dvb_ca_private *ca = (struct dvb_ca_private *) pubca->private; + struct dvb_ca_private *ca = pubca->private; dprintk("CAMREADY IRQ slot:%i\n", slot); @@ -876,7 +876,7 @@ void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot) */ void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot) { - struct dvb_ca_private *ca = (struct dvb_ca_private *) pubca->private; + struct dvb_ca_private *ca = pubca->private; int flags; dprintk("FR/DA IRQ slot:%i\n", slot); @@ -993,7 +993,7 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca) */ static int dvb_ca_en50221_thread(void *data) { - struct dvb_ca_private *ca = (struct dvb_ca_private *) data; + struct dvb_ca_private *ca = data; char name[15]; int slot; int flags; @@ -1202,8 +1202,8 @@ static int dvb_ca_en50221_thread(void *data) static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { - struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; - struct dvb_ca_private *ca = (struct dvb_ca_private *) dvbdev->priv; + struct dvb_device *dvbdev = file->private_data; + struct dvb_ca_private *ca = dvbdev->priv; int err = 0; int slot; @@ -1225,7 +1225,7 @@ static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, break; case CA_GET_CAP: { - struct ca_caps *caps = (struct ca_caps *) parg; + struct ca_caps *caps = parg; caps->slot_num = ca->slot_count; caps->slot_type = CA_CI_LINK; @@ -1235,7 +1235,7 @@ static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, } case CA_GET_SLOT_INFO: { - struct ca_slot_info *info = (struct ca_slot_info *) parg; + struct ca_slot_info *info = parg; if ((info->num > ca->slot_count) || (info->num < 0)) return -EINVAL; @@ -1291,8 +1291,8 @@ static int dvb_ca_en50221_io_ioctl(struct inode *inode, struct file *file, static ssize_t dvb_ca_en50221_io_write(struct file *file, const char __user * buf, size_t count, loff_t * ppos) { - struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; - struct dvb_ca_private *ca = (struct dvb_ca_private *) dvbdev->priv; + struct dvb_device *dvbdev = file->private_data; + struct dvb_ca_private *ca = dvbdev->priv; u8 slot, connection_id; int status; char fragbuf[HOST_LINK_BUF_SIZE]; @@ -1428,8 +1428,8 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, int *resu static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf, size_t count, loff_t * ppos) { - struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; - struct dvb_ca_private *ca = (struct dvb_ca_private *) dvbdev->priv; + struct dvb_device *dvbdev = file->private_data; + struct dvb_ca_private *ca = dvbdev->priv; int status; int result = 0; u8 hdr[2]; @@ -1526,8 +1526,8 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf, */ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) { - struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; - struct dvb_ca_private *ca = (struct dvb_ca_private *) dvbdev->priv; + struct dvb_device *dvbdev = file->private_data; + struct dvb_ca_private *ca = dvbdev->priv; int err; int i; @@ -1569,8 +1569,8 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) */ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) { - struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; - struct dvb_ca_private *ca = (struct dvb_ca_private *) dvbdev->priv; + struct dvb_device *dvbdev = file->private_data; + struct dvb_ca_private *ca = dvbdev->priv; int err = 0; dprintk("%s\n", __FUNCTION__); @@ -1597,8 +1597,8 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) */ static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table * wait) { - struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; - struct dvb_ca_private *ca = (struct dvb_ca_private *) dvbdev->priv; + struct dvb_device *dvbdev = file->private_data; + struct dvb_ca_private *ca = dvbdev->priv; unsigned int mask = 0; int slot; int result = 0; @@ -1750,7 +1750,7 @@ EXPORT_SYMBOL(dvb_ca_en50221_release); */ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) { - struct dvb_ca_private *ca = (struct dvb_ca_private *) pubca->private; + struct dvb_ca_private *ca = pubca->private; int i; dprintk("%s\n", __FUNCTION__); diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 3f94afb02c6..d19301d90a0 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -117,7 +117,7 @@ struct dvb_frontend_private { static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) { - struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dvb_fe_events *events = &fepriv->events; struct dvb_frontend_event *e; int wp; @@ -155,7 +155,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) static int dvb_frontend_get_event(struct dvb_frontend *fe, struct dvb_frontend_event *event, int flags) { - struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dvb_fe_events *events = &fepriv->events; dprintk ("%s\n", __FUNCTION__); @@ -234,7 +234,7 @@ static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped) { int autoinversion; int ready = 0; - struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; int original_inversion = fepriv->parameters.inversion; u32 original_frequency = fepriv->parameters.frequency; @@ -321,7 +321,7 @@ static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped) static int dvb_frontend_is_exiting(struct dvb_frontend *fe) { - struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; if (fepriv->exit) return 1; @@ -335,7 +335,7 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe) static int dvb_frontend_should_wakeup(struct dvb_frontend *fe) { - struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; if (fepriv->wakeup) { fepriv->wakeup = 0; @@ -346,7 +346,7 @@ static int dvb_frontend_should_wakeup(struct dvb_frontend *fe) static void dvb_frontend_wakeup(struct dvb_frontend *fe) { - struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; fepriv->wakeup = 1; wake_up_interruptible(&fepriv->wait_queue); @@ -357,8 +357,8 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe) */ static int dvb_frontend_thread(void *data) { - struct dvb_frontend *fe = (struct dvb_frontend *) data; - struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + struct dvb_frontend *fe = data; + struct dvb_frontend_private *fepriv = fe->frontend_priv; unsigned long timeout; char name [15]; int quality = 0, delay = 3*HZ; @@ -520,7 +520,7 @@ static int dvb_frontend_thread(void *data) static void dvb_frontend_stop(struct dvb_frontend *fe) { unsigned long ret; - struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; dprintk ("%s\n", __FUNCTION__); @@ -559,7 +559,7 @@ static void dvb_frontend_stop(struct dvb_frontend *fe) static int dvb_frontend_start(struct dvb_frontend *fe) { int ret; - struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; dprintk ("%s\n", __FUNCTION__); @@ -597,7 +597,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; - struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; int err = -EOPNOTSUPP; dprintk ("%s\n", __FUNCTION__); @@ -615,7 +615,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, switch (cmd) { case FE_GET_INFO: { - struct dvb_frontend_info* info = (struct dvb_frontend_info*) parg; + struct dvb_frontend_info* info = parg; memcpy(info, &fe->ops->info, sizeof(struct dvb_frontend_info)); /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't @@ -793,7 +793,7 @@ static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struc { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; - struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; dprintk ("%s\n", __FUNCTION__); @@ -809,7 +809,7 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; - struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; int ret; dprintk ("%s\n", __FUNCTION__); @@ -833,7 +833,7 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; - struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; dprintk ("%s\n", __FUNCTION__); @@ -873,7 +873,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb, up(&frontend_mutex); return -ENOMEM; } - fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + fepriv = fe->frontend_priv; memset(fe->frontend_priv, 0, sizeof(struct dvb_frontend_private)); init_MUTEX (&fepriv->sem); @@ -897,7 +897,7 @@ EXPORT_SYMBOL(dvb_register_frontend); int dvb_unregister_frontend(struct dvb_frontend* fe) { - struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; dprintk ("%s\n", __FUNCTION__); down (&frontend_mutex); diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 44892e7abd3..997199cc580 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -315,7 +315,7 @@ static inline void reset_ule( struct dvb_net_priv *p ) */ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) { - struct dvb_net_priv *priv = (struct dvb_net_priv *)dev->priv; + struct dvb_net_priv *priv = dev->priv; unsigned long skipped = 0L; u8 *ts, *ts_end, *from_where = NULL, ts_remain = 0, how_much = 0, new_ts = 1; struct ethhdr *ethh = NULL; @@ -709,7 +709,7 @@ static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len, const u8 *buffer2, size_t buffer2_len, struct dmx_ts_feed *feed, enum dmx_success success) { - struct net_device *dev = (struct net_device *)feed->priv; + struct net_device *dev = feed->priv; if (buffer2 != 0) printk(KERN_WARNING "buffer2 not 0: %p.\n", buffer2); @@ -801,7 +801,7 @@ static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len, struct dmx_section_filter *filter, enum dmx_success success) { - struct net_device *dev=(struct net_device *) filter->priv; + struct net_device *dev = filter->priv; /** * we rely on the DVB API definition where exactly one complete @@ -826,7 +826,7 @@ static int dvb_net_filter_sec_set(struct net_device *dev, struct dmx_section_filter **secfilter, u8 *mac, u8 *mac_mask) { - struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv; + struct dvb_net_priv *priv = dev->priv; int ret; *secfilter=NULL; @@ -870,7 +870,7 @@ static int dvb_net_filter_sec_set(struct net_device *dev, static int dvb_net_feed_start(struct net_device *dev) { int ret, i; - struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv; + struct dvb_net_priv *priv = dev->priv; struct dmx_demux *demux = priv->demux; unsigned char *mac = (unsigned char *) dev->dev_addr; @@ -965,7 +965,7 @@ static int dvb_net_feed_start(struct net_device *dev) static int dvb_net_feed_stop(struct net_device *dev) { - struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv; + struct dvb_net_priv *priv = dev->priv; int i; dprintk("%s\n", __FUNCTION__); @@ -1016,7 +1016,7 @@ static int dvb_net_feed_stop(struct net_device *dev) static int dvb_set_mc_filter (struct net_device *dev, struct dev_mc_list *mc) { - struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv; + struct dvb_net_priv *priv = dev->priv; if (priv->multi_num == DVB_NET_MULTICAST_MAX) return -ENOMEM; @@ -1031,7 +1031,7 @@ static int dvb_set_mc_filter (struct net_device *dev, struct dev_mc_list *mc) static void wq_set_multicast_list (void *data) { struct net_device *dev = data; - struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv; + struct dvb_net_priv *priv = dev->priv; dvb_net_feed_stop(dev); @@ -1066,7 +1066,7 @@ static void wq_set_multicast_list (void *data) static void dvb_net_set_multicast_list (struct net_device *dev) { - struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv; + struct dvb_net_priv *priv = dev->priv; schedule_work(&priv->set_multicast_list_wq); } @@ -1084,7 +1084,7 @@ static void wq_restart_net_feed (void *data) static int dvb_net_set_mac (struct net_device *dev, void *p) { - struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv; + struct dvb_net_priv *priv = dev->priv; struct sockaddr *addr=p; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); @@ -1098,7 +1098,7 @@ static int dvb_net_set_mac (struct net_device *dev, void *p) static int dvb_net_open(struct net_device *dev) { - struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv; + struct dvb_net_priv *priv = dev->priv; priv->in_use++; dvb_net_feed_start(dev); @@ -1108,7 +1108,7 @@ static int dvb_net_open(struct net_device *dev) static int dvb_net_stop(struct net_device *dev) { - struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv; + struct dvb_net_priv *priv = dev->priv; priv->in_use--; return dvb_net_feed_stop(dev); @@ -1228,8 +1228,8 @@ static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned int num) static int dvb_net_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { - struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; - struct dvb_net *dvbnet = (struct dvb_net *) dvbdev->priv; + struct dvb_device *dvbdev = file->private_data; + struct dvb_net *dvbnet = dvbdev->priv; if (((file->f_flags&O_ACCMODE)==O_RDONLY)) return -EPERM; @@ -1237,7 +1237,7 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file, switch (cmd) { case NET_ADD_IF: { - struct dvb_net_if *dvbnetif=(struct dvb_net_if *)parg; + struct dvb_net_if *dvbnetif = parg; int result; if (!capable(CAP_SYS_ADMIN)) @@ -1258,7 +1258,7 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file, { struct net_device *netdev; struct dvb_net_priv *priv_data; - struct dvb_net_if *dvbnetif=(struct dvb_net_if *)parg; + struct dvb_net_if *dvbnetif = parg; if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX || !dvbnet->state[dvbnetif->if_num]) @@ -1266,7 +1266,7 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file, netdev = dvbnet->device[dvbnetif->if_num]; - priv_data=(struct dvb_net_priv*)netdev->priv; + priv_data = netdev->priv; dvbnetif->pid=priv_data->pid; dvbnetif->feedtype=priv_data->feedtype; break; @@ -1288,7 +1288,7 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file, /* binary compatiblity cruft */ case __NET_ADD_IF_OLD: { - struct __dvb_net_if_old *dvbnetif=(struct __dvb_net_if_old *)parg; + struct __dvb_net_if_old *dvbnetif = parg; int result; if (!capable(CAP_SYS_ADMIN)) @@ -1309,7 +1309,7 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file, { struct net_device *netdev; struct dvb_net_priv *priv_data; - struct __dvb_net_if_old *dvbnetif=(struct __dvb_net_if_old *)parg; + struct __dvb_net_if_old *dvbnetif = parg; if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX || !dvbnet->state[dvbnetif->if_num]) @@ -1317,7 +1317,7 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file, netdev = dvbnet->device[dvbnetif->if_num]; - priv_data=(struct dvb_net_priv*)netdev->priv; + priv_data = netdev->priv; dvbnetif->pid=priv_data->pid; break; } -- cgit v1.2.3 From 59142330aaea9d870d795065d8b91e21d5e55254 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:25 -0700 Subject: [PATCH] dvb: dvb_net: handle IPv6 and LLC/SNAP handle IPv6 and LLC/SNAP (Bertrand Mazieres, Matthieu Castet, Johannes Stezenbach) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-core/dvb_net.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 997199cc580..6a968c346a3 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -727,6 +727,7 @@ static void dvb_net_sec(struct net_device *dev, u8 *pkt, int pkt_len) u8 *eth; struct sk_buff *skb; struct net_device_stats *stats = &(((struct dvb_net_priv *) dev->priv)->stats); + int snap = 0; /* note: pkt_len includes a 32bit checksum */ if (pkt_len < 16) { @@ -750,9 +751,12 @@ static void dvb_net_sec(struct net_device *dev, u8 *pkt, int pkt_len) return; } if (pkt[5] & 0x02) { - //FIXME: handle LLC/SNAP - stats->rx_dropped++; - return; + /* handle LLC/SNAP, see rfc-1042 */ + if (pkt_len < 24 || memcmp(&pkt[12], "\xaa\xaa\x03\0\0\0", 6)) { + stats->rx_dropped++; + return; + } + snap = 8; } if (pkt[7]) { /* FIXME: assemble datagram from multiple sections */ @@ -762,9 +766,9 @@ static void dvb_net_sec(struct net_device *dev, u8 *pkt, int pkt_len) } /* we have 14 byte ethernet header (ip header follows); - * 12 byte MPE header; 4 byte checksum; + 2 byte alignment + * 12 byte MPE header; 4 byte checksum; + 2 byte alignment, 8 byte LLC/SNAP */ - if (!(skb = dev_alloc_skb(pkt_len - 4 - 12 + 14 + 2))) { + if (!(skb = dev_alloc_skb(pkt_len - 4 - 12 + 14 + 2 - snap))) { //printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); stats->rx_dropped++; return; @@ -773,8 +777,8 @@ static void dvb_net_sec(struct net_device *dev, u8 *pkt, int pkt_len) skb->dev = dev; /* copy L3 payload */ - eth = (u8 *) skb_put(skb, pkt_len - 12 - 4 + 14); - memcpy(eth + 14, pkt + 12, pkt_len - 12 - 4); + eth = (u8 *) skb_put(skb, pkt_len - 12 - 4 + 14 - snap); + memcpy(eth + 14, pkt + 12 + snap, pkt_len - 12 - 4 - snap); /* create ethernet header: */ eth[0]=pkt[0x0b]; @@ -786,8 +790,21 @@ static void dvb_net_sec(struct net_device *dev, u8 *pkt, int pkt_len) eth[6]=eth[7]=eth[8]=eth[9]=eth[10]=eth[11]=0; - eth[12] = 0x08; /* ETH_P_IP */ - eth[13] = 0x00; + if (snap) { + eth[12] = pkt[18]; + eth[13] = pkt[19]; + } else { + /* protocol numbers are from rfc-1700 or + * http://www.iana.org/assignments/ethernet-numbers + */ + if (pkt[12] >> 4 == 6) { /* version field from IP header */ + eth[12] = 0x86; /* IPv6 */ + eth[13] = 0xdd; + } else { + eth[12] = 0x08; /* IPv4 */ + eth[13] = 0x00; + } + } skb->protocol = dvb_net_eth_type_trans(skb, dev); -- cgit v1.2.3 From a65d3bb7177cbab1fca69dd97537766c2817b6b2 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:26 -0700 Subject: [PATCH] dvb: av7110: fix VIDEO_SET_DISPLAY_FORMAT VIDEO_SET_DISPLAY_FORMAT ioctl fixed: set videostate.display_format, not videostate.video_format (Oliver Endriss) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110_av.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index 2c3b0b32b8d..f90e1cf2419 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -1075,7 +1075,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, } if (ret < 0) break; - av7110->videostate.video_format = format; + av7110->videostate.display_format = format; ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType, 1, (u16) val); break; -- cgit v1.2.3 From 4ab3f08b28676d365f3fb8600ead325fd235711a Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:27 -0700 Subject: [PATCH] dvb: av7110: fix NTSC/PAL switching fix NTSC -> PAL switching (std->id is a bitmap!) (Oliver Endriss) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110_v4l.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index eb84fb08d95..13aa7a42758 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -726,11 +726,11 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std) { struct av7110 *av7110 = (struct av7110*) dev->ext_priv; - if (std->id == V4L2_STD_PAL) { + if (std->id & V4L2_STD_PAL) { av7110->vidmode = VIDEO_MODE_PAL; av7110_set_vidmode(av7110, av7110->vidmode); } - else if (std->id == V4L2_STD_NTSC) { + else if (std->id & V4L2_STD_NTSC) { av7110->vidmode = VIDEO_MODE_NTSC; av7110_set_vidmode(av7110, av7110->vidmode); } -- cgit v1.2.3 From 3dbce49ea1c6885d07eb59d12889c059a868e6f5 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:28 -0700 Subject: [PATCH] dvb: av7110: fix comment fixed debugging instructions: av7110_debug -> debug (Oliver Endirss) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110_ir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c index 6d2256f1e35..665cdb8a3f7 100644 --- a/drivers/media/dvb/ttpci/av7110_ir.c +++ b/drivers/media/dvb/ttpci/av7110_ir.c @@ -10,7 +10,7 @@ #define UP_TIMEOUT (HZ/4) -/* enable ir debugging by or'ing av7110_debug with 16 */ +/* enable ir debugging by or'ing debug with 16 */ static int ir_initialized; static struct input_dev input_dev; -- cgit v1.2.3 From 3165dcb300ff60e794909f02b1fd3a41908682ea Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:28 -0700 Subject: [PATCH] dvb: av7110: fix indentation fix indentation Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110_ca.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c index 21f7aacf772..75173a22f5c 100644 --- a/drivers/media/dvb/ttpci/av7110_ca.c +++ b/drivers/media/dvb/ttpci/av7110_ca.c @@ -123,7 +123,7 @@ static void ci_ll_release(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer * } static int ci_ll_reset(struct dvb_ringbuffer *cibuf, struct file *file, - int slots, ca_slot_info_t *slot) + int slots, ca_slot_info_t *slot) { int i; int len = 0; -- cgit v1.2.3 From 3a4a571124cdd04215e0f78bc53fe16bab58f32d Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:29 -0700 Subject: [PATCH] dvb: nxt6000: support frontend status reads add support for read_ber, read_signal_strength and read_status (Greg Wickham) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/nxt6000.c | 44 +++++++++++++++++++++++++++++- drivers/media/dvb/frontends/nxt6000_priv.h | 21 ++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c index a41f7da8b84..f79a69d0eb0 100644 --- a/drivers/media/dvb/frontends/nxt6000.c +++ b/drivers/media/dvb/frontends/nxt6000.c @@ -180,7 +180,12 @@ static void nxt6000_setup(struct dvb_frontend* fe) nxt6000_writereg(state, RS_COR_SYNC_PARAM, SYNC_PARAM); nxt6000_writereg(state, BER_CTRL, /*(1 << 2) | */ (0x01 << 1) | 0x01); - nxt6000_writereg(state, VIT_COR_CTL, VIT_COR_RESYNC); + nxt6000_writereg(state, VIT_BERTIME_2, 0x00); // BER Timer = 0x000200 * 256 = 131072 bits + nxt6000_writereg(state, VIT_BERTIME_1, 0x02); // + nxt6000_writereg(state, VIT_BERTIME_0, 0x00); // + nxt6000_writereg(state, VIT_COR_INTEN, 0x98); // Enable BER interrupts + nxt6000_writereg(state, VIT_COR_CTL, 0x82); // Enable BER measurement + nxt6000_writereg(state, VIT_COR_CTL, VIT_COR_RESYNC | 0x02 ); nxt6000_writereg(state, OFDM_COR_CTL, (0x01 << 5) | (nxt6000_readreg(state, OFDM_COR_CTL) & 0x0F)); nxt6000_writereg(state, OFDM_COR_MODEGUARD, FORCEMODE8K | 0x02); nxt6000_writereg(state, OFDM_AGC_CTL, AGCLAST | INITIAL_AGC_BW); @@ -486,6 +491,40 @@ static void nxt6000_release(struct dvb_frontend* fe) kfree(state); } +static int nxt6000_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; + + *snr = nxt6000_readreg( state, OFDM_CHC_SNR) / 8; + + return 0; +} + +static int nxt6000_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; + + nxt6000_writereg( state, VIT_COR_INTSTAT, 0x18 ); + + *ber = (nxt6000_readreg( state, VIT_BER_1 ) << 8 ) | + nxt6000_readreg( state, VIT_BER_0 ); + + nxt6000_writereg( state, VIT_COR_INTSTAT, 0x18); // Clear BER Done interrupts + + return 0; +} + +static int nxt6000_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) +{ + struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; + + *signal_strength = (short) (511 - + (nxt6000_readreg(state, AGC_GAIN_1) + + ((nxt6000_readreg(state, AGC_GAIN_2) & 0x03) << 8))); + + return 0; +} + static struct dvb_frontend_ops nxt6000_ops; struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, @@ -542,6 +581,9 @@ static struct dvb_frontend_ops nxt6000_ops = { .set_frontend = nxt6000_set_frontend, .read_status = nxt6000_read_status, + .read_ber = nxt6000_read_ber, + .read_signal_strength = nxt6000_read_signal_strength, + .read_snr = nxt6000_read_snr, }; module_param(debug, int, 0644); diff --git a/drivers/media/dvb/frontends/nxt6000_priv.h b/drivers/media/dvb/frontends/nxt6000_priv.h index 64b1a89b2a2..0422e580038 100644 --- a/drivers/media/dvb/frontends/nxt6000_priv.h +++ b/drivers/media/dvb/frontends/nxt6000_priv.h @@ -65,12 +65,27 @@ #define BER_DONE (0x08) #define BER_OVERFLOW (0x10) +/* 0x38 VIT_BERTIME_2 */ +#define VIT_BERTIME_2 (0x38) + +/* 0x39 VIT_BERTIME_1 */ +#define VIT_BERTIME_1 (0x39) + +/* 0x3A VIT_BERTIME_0 */ +#define VIT_BERTIME_0 (0x3a) + /* 0x38 OFDM_BERTimer *//* Use the alias registers */ #define A_VIT_BER_TIMER_0 (0x1D) /* 0x3A VIT_BER_TIMER_0 *//* Use the alias registers */ #define A_VIT_BER_0 (0x1B) +/* 0x3B VIT_BER_1 */ +#define VIT_BER_1 (0x3b) + +/* 0x3C VIT_BER_0 */ +#define VIT_BER_0 (0x3c) + /* 0x40 OFDM_COR_CTL */ #define OFDM_COR_CTL (0x40) #define COREACT (0x20) @@ -117,6 +132,12 @@ #define OFDM_ITB_CTL (0x4B) #define ITBINV (0x01) +/* 0x49 AGC_GAIN_1 */ +#define AGC_GAIN_1 (0x49) + +/* 0x4A AGC_GAIN_2 */ +#define AGC_GAIN_2 (0x4A) + /* 0x4C OFDM_ITB_FREQ_1 */ #define OFDM_ITB_FREQ_1 (0x4C) -- cgit v1.2.3 From 7f5e02db4a39c36e68878a14fae1fe7ee6dd6fcf Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:30 -0700 Subject: [PATCH] dvb: tda1004x: formatting cleanups mostly formatting cleanups, no functional change (Andreas Oberritter) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/tda1004x.c | 246 +++++++++++++++++---------------- 1 file changed, 125 insertions(+), 121 deletions(-) diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 687ad9cf338..6dd428b7c9e 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -35,9 +35,10 @@ #include "dvb_frontend.h" #include "tda1004x.h" -#define TDA1004X_DEMOD_TDA10045 0 -#define TDA1004X_DEMOD_TDA10046 1 - +enum tda1004x_demod { + TDA1004X_DEMOD_TDA10045, + TDA1004X_DEMOD_TDA10046, +}; struct tda1004x_state { struct i2c_adapter* i2c; @@ -46,8 +47,8 @@ struct tda1004x_state { struct dvb_frontend frontend; /* private demod data */ - u8 initialised:1; - u8 demod_type; + u8 initialised; + enum tda1004x_demod demod_type; }; @@ -139,7 +140,7 @@ static int tda1004x_write_byteI(struct tda1004x_state *state, int reg, int data) { int ret; u8 buf[] = { reg, data }; - struct i2c_msg msg = { .addr=0, .flags=0, .buf=buf, .len=2 }; + struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 }; dprintk("%s: reg=0x%x, data=0x%x\n", __FUNCTION__, reg, data); @@ -160,8 +161,8 @@ static int tda1004x_read_byte(struct tda1004x_state *state, int reg) int ret; u8 b0[] = { reg }; u8 b1[] = { 0 }; - struct i2c_msg msg[] = {{ .addr=0, .flags=0, .buf=b0, .len=1}, - { .addr=0, .flags=I2C_M_RD, .buf=b1, .len = 1}}; + struct i2c_msg msg[] = {{ .flags = 0, .buf = b0, .len = 1 }, + { .flags = I2C_M_RD, .buf = b1, .len = 1 }}; dprintk("%s: reg=0x%x\n", __FUNCTION__, reg); @@ -294,7 +295,7 @@ static int tda1004x_do_upload(struct tda1004x_state *state, u8 dspCodeCounterReg, u8 dspCodeInReg) { u8 buf[65]; - struct i2c_msg fw_msg = {.addr = 0,.flags = 0,.buf = buf,.len = 0 }; + struct i2c_msg fw_msg = { .flags = 0, .buf = buf, .len = 0 }; int tx_size; int pos = 0; @@ -304,12 +305,10 @@ static int tda1004x_do_upload(struct tda1004x_state *state, buf[0] = dspCodeInReg; while (pos != len) { - // work out how much to send this time tx_size = len - pos; - if (tx_size > 0x10) { + if (tx_size > 0x10) tx_size = 0x10; - } // send the chunk memcpy(buf + 1, mem + pos, tx_size); @@ -322,6 +321,7 @@ static int tda1004x_do_upload(struct tda1004x_state *state, dprintk("%s: fw_pos=0x%x\n", __FUNCTION__, pos); } + return 0; } @@ -335,9 +335,8 @@ static int tda1004x_check_upload_ok(struct tda1004x_state *state, u8 dspVersion) data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1); data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2); - if (data1 != 0x67 || data2 != dspVersion) { + if ((data1 != 0x67) || (data2 != dspVersion)) return -EIO; - } return 0; } @@ -348,9 +347,9 @@ static int tda10045_fwupload(struct dvb_frontend* fe) int ret; const struct firmware *fw; - /* don't re-upload unless necessary */ - if (tda1004x_check_upload_ok(state, 0x2c) == 0) return 0; + if (tda1004x_check_upload_ok(state, 0x2c) == 0) + return 0; /* request the firmware, this will block until someone uploads it */ printk("tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE); @@ -394,7 +393,8 @@ static int tda10046_fwupload(struct dvb_frontend* fe) msleep(100); /* don't re-upload unless necessary */ - if (tda1004x_check_upload_ok(state, 0x20) == 0) return 0; + if (tda1004x_check_upload_ok(state, 0x20) == 0) + return 0; /* request the firmware, this will block until someone uploads it */ printk("tda1004x: waiting for firmware upload (%s)...\n", TDA10046_DEFAULT_FIRMWARE); @@ -419,7 +419,7 @@ static int tda10046_fwupload(struct dvb_frontend* fe) /* wait for DSP to initialise */ timeout = jiffies + HZ; - while(!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) { + while (!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) { if (time_after(jiffies, timeout)) { printk("tda1004x: DSP failed to initialised.\n"); return -EIO; @@ -483,7 +483,8 @@ static int tda10045_init(struct dvb_frontend* fe) dprintk("%s\n", __FUNCTION__); - if (state->initialised) return 0; + if (state->initialised) + return 0; if (tda10045_fwupload(fe)) { printk("tda1004x: firmware upload failed\n"); @@ -523,7 +524,8 @@ static int tda10046_init(struct dvb_frontend* fe) struct tda1004x_state* state = fe->demodulator_priv; dprintk("%s\n", __FUNCTION__); - if (state->initialised) return 0; + if (state->initialised) + return 0; if (tda10046_fwupload(fe)) { printk("tda1004x: firmware upload failed\n"); @@ -621,12 +623,14 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, // set HP FEC tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_HP); - if (tmp < 0) return tmp; + if (tmp < 0) + return tmp; tda1004x_write_mask(state, TDA1004X_IN_CONF2, 7, tmp); // set LP FEC tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_LP); - if (tmp < 0) return tmp; + if (tmp < 0) + return tmp; tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3); // set constellation @@ -671,7 +675,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, } // set bandwidth - switch(state->demod_type) { + switch (state->demod_type) { case TDA1004X_DEMOD_TDA10045: tda10045h_set_bandwidth(state, fe_params->u.ofdm.bandwidth); break; @@ -683,7 +687,8 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, // set inversion inversion = fe_params->inversion; - if (state->config->invert) inversion = inversion ? INVERSION_OFF : INVERSION_ON; + if (state->config->invert) + inversion = inversion ? INVERSION_OFF : INVERSION_ON; switch (inversion) { case INVERSION_OFF: tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0); @@ -750,19 +755,19 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, } // start the lock - switch(state->demod_type) { + switch (state->demod_type) { case TDA1004X_DEMOD_TDA10045: tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0); - msleep(10); break; case TDA1004X_DEMOD_TDA10046: tda1004x_write_mask(state, TDA1004X_AUTO, 0x40, 0x40); - msleep(10); break; } + msleep(10); + return 0; } @@ -773,13 +778,13 @@ static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_paramete // inversion status fe_params->inversion = INVERSION_OFF; - if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20) { + if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20) fe_params->inversion = INVERSION_ON; - } - if (state->config->invert) fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON; + if (state->config->invert) + fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON; // bandwidth - switch(state->demod_type) { + switch (state->demod_type) { case TDA1004X_DEMOD_TDA10045: switch (tda1004x_read_byte(state, TDA10045H_WREF_LSB)) { case 0x14: @@ -830,9 +835,8 @@ static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_paramete // transmission mode fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; - if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10) { + if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10) fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; - } // guard interval switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) { @@ -880,30 +884,33 @@ static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status // read status status = tda1004x_read_byte(state, TDA1004X_STATUS_CD); - if (status == -1) { + if (status == -1) return -EIO; - } // decode *fe_status = 0; - if (status & 4) *fe_status |= FE_HAS_SIGNAL; - if (status & 2) *fe_status |= FE_HAS_CARRIER; - if (status & 8) *fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + if (status & 4) + *fe_status |= FE_HAS_SIGNAL; + if (status & 2) + *fe_status |= FE_HAS_CARRIER; + if (status & 8) + *fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; // if we don't already have VITERBI (i.e. not LOCKED), see if the viterbi // is getting anything valid if (!(*fe_status & FE_HAS_VITERBI)) { // read the CBER cber = tda1004x_read_byte(state, TDA1004X_CBER_LSB); - if (cber == -1) return -EIO; + if (cber == -1) + return -EIO; status = tda1004x_read_byte(state, TDA1004X_CBER_MSB); - if (status == -1) return -EIO; + if (status == -1) + return -EIO; cber |= (status << 8); tda1004x_read_byte(state, TDA1004X_CBER_RESET); - if (cber != 65535) { + if (cber != 65535) *fe_status |= FE_HAS_VITERBI; - } } // if we DO have some valid VITERBI output, but don't already have SYNC @@ -911,20 +918,22 @@ static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) { // read the VBER vber = tda1004x_read_byte(state, TDA1004X_VBER_LSB); - if (vber == -1) return -EIO; + if (vber == -1) + return -EIO; status = tda1004x_read_byte(state, TDA1004X_VBER_MID); - if (status == -1) return -EIO; + if (status == -1) + return -EIO; vber |= (status << 8); status = tda1004x_read_byte(state, TDA1004X_VBER_MSB); - if (status == -1) return -EIO; + if (status == -1) + return -EIO; vber |= ((status << 16) & 0x0f); tda1004x_read_byte(state, TDA1004X_CVBER_LUT); // if RS has passed some valid TS packets, then we must be // getting some SYNC bytes - if (vber < 16632) { + if (vber < 16632) *fe_status |= FE_HAS_SYNC; - } } // success @@ -941,7 +950,7 @@ static int tda1004x_read_signal_strength(struct dvb_frontend* fe, u16 * signal) dprintk("%s\n", __FUNCTION__); // determine the register to use - switch(state->demod_type) { + switch (state->demod_type) { case TDA1004X_DEMOD_TDA10045: reg = TDA10045H_S_AGC; break; @@ -972,9 +981,8 @@ static int tda1004x_read_snr(struct dvb_frontend* fe, u16 * snr) tmp = tda1004x_read_byte(state, TDA1004X_SNR); if (tmp < 0) return -EIO; - if (tmp) { + if (tmp) tmp = 255 - tmp; - } *snr = ((tmp << 8) | tmp); dprintk("%s: snr=0x%x\n", __FUNCTION__, *snr); @@ -1009,11 +1017,11 @@ static int tda1004x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) break; } - if (tmp != 0x7f) { + if (tmp != 0x7f) *ucblocks = tmp; - } else { + else *ucblocks = 0xffffffff; - } + dprintk("%s: ucblocks=0x%x\n", __FUNCTION__, *ucblocks); return 0; } @@ -1027,10 +1035,12 @@ static int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber) // read it in tmp = tda1004x_read_byte(state, TDA1004X_CBER_LSB); - if (tmp < 0) return -EIO; + if (tmp < 0) + return -EIO; *ber = tmp << 1; tmp = tda1004x_read_byte(state, TDA1004X_CBER_MSB); - if (tmp < 0) return -EIO; + if (tmp < 0) + return -EIO; *ber |= (tmp << 9); tda1004x_read_byte(state, TDA1004X_CBER_RESET); @@ -1042,7 +1052,7 @@ static int tda1004x_sleep(struct dvb_frontend* fe) { struct tda1004x_state* state = fe->demodulator_priv; - switch(state->demod_type) { + switch (state->demod_type) { case TDA1004X_DEMOD_TDA10045: tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0x10); break; @@ -1066,74 +1076,11 @@ static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_fronte static void tda1004x_release(struct dvb_frontend* fe) { - struct tda1004x_state* state = (struct tda1004x_state*) fe->demodulator_priv; + struct tda1004x_state *state = fe->demodulator_priv; kfree(state); } -static struct dvb_frontend_ops tda10045_ops; - -struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, - struct i2c_adapter* i2c) -{ - struct tda1004x_state* state = NULL; - - /* allocate memory for the internal state */ - state = (struct tda1004x_state*) kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - memcpy(&state->ops, &tda10045_ops, sizeof(struct dvb_frontend_ops)); - state->initialised = 0; - state->demod_type = TDA1004X_DEMOD_TDA10045; - - /* check if the demod is there */ - if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x25) goto error; - - /* create dvb_frontend */ - state->frontend.ops = &state->ops; - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops tda10046_ops; - -struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, - struct i2c_adapter* i2c) -{ - struct tda1004x_state* state = NULL; - - /* allocate memory for the internal state */ - state = (struct tda1004x_state*) kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* setup the state */ - state->config = config; - state->i2c = i2c; - memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops)); - state->initialised = 0; - state->demod_type = TDA1004X_DEMOD_TDA10046; - - /* check if the demod is there */ - if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x46) goto error; - - /* create dvb_frontend */ - state->frontend.ops = &state->ops; - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - if (state) kfree(state); - return NULL; -} - static struct dvb_frontend_ops tda10045_ops = { - .info = { .name = "Philips TDA10045H DVB-T", .type = FE_OFDM, @@ -1163,8 +1110,36 @@ static struct dvb_frontend_ops tda10045_ops = { .read_ucblocks = tda1004x_read_ucblocks, }; -static struct dvb_frontend_ops tda10046_ops = { +struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, + struct i2c_adapter* i2c) +{ + struct tda1004x_state *state; + + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL); + if (!state) + return NULL; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &tda10045_ops, sizeof(struct dvb_frontend_ops)); + state->initialised = 0; + state->demod_type = TDA1004X_DEMOD_TDA10045; + + /* check if the demod is there */ + if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x25) { + kfree(state); + return NULL; + } + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; +} +static struct dvb_frontend_ops tda10046_ops = { .info = { .name = "Philips TDA10046H DVB-T", .type = FE_OFDM, @@ -1194,6 +1169,35 @@ static struct dvb_frontend_ops tda10046_ops = { .read_ucblocks = tda1004x_read_ucblocks, }; +struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, + struct i2c_adapter* i2c) +{ + struct tda1004x_state *state; + + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL); + if (!state) + return NULL; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops)); + state->initialised = 0; + state->demod_type = TDA1004X_DEMOD_TDA10046; + + /* check if the demod is there */ + if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x46) { + kfree(state); + return NULL; + } + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; +} + module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -- cgit v1.2.3 From 591ad98db3be2cd596ac5e0cfba7b164c3bdfb52 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:31 -0700 Subject: [PATCH] dvb: stv0299: fix FE_DISHNETWORK_SEND_LEGACY_CMD fix the current stv0299 code that handles FE_DISHNETWORK_SEND_LEGACY_CMD. (supports the legacy SW21, SW44, and SW64 switches) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/stv0299.c | 78 +++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 12 deletions(-) diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index 15b40541b62..a47cd2b32d6 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -70,6 +70,7 @@ struct stv0299_state { #define STATUS_UCBLOCKS 1 static int debug; +static int debug_legacy_dish_switch; #define dprintk(args...) \ do { \ if (debug) printk(KERN_DEBUG "stv0299: " args); \ @@ -385,34 +386,84 @@ static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag }; } -static int stv0299_send_legacy_dish_cmd(struct dvb_frontend* fe, u32 cmd) +static inline s32 stv0299_calc_usec_delay (struct timeval lasttime, struct timeval curtime) { + return ((curtime.tv_usec < lasttime.tv_usec) ? + 1000000 - lasttime.tv_usec + curtime.tv_usec : + curtime.tv_usec - lasttime.tv_usec); +} + +static void stv0299_sleep_until (struct timeval *waketime, u32 add_usec) +{ + struct timeval lasttime; + s32 delta, newdelta; + + waketime->tv_usec += add_usec; + if (waketime->tv_usec >= 1000000) { + waketime->tv_usec -= 1000000; + waketime->tv_sec++; + } + + do_gettimeofday (&lasttime); + delta = stv0299_calc_usec_delay (lasttime, *waketime); + if (delta > 2500) { + msleep ((delta - 1500) / 1000); + do_gettimeofday (&lasttime); + newdelta = stv0299_calc_usec_delay (lasttime, *waketime); + delta = (newdelta > delta) ? 0 : newdelta; + } + if (delta > 0) + udelay (delta); +} + +static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd) +{ + struct stv0299_state* state = fe->demodulator_priv; + u8 reg0x08; + u8 reg0x0c; + u8 lv_mask = 0x40; u8 last = 1; int i; + struct timeval nexttime; + struct timeval tv[10]; - /* reset voltage at the end - if((0x50 & stv0299_readreg (i2c, 0x0c)) == 0x50) - cmd |= 0x80; - else - cmd &= 0x7F; - */ + reg0x08 = stv0299_readreg (state, 0x08); + reg0x0c = stv0299_readreg (state, 0x0c); + reg0x0c &= 0x0f; + stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6)); + if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0) + lv_mask = 0x10; cmd = cmd << 1; - dprintk("%s switch command: 0x%04x\n",__FUNCTION__, cmd); + if (debug_legacy_dish_switch) + printk ("%s switch command: 0x%04x\n",__FUNCTION__, cmd); + + do_gettimeofday (&nexttime); + if (debug_legacy_dish_switch) + memcpy (&tv[0], &nexttime, sizeof (struct timeval)); + stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */ - stv0299_set_voltage(fe,SEC_VOLTAGE_18); - msleep(32); + stv0299_sleep_until (&nexttime, 32000); for (i=0; i<9; i++) { + if (debug_legacy_dish_switch) + do_gettimeofday (&tv[i+1]); if((cmd & 0x01) != last) { - stv0299_set_voltage(fe, last ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18); + /* set voltage to (last ? 13V : 18V) */ + stv0299_writeregI (state, 0x0c, reg0x0c | (last ? lv_mask : 0x50)); last = (last) ? 0 : 1; } cmd = cmd >> 1; if (i != 8) - msleep(8); + stv0299_sleep_until (&nexttime, 8000); + } + if (debug_legacy_dish_switch) { + printk ("%s(%d): switch delay (should be 32k followed by all 8k\n", + __FUNCTION__, fe->dvb->num); + for (i=1; i < 10; i++) + printk ("%d: %d\n", i, stv0299_calc_usec_delay (tv[i-1] , tv[i])); } return 0; @@ -719,6 +770,9 @@ static struct dvb_frontend_ops stv0299_ops = { .dishnetwork_send_legacy_command = stv0299_send_legacy_dish_cmd, }; +module_param(debug_legacy_dish_switch, int, 0444); +MODULE_PARM_DESC(debug_legacy_dish_switch, "Enable timing analysis for Dish Network legacy switches"); + module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -- cgit v1.2.3 From b8742700f13163ffa00cddce2a3c940b9ab2ab5a Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:31 -0700 Subject: [PATCH] dvb: remove unnecessary casts in frontends remove unnecessary casts in frontends (Kenneth Aafloy) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/at76c651.c | 18 +++++++-------- drivers/media/dvb/frontends/cx22700.c | 20 ++++++++--------- drivers/media/dvb/frontends/cx22702.c | 20 ++++++++--------- drivers/media/dvb/frontends/cx24110.c | 31 +++++++++++++------------ drivers/media/dvb/frontends/dib3000mb.c | 26 ++++++++++----------- drivers/media/dvb/frontends/dib3000mc.c | 24 ++++++++++---------- drivers/media/dvb/frontends/dvb_dummy_fe.c | 8 +++---- drivers/media/dvb/frontends/l64781.c | 22 +++++++++--------- drivers/media/dvb/frontends/mt312.c | 32 +++++++++++++------------- drivers/media/dvb/frontends/nxt2002.c | 20 ++++++++--------- drivers/media/dvb/frontends/nxt6000.c | 18 +++++++-------- drivers/media/dvb/frontends/or51132.c | 14 ++++++------ drivers/media/dvb/frontends/sp8870.c | 20 ++++++++--------- drivers/media/dvb/frontends/sp887x.c | 22 +++++++++--------- drivers/media/dvb/frontends/stv0297.c | 24 ++++++++++---------- drivers/media/dvb/frontends/stv0299.c | 36 +++++++++++++++--------------- drivers/media/dvb/frontends/tda10021.c | 22 +++++++++--------- drivers/media/dvb/frontends/tda8083.c | 26 ++++++++++----------- drivers/media/dvb/frontends/tda80xx.c | 34 ++++++++++++++-------------- drivers/media/dvb/frontends/ves1820.c | 22 +++++++++--------- drivers/media/dvb/frontends/ves1x93.c | 24 ++++++++++---------- 21 files changed, 241 insertions(+), 242 deletions(-) diff --git a/drivers/media/dvb/frontends/at76c651.c b/drivers/media/dvb/frontends/at76c651.c index ce2eaa1640e..72a2b5455b0 100644 --- a/drivers/media/dvb/frontends/at76c651.c +++ b/drivers/media/dvb/frontends/at76c651.c @@ -259,7 +259,7 @@ static int at76c651_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { int ret; - struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; + struct at76c651_state* state = fe->demodulator_priv; at76c651_writereg(state, 0x0c, 0xc3); state->config->pll_set(fe, p); @@ -276,7 +276,7 @@ static int at76c651_set_parameters(struct dvb_frontend* fe, static int at76c651_set_defaults(struct dvb_frontend* fe) { - struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; + struct at76c651_state* state = fe->demodulator_priv; at76c651_set_symbol_rate(state, 6900000); at76c651_set_qam(state, QAM_64); @@ -294,7 +294,7 @@ static int at76c651_set_defaults(struct dvb_frontend* fe) static int at76c651_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; + struct at76c651_state* state = fe->demodulator_priv; u8 sync; /* @@ -319,7 +319,7 @@ static int at76c651_read_status(struct dvb_frontend* fe, fe_status_t* status) static int at76c651_read_ber(struct dvb_frontend* fe, u32* ber) { - struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; + struct at76c651_state* state = fe->demodulator_priv; *ber = (at76c651_readreg(state, 0x81) & 0x0F) << 16; *ber |= at76c651_readreg(state, 0x82) << 8; @@ -331,7 +331,7 @@ static int at76c651_read_ber(struct dvb_frontend* fe, u32* ber) static int at76c651_read_signal_strength(struct dvb_frontend* fe, u16* strength) { - struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; + struct at76c651_state* state = fe->demodulator_priv; u8 gain = ~at76c651_readreg(state, 0x91); *strength = (gain << 8) | gain; @@ -341,7 +341,7 @@ static int at76c651_read_signal_strength(struct dvb_frontend* fe, u16* strength) static int at76c651_read_snr(struct dvb_frontend* fe, u16* snr) { - struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; + struct at76c651_state* state = fe->demodulator_priv; *snr = 0xFFFF - ((at76c651_readreg(state, 0x8F) << 8) | @@ -352,7 +352,7 @@ static int at76c651_read_snr(struct dvb_frontend* fe, u16* snr) static int at76c651_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; + struct at76c651_state* state = fe->demodulator_priv; *ucblocks = at76c651_readreg(state, 0x82); @@ -369,7 +369,7 @@ static int at76c651_get_tune_settings(struct dvb_frontend* fe, struct dvb_fronte static void at76c651_release(struct dvb_frontend* fe) { - struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; + struct at76c651_state* state = fe->demodulator_priv; kfree(state); } @@ -381,7 +381,7 @@ struct dvb_frontend* at76c651_attach(const struct at76c651_config* config, struct at76c651_state* state = NULL; /* allocate memory for the internal state */ - state = (struct at76c651_state*) kmalloc(sizeof(struct at76c651_state), GFP_KERNEL); + state = kmalloc(sizeof(struct at76c651_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c index a212279042b..0c2ed443861 100644 --- a/drivers/media/dvb/frontends/cx22700.c +++ b/drivers/media/dvb/frontends/cx22700.c @@ -232,7 +232,7 @@ static int cx22700_get_tps (struct cx22700_state* state, struct dvb_ofdm_paramet static int cx22700_init (struct dvb_frontend* fe) -{ struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; +{ struct cx22700_state* state = fe->demodulator_priv; int i; dprintk("cx22700_init: init chip\n"); @@ -258,7 +258,7 @@ static int cx22700_init (struct dvb_frontend* fe) static int cx22700_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; + struct cx22700_state* state = fe->demodulator_priv; u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9) | (cx22700_readreg (state, 0x0e) << 1); @@ -286,7 +286,7 @@ static int cx22700_read_status(struct dvb_frontend* fe, fe_status_t* status) static int cx22700_read_ber(struct dvb_frontend* fe, u32* ber) { - struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; + struct cx22700_state* state = fe->demodulator_priv; *ber = cx22700_readreg (state, 0x0c) & 0x7f; cx22700_writereg (state, 0x0c, 0x00); @@ -296,7 +296,7 @@ static int cx22700_read_ber(struct dvb_frontend* fe, u32* ber) static int cx22700_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) { - struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; + struct cx22700_state* state = fe->demodulator_priv; u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9) | (cx22700_readreg (state, 0x0e) << 1); @@ -307,7 +307,7 @@ static int cx22700_read_signal_strength(struct dvb_frontend* fe, u16* signal_str static int cx22700_read_snr(struct dvb_frontend* fe, u16* snr) { - struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; + struct cx22700_state* state = fe->demodulator_priv; u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9) | (cx22700_readreg (state, 0x0e) << 1); @@ -318,7 +318,7 @@ static int cx22700_read_snr(struct dvb_frontend* fe, u16* snr) static int cx22700_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; + struct cx22700_state* state = fe->demodulator_priv; *ucblocks = cx22700_readreg (state, 0x0f); cx22700_writereg (state, 0x0f, 0x00); @@ -328,7 +328,7 @@ static int cx22700_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) static int cx22700_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; + struct cx22700_state* state = fe->demodulator_priv; cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/ cx22700_writereg (state, 0x00, 0x00); @@ -346,7 +346,7 @@ static int cx22700_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par static int cx22700_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; + struct cx22700_state* state = fe->demodulator_priv; u8 reg09 = cx22700_readreg (state, 0x09); p->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF; @@ -363,7 +363,7 @@ static int cx22700_get_tune_settings(struct dvb_frontend* fe, struct dvb_fronten static void cx22700_release(struct dvb_frontend* fe) { - struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; + struct cx22700_state* state = fe->demodulator_priv; kfree(state); } @@ -375,7 +375,7 @@ struct dvb_frontend* cx22700_attach(const struct cx22700_config* config, struct cx22700_state* state = NULL; /* allocate memory for the internal state */ - state = (struct cx22700_state*) kmalloc(sizeof(struct cx22700_state), GFP_KERNEL); + state = kmalloc(sizeof(struct cx22700_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c index 011860ce36c..f4aa44136c7 100644 --- a/drivers/media/dvb/frontends/cx22702.c +++ b/drivers/media/dvb/frontends/cx22702.c @@ -200,7 +200,7 @@ static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_paramet static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { u8 val; - struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; + struct cx22702_state* state = fe->demodulator_priv; /* set PLL */ cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe); @@ -338,7 +338,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet static int cx22702_init (struct dvb_frontend* fe) { int i; - struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; + struct cx22702_state* state = fe->demodulator_priv; cx22702_writereg (state, 0x00, 0x02); @@ -360,7 +360,7 @@ static int cx22702_init (struct dvb_frontend* fe) static int cx22702_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; + struct cx22702_state* state = fe->demodulator_priv; u8 reg0A; u8 reg23; @@ -389,7 +389,7 @@ static int cx22702_read_status(struct dvb_frontend* fe, fe_status_t* status) static int cx22702_read_ber(struct dvb_frontend* fe, u32* ber) { - struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; + struct cx22702_state* state = fe->demodulator_priv; if(cx22702_readreg (state, 0xE4) & 0x02) { /* Realtime statistics */ @@ -406,7 +406,7 @@ static int cx22702_read_ber(struct dvb_frontend* fe, u32* ber) static int cx22702_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) { - struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; + struct cx22702_state* state = fe->demodulator_priv; *signal_strength = cx22702_readreg (state, 0x23); @@ -415,7 +415,7 @@ static int cx22702_read_signal_strength(struct dvb_frontend* fe, u16* signal_str static int cx22702_read_snr(struct dvb_frontend* fe, u16* snr) { - struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; + struct cx22702_state* state = fe->demodulator_priv; u16 rs_ber=0; if(cx22702_readreg (state, 0xE4) & 0x02) { @@ -434,7 +434,7 @@ static int cx22702_read_snr(struct dvb_frontend* fe, u16* snr) static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; + struct cx22702_state* state = fe->demodulator_priv; u8 _ucblocks; @@ -449,7 +449,7 @@ static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) static int cx22702_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; + struct cx22702_state* state = fe->demodulator_priv; u8 reg0C = cx22702_readreg (state, 0x0C); @@ -459,7 +459,7 @@ static int cx22702_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par static void cx22702_release(struct dvb_frontend* fe) { - struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; + struct cx22702_state* state = fe->demodulator_priv; kfree(state); } @@ -471,7 +471,7 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config, struct cx22702_state* state = NULL; /* allocate memory for the internal state */ - state = (struct cx22702_state*) kmalloc(sizeof(struct cx22702_state), GFP_KERNEL); + state = kmalloc(sizeof(struct cx22702_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index ae16112a065..8222b88cb48 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -315,7 +315,7 @@ dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate); int cx24110_pll_write (struct dvb_frontend* fe, u32 data) { - struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; + struct cx24110_state *state = fe->demodulator_priv; /* tuner data is 21 bits long, must be left-aligned in data */ /* tuner cx24108 is written through a dedicated 3wire interface on the demod chip */ @@ -356,7 +356,7 @@ int cx24110_pll_write (struct dvb_frontend* fe, u32 data) static int cx24110_initfe(struct dvb_frontend* fe) { - struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; + struct cx24110_state *state = fe->demodulator_priv; /* fixme (low): error handling */ int i; @@ -373,7 +373,7 @@ static int cx24110_initfe(struct dvb_frontend* fe) static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) { - struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; + struct cx24110_state *state = fe->demodulator_priv; switch (voltage) { case SEC_VOLTAGE_13: @@ -385,8 +385,7 @@ static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag }; } -static int cx24110_diseqc_send_burst(struct dvb_frontend* fe, - fe_sec_mini_cmd_t burst) +static int cx24110_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) { int rv, bit, i; struct cx24110_state *state = fe->demodulator_priv; @@ -413,7 +412,7 @@ static int cx24110_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd) { int i, rv; - struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; + struct cx24110_state *state = fe->demodulator_priv; for (i = 0; i < cmd->msg_len; i++) cx24110_writereg(state, 0x79 + i, cmd->msg[i]); @@ -432,7 +431,7 @@ static int cx24110_send_diseqc_msg(struct dvb_frontend* fe, static int cx24110_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; + struct cx24110_state *state = fe->demodulator_priv; int sync = cx24110_readreg (state, 0x55); @@ -460,7 +459,7 @@ static int cx24110_read_status(struct dvb_frontend* fe, fe_status_t* status) static int cx24110_read_ber(struct dvb_frontend* fe, u32* ber) { - struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; + struct cx24110_state *state = fe->demodulator_priv; /* fixme (maybe): value range is 16 bit. Scale? */ if(cx24110_readreg(state,0x24)&0x10) { @@ -478,7 +477,7 @@ static int cx24110_read_ber(struct dvb_frontend* fe, u32* ber) static int cx24110_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) { - struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; + struct cx24110_state *state = fe->demodulator_priv; /* no provision in hardware. Read the frontend AGC accumulator. No idea how to scale this, but I know it is 2s complement */ u8 signal = cx24110_readreg (state, 0x27)+128; @@ -489,7 +488,7 @@ static int cx24110_read_signal_strength(struct dvb_frontend* fe, u16* signal_str static int cx24110_read_snr(struct dvb_frontend* fe, u16* snr) { - struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; + struct cx24110_state *state = fe->demodulator_priv; /* no provision in hardware. Can be computed from the Es/N0 estimator, but I don't know how. */ if(cx24110_readreg(state,0x6a)&0x80) { @@ -505,7 +504,7 @@ static int cx24110_read_snr(struct dvb_frontend* fe, u16* snr) static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; + struct cx24110_state *state = fe->demodulator_priv; u32 lastbyer; if(cx24110_readreg(state,0x10)&0x40) { @@ -527,7 +526,7 @@ static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; + struct cx24110_state *state = fe->demodulator_priv; state->config->pll_set(fe, p); cx24110_set_inversion (state, p->inversion); @@ -540,7 +539,7 @@ static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par static int cx24110_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; + struct cx24110_state *state = fe->demodulator_priv; s32 afc; unsigned sclk; /* cannot read back tuner settings (freq). Need to have some private storage */ @@ -567,14 +566,14 @@ static int cx24110_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par static int cx24110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) { - struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; + struct cx24110_state *state = fe->demodulator_priv; return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&~0x10)|(((tone==SEC_TONE_ON))?0x10:0)); } static void cx24110_release(struct dvb_frontend* fe) { - struct cx24110_state* state = (struct cx24110_state*) fe->demodulator_priv; + struct cx24110_state* state = fe->demodulator_priv; kfree(state); } @@ -587,7 +586,7 @@ struct dvb_frontend* cx24110_attach(const struct cx24110_config* config, int ret; /* allocate memory for the internal state */ - state = (struct cx24110_state*) kmalloc(sizeof(struct cx24110_state), GFP_KERNEL); + state = kmalloc(sizeof(struct cx24110_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c index a853d12a26f..f2fbb7c1598 100644 --- a/drivers/media/dvb/frontends/dib3000mb.c +++ b/drivers/media/dvb/frontends/dib3000mb.c @@ -56,7 +56,7 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe, static int dib3000mb_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep, int tuner) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state* state = fe->demodulator_priv; struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; fe_code_rate_t fe_cr = FEC_NONE; int search_state, seq; @@ -317,7 +317,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state* state = fe->demodulator_priv; deb_info("dib3000mb is getting up.\n"); wr(DIB3000MB_REG_POWER_CONTROL, DIB3000MB_POWER_UP); @@ -401,7 +401,7 @@ static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode) static int dib3000mb_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state* state = fe->demodulator_priv; struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; fe_code_rate_t *cr; u16 tps_val; @@ -562,7 +562,7 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe, static int dib3000mb_read_status(struct dvb_frontend* fe, fe_status_t *stat) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state* state = fe->demodulator_priv; *stat = 0; @@ -594,7 +594,7 @@ static int dib3000mb_read_status(struct dvb_frontend* fe, fe_status_t *stat) static int dib3000mb_read_ber(struct dvb_frontend* fe, u32 *ber) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state* state = fe->demodulator_priv; *ber = ((rd(DIB3000MB_REG_BER_MSB) << 16) | rd(DIB3000MB_REG_BER_LSB)); return 0; @@ -603,7 +603,7 @@ static int dib3000mb_read_ber(struct dvb_frontend* fe, u32 *ber) /* see dib3000-watch dvb-apps for exact calcuations of signal_strength and snr */ static int dib3000mb_read_signal_strength(struct dvb_frontend* fe, u16 *strength) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state* state = fe->demodulator_priv; *strength = rd(DIB3000MB_REG_SIGNAL_POWER) * 0xffff / 0x170; return 0; @@ -611,7 +611,7 @@ static int dib3000mb_read_signal_strength(struct dvb_frontend* fe, u16 *strength static int dib3000mb_read_snr(struct dvb_frontend* fe, u16 *snr) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state* state = fe->demodulator_priv; short sigpow = rd(DIB3000MB_REG_SIGNAL_POWER); int icipow = ((rd(DIB3000MB_REG_NOISE_POWER_MSB) & 0xff) << 16) | rd(DIB3000MB_REG_NOISE_POWER_LSB); @@ -621,7 +621,7 @@ static int dib3000mb_read_snr(struct dvb_frontend* fe, u16 *snr) static int dib3000mb_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state* state = fe->demodulator_priv; *unc = rd(DIB3000MB_REG_UNC); return 0; @@ -629,7 +629,7 @@ static int dib3000mb_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) static int dib3000mb_sleep(struct dvb_frontend* fe) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state* state = fe->demodulator_priv; deb_info("dib3000mb is going to bed.\n"); wr(DIB3000MB_REG_POWER_CONTROL, DIB3000MB_POWER_DOWN); return 0; @@ -656,7 +656,7 @@ static int dib3000mb_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_ static void dib3000mb_release(struct dvb_frontend* fe) { - struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state *state = fe->demodulator_priv; kfree(state); } @@ -671,7 +671,7 @@ static int dib3000mb_pid_control(struct dvb_frontend *fe,int index, int pid,int static int dib3000mb_fifo_control(struct dvb_frontend *fe, int onoff) { - struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state *state = fe->demodulator_priv; deb_xfer("%s fifo\n",onoff ? "enabling" : "disabling"); if (onoff) { @@ -692,7 +692,7 @@ static int dib3000mb_pid_parse(struct dvb_frontend *fe, int onoff) static int dib3000mb_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr) { - struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state *state = fe->demodulator_priv; if (onoff) { wr(DIB3000MB_REG_TUNER, DIB3000_TUNER_WRITE_ENABLE(pll_addr)); } else { @@ -709,7 +709,7 @@ struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, struct dib3000_state* state = NULL; /* allocate memory for the internal state */ - state = (struct dib3000_state*) kmalloc(sizeof(struct dib3000_state), GFP_KERNEL); + state = kmalloc(sizeof(struct dib3000_state), GFP_KERNEL); if (state == NULL) goto error; memset(state,0,sizeof(struct dib3000_state)); diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index 4a31c05eaec..bb0abdc78f3 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -297,7 +297,7 @@ static int dib3000mc_set_general_cfg(struct dib3000_state *state, struct dvb_fro static int dib3000mc_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state* state = fe->demodulator_priv; struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; fe_code_rate_t *cr; u16 tps_val,cr_val; @@ -458,7 +458,7 @@ static int dib3000mc_get_frontend(struct dvb_frontend* fe, static int dib3000mc_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep, int tuner) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state* state = fe->demodulator_priv; struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; int search_state,auto_val; u16 val; @@ -659,7 +659,7 @@ static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode) } static int dib3000mc_read_status(struct dvb_frontend* fe, fe_status_t *stat) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state* state = fe->demodulator_priv; u16 lock = rd(DIB3000MC_REG_LOCKING); *stat = 0; @@ -679,14 +679,14 @@ static int dib3000mc_read_status(struct dvb_frontend* fe, fe_status_t *stat) static int dib3000mc_read_ber(struct dvb_frontend* fe, u32 *ber) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state* state = fe->demodulator_priv; *ber = ((rd(DIB3000MC_REG_BER_MSB) << 16) | rd(DIB3000MC_REG_BER_LSB)); return 0; } static int dib3000mc_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state* state = fe->demodulator_priv; *unc = rd(DIB3000MC_REG_PACKET_ERROR_COUNT); return 0; @@ -695,7 +695,7 @@ static int dib3000mc_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) /* see dib3000mb.c for calculation comments */ static int dib3000mc_read_signal_strength(struct dvb_frontend* fe, u16 *strength) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state* state = fe->demodulator_priv; u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB); *strength = (((val >> 6) & 0xff) << 8) + (val & 0x3f); @@ -706,7 +706,7 @@ static int dib3000mc_read_signal_strength(struct dvb_frontend* fe, u16 *strength /* see dib3000mb.c for calculation comments */ static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state* state = fe->demodulator_priv; u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB), val2 = rd(DIB3000MC_REG_SIGNAL_NOISE_MSB); u16 sig,noise; @@ -726,7 +726,7 @@ static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr) static int dib3000mc_sleep(struct dvb_frontend* fe) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state* state = fe->demodulator_priv; set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_PWR_DOWN); wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_DOWN); @@ -756,7 +756,7 @@ static int dib3000mc_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_ static void dib3000mc_release(struct dvb_frontend* fe) { - struct dib3000_state *state = (struct dib3000_state *) fe->demodulator_priv; + struct dib3000_state *state = fe->demodulator_priv; kfree(state); } @@ -771,7 +771,7 @@ static int dib3000mc_pid_control(struct dvb_frontend *fe,int index, int pid,int static int dib3000mc_fifo_control(struct dvb_frontend *fe, int onoff) { - struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state *state = fe->demodulator_priv; u16 tmp = rd(DIB3000MC_REG_SMO_MODE); deb_xfer("%s fifo\n",onoff ? "enabling" : "disabling"); @@ -803,7 +803,7 @@ static int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff) static int dib3000mc_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr) { - struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv; + struct dib3000_state *state = fe->demodulator_priv; if (onoff) { wr(DIB3000MC_REG_TUNER, DIB3000_TUNER_WRITE_ENABLE(pll_addr)); } else { @@ -844,7 +844,7 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config, u16 devid; /* allocate memory for the internal state */ - state = (struct dib3000_state*) kmalloc(sizeof(struct dib3000_state), GFP_KERNEL); + state = kmalloc(sizeof(struct dib3000_state), GFP_KERNEL); if (state == NULL) goto error; memset(state,0,sizeof(struct dib3000_state)); diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c index c05a9b05600..cff93b9d8ab 100644 --- a/drivers/media/dvb/frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c @@ -100,7 +100,7 @@ static int dvb_dummy_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t vo static void dvb_dummy_fe_release(struct dvb_frontend* fe) { - struct dvb_dummy_fe_state* state = (struct dvb_dummy_fe_state*) fe->demodulator_priv; + struct dvb_dummy_fe_state* state = fe->demodulator_priv; kfree(state); } @@ -111,7 +111,7 @@ struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void) struct dvb_dummy_fe_state* state = NULL; /* allocate memory for the internal state */ - state = (struct dvb_dummy_fe_state*) kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); + state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ @@ -134,7 +134,7 @@ struct dvb_frontend* dvb_dummy_fe_qpsk_attach() struct dvb_dummy_fe_state* state = NULL; /* allocate memory for the internal state */ - state = (struct dvb_dummy_fe_state*) kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); + state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ @@ -157,7 +157,7 @@ struct dvb_frontend* dvb_dummy_fe_qam_attach() struct dvb_dummy_fe_state* state = NULL; /* allocate memory for the internal state */ - state = (struct dvb_dummy_fe_state*) kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); + state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c index 9ac95de9834..031a1ddc7d1 100644 --- a/drivers/media/dvb/frontends/l64781.c +++ b/drivers/media/dvb/frontends/l64781.c @@ -121,7 +121,7 @@ static int reset_and_configure (struct l64781_state* state) static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_parameters *param) { - struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; + struct l64781_state* state = fe->demodulator_priv; /* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */ static const u8 fec_tab[] = { 7, 0, 1, 2, 9, 3, 10, 4 }; /* QPSK, QAM_16, QAM_64 */ @@ -234,7 +234,7 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* param) { - struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; + struct l64781_state* state = fe->demodulator_priv; int tmp; @@ -352,7 +352,7 @@ static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* static int l64781_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; + struct l64781_state* state = fe->demodulator_priv; int sync = l64781_readreg (state, 0x32); int gain = l64781_readreg (state, 0x0e); @@ -381,7 +381,7 @@ static int l64781_read_status(struct dvb_frontend* fe, fe_status_t* status) static int l64781_read_ber(struct dvb_frontend* fe, u32* ber) { - struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; + struct l64781_state* state = fe->demodulator_priv; /* XXX FIXME: set up counting period (reg 0x26...0x28) */ @@ -393,7 +393,7 @@ static int l64781_read_ber(struct dvb_frontend* fe, u32* ber) static int l64781_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) { - struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; + struct l64781_state* state = fe->demodulator_priv; u8 gain = l64781_readreg (state, 0x0e); *signal_strength = (gain << 8) | gain; @@ -403,7 +403,7 @@ static int l64781_read_signal_strength(struct dvb_frontend* fe, u16* signal_stre static int l64781_read_snr(struct dvb_frontend* fe, u16* snr) { - struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; + struct l64781_state* state = fe->demodulator_priv; u8 avg_quality = 0xff - l64781_readreg (state, 0x33); *snr = (avg_quality << 8) | avg_quality; /* not exact, but...*/ @@ -413,7 +413,7 @@ static int l64781_read_snr(struct dvb_frontend* fe, u16* snr) static int l64781_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; + struct l64781_state* state = fe->demodulator_priv; *ucblocks = l64781_readreg (state, 0x37) | (l64781_readreg (state, 0x38) << 8); @@ -423,7 +423,7 @@ static int l64781_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) static int l64781_sleep(struct dvb_frontend* fe) { - struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; + struct l64781_state* state = fe->demodulator_priv; /* Power down */ return l64781_writereg (state, 0x3e, 0x5a); @@ -431,7 +431,7 @@ static int l64781_sleep(struct dvb_frontend* fe) static int l64781_init(struct dvb_frontend* fe) { - struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; + struct l64781_state* state = fe->demodulator_priv; reset_and_configure (state); @@ -484,7 +484,7 @@ static int l64781_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend static void l64781_release(struct dvb_frontend* fe) { - struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; + struct l64781_state* state = fe->demodulator_priv; kfree(state); } @@ -501,7 +501,7 @@ struct dvb_frontend* l64781_attach(const struct l64781_config* config, { .addr = config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; /* allocate memory for the internal state */ - state = (struct l64781_state*) kmalloc(sizeof(struct l64781_state), GFP_KERNEL); + state = kmalloc(sizeof(struct l64781_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c index 176a22e3441..e455aecd76b 100644 --- a/drivers/media/dvb/frontends/mt312.c +++ b/drivers/media/dvb/frontends/mt312.c @@ -226,7 +226,7 @@ static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr) static int mt312_initfe(struct dvb_frontend* fe) { - struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; + struct mt312_state *state = fe->demodulator_priv; int ret; u8 buf[2]; @@ -287,7 +287,7 @@ static int mt312_initfe(struct dvb_frontend* fe) static int mt312_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *c) { - struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; + struct mt312_state *state = fe->demodulator_priv; int ret; u8 diseqc_mode; @@ -318,7 +318,7 @@ static int mt312_send_master_cmd(struct dvb_frontend* fe, static int mt312_send_burst(struct dvb_frontend* fe, const fe_sec_mini_cmd_t c) { - struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; + struct mt312_state *state = fe->demodulator_priv; const u8 mini_tab[2] = { 0x02, 0x03 }; int ret; @@ -340,7 +340,7 @@ static int mt312_send_burst(struct dvb_frontend* fe, const fe_sec_mini_cmd_t c) static int mt312_set_tone(struct dvb_frontend* fe, const fe_sec_tone_mode_t t) { - struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; + struct mt312_state *state = fe->demodulator_priv; const u8 tone_tab[2] = { 0x01, 0x00 }; int ret; @@ -362,7 +362,7 @@ static int mt312_set_tone(struct dvb_frontend* fe, const fe_sec_tone_mode_t t) static int mt312_set_voltage(struct dvb_frontend* fe, const fe_sec_voltage_t v) { - struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; + struct mt312_state *state = fe->demodulator_priv; const u8 volt_tab[3] = { 0x00, 0x40, 0x00 }; if (v > SEC_VOLTAGE_OFF) @@ -373,7 +373,7 @@ static int mt312_set_voltage(struct dvb_frontend* fe, const fe_sec_voltage_t v) static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s) { - struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; + struct mt312_state *state = fe->demodulator_priv; int ret; u8 status[3]; @@ -400,7 +400,7 @@ static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s) static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber) { - struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; + struct mt312_state *state = fe->demodulator_priv; int ret; u8 buf[3]; @@ -414,7 +414,7 @@ static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber) static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_strength) { - struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; + struct mt312_state *state = fe->demodulator_priv; int ret; u8 buf[3]; u16 agc; @@ -435,7 +435,7 @@ static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_stren static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr) { - struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; + struct mt312_state *state = fe->demodulator_priv; int ret; u8 buf[2]; @@ -449,7 +449,7 @@ static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr) static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc) { - struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; + struct mt312_state *state = fe->demodulator_priv; int ret; u8 buf[2]; @@ -464,7 +464,7 @@ static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc) static int mt312_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; + struct mt312_state *state = fe->demodulator_priv; int ret; u8 buf[5], config_val; u16 sr; @@ -560,7 +560,7 @@ static int mt312_set_frontend(struct dvb_frontend* fe, static int mt312_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; + struct mt312_state *state = fe->demodulator_priv; int ret; if ((ret = mt312_get_inversion(state, &p->inversion)) < 0) @@ -577,7 +577,7 @@ static int mt312_get_frontend(struct dvb_frontend* fe, static int mt312_sleep(struct dvb_frontend* fe) { - struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; + struct mt312_state *state = fe->demodulator_priv; int ret; u8 config; @@ -605,7 +605,7 @@ static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_ static void mt312_release(struct dvb_frontend* fe) { - struct mt312_state* state = (struct mt312_state*) fe->demodulator_priv; + struct mt312_state* state = fe->demodulator_priv; kfree(state); } @@ -617,7 +617,7 @@ struct dvb_frontend* vp310_attach(const struct mt312_config* config, struct mt312_state* state = NULL; /* allocate memory for the internal state */ - state = (struct mt312_state*) kmalloc(sizeof(struct mt312_state), GFP_KERNEL); + state = kmalloc(sizeof(struct mt312_state), GFP_KERNEL); if (state == NULL) goto error; @@ -651,7 +651,7 @@ struct dvb_frontend* mt312_attach(const struct mt312_config* config, struct mt312_state* state = NULL; /* allocate memory for the internal state */ - state = (struct mt312_state*) kmalloc(sizeof(struct mt312_state), GFP_KERNEL); + state = kmalloc(sizeof(struct mt312_state), GFP_KERNEL); if (state == NULL) goto error; diff --git a/drivers/media/dvb/frontends/nxt2002.c b/drivers/media/dvb/frontends/nxt2002.c index 4743aa17406..8805b0f5f61 100644 --- a/drivers/media/dvb/frontends/nxt2002.c +++ b/drivers/media/dvb/frontends/nxt2002.c @@ -241,7 +241,7 @@ static void nxt2002_agc_reset(struct nxt2002_state* state) static int nxt2002_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) { - struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; + struct nxt2002_state* state = fe->demodulator_priv; u8 buf[256],written = 0,chunkpos = 0; u16 rambase,position,crc = 0; @@ -309,7 +309,7 @@ static int nxt2002_load_firmware (struct dvb_frontend* fe, const struct firmware static int nxt2002_setup_frontend_parameters (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; + struct nxt2002_state* state = fe->demodulator_priv; u32 freq = 0; u16 tunerfreq = 0; u8 buf[4]; @@ -453,7 +453,7 @@ static int nxt2002_setup_frontend_parameters (struct dvb_frontend* fe, static int nxt2002_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; + struct nxt2002_state* state = fe->demodulator_priv; u8 lock; i2c_readbytes(state,0x31,&lock,1); @@ -470,7 +470,7 @@ static int nxt2002_read_status(struct dvb_frontend* fe, fe_status_t* status) static int nxt2002_read_ber(struct dvb_frontend* fe, u32* ber) { - struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; + struct nxt2002_state* state = fe->demodulator_priv; u8 b[3]; nxt2002_readreg_multibyte(state,0xE6,b,3); @@ -482,7 +482,7 @@ static int nxt2002_read_ber(struct dvb_frontend* fe, u32* ber) static int nxt2002_read_signal_strength(struct dvb_frontend* fe, u16* strength) { - struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; + struct nxt2002_state* state = fe->demodulator_priv; u8 b[2]; u16 temp = 0; @@ -502,7 +502,7 @@ static int nxt2002_read_signal_strength(struct dvb_frontend* fe, u16* strength) static int nxt2002_read_snr(struct dvb_frontend* fe, u16* snr) { - struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; + struct nxt2002_state* state = fe->demodulator_priv; u8 b[2]; u16 temp = 0, temp2; u32 snrdb = 0; @@ -536,7 +536,7 @@ static int nxt2002_read_snr(struct dvb_frontend* fe, u16* snr) static int nxt2002_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; + struct nxt2002_state* state = fe->demodulator_priv; u8 b[3]; nxt2002_readreg_multibyte(state,0xE6,b,3); @@ -552,7 +552,7 @@ static int nxt2002_sleep(struct dvb_frontend* fe) static int nxt2002_init(struct dvb_frontend* fe) { - struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; + struct nxt2002_state* state = fe->demodulator_priv; const struct firmware *fw; int ret; u8 buf[2]; @@ -624,7 +624,7 @@ static int nxt2002_get_tune_settings(struct dvb_frontend* fe, struct dvb_fronten static void nxt2002_release(struct dvb_frontend* fe) { - struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; + struct nxt2002_state* state = fe->demodulator_priv; kfree(state); } @@ -637,7 +637,7 @@ struct dvb_frontend* nxt2002_attach(const struct nxt2002_config* config, u8 buf [] = {0,0,0,0,0}; /* allocate memory for the internal state */ - state = (struct nxt2002_state*) kmalloc(sizeof(struct nxt2002_state), GFP_KERNEL); + state = kmalloc(sizeof(struct nxt2002_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c index f79a69d0eb0..966de9853d1 100644 --- a/drivers/media/dvb/frontends/nxt6000.c +++ b/drivers/media/dvb/frontends/nxt6000.c @@ -176,7 +176,7 @@ static int nxt6000_set_transmission_mode(struct nxt6000_state* state, fe_transmi static void nxt6000_setup(struct dvb_frontend* fe) { - struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; + struct nxt6000_state* state = fe->demodulator_priv; nxt6000_writereg(state, RS_COR_SYNC_PARAM, SYNC_PARAM); nxt6000_writereg(state, BER_CTRL, /*(1 << 2) | */ (0x01 << 1) | 0x01); @@ -427,7 +427,7 @@ static void nxt6000_dump_status(struct nxt6000_state *state) static int nxt6000_read_status(struct dvb_frontend* fe, fe_status_t* status) { u8 core_status; - struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; + struct nxt6000_state* state = fe->demodulator_priv; *status = 0; @@ -456,7 +456,7 @@ static int nxt6000_read_status(struct dvb_frontend* fe, fe_status_t* status) static int nxt6000_init(struct dvb_frontend* fe) { - struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; + struct nxt6000_state* state = fe->demodulator_priv; nxt6000_reset(state); nxt6000_setup(fe); @@ -466,7 +466,7 @@ static int nxt6000_init(struct dvb_frontend* fe) static int nxt6000_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *param) { - struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; + struct nxt6000_state* state = fe->demodulator_priv; int result; nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */ @@ -487,13 +487,13 @@ static int nxt6000_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par static void nxt6000_release(struct dvb_frontend* fe) { - struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; + struct nxt6000_state* state = fe->demodulator_priv; kfree(state); } static int nxt6000_read_snr(struct dvb_frontend* fe, u16* snr) { - struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; + struct nxt6000_state* state = fe->demodulator_priv; *snr = nxt6000_readreg( state, OFDM_CHC_SNR) / 8; @@ -502,7 +502,7 @@ static int nxt6000_read_snr(struct dvb_frontend* fe, u16* snr) static int nxt6000_read_ber(struct dvb_frontend* fe, u32* ber) { - struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; + struct nxt6000_state* state = fe->demodulator_priv; nxt6000_writereg( state, VIT_COR_INTSTAT, 0x18 ); @@ -516,7 +516,7 @@ static int nxt6000_read_ber(struct dvb_frontend* fe, u32* ber) static int nxt6000_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) { - struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; + struct nxt6000_state* state = fe->demodulator_priv; *signal_strength = (short) (511 - (nxt6000_readreg(state, AGC_GAIN_1) + @@ -533,7 +533,7 @@ struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, struct nxt6000_state* state = NULL; /* allocate memory for the internal state */ - state = (struct nxt6000_state*) kmalloc(sizeof(struct nxt6000_state), GFP_KERNEL); + state = kmalloc(sizeof(struct nxt6000_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index df5dee7760a..cc0a77c790f 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c @@ -102,7 +102,7 @@ static u8 i2c_readbytes (struct or51132_state* state, u8 reg, u8* buf, int len) static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) { - struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; + struct or51132_state* state = fe->demodulator_priv; static u8 run_buf[] = {0x7F,0x01}; static u8 get_ver_buf[] = {0x04,0x00,0x30,0x00,0x00}; u8 rec_buf[14]; @@ -240,7 +240,7 @@ static int or51132_sleep(struct dvb_frontend* fe) static int or51132_setmode(struct dvb_frontend* fe) { - struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; + struct or51132_state* state = fe->demodulator_priv; unsigned char cmd_buf[4]; dprintk("setmode %d\n",(int)state->current_modulation); @@ -316,7 +316,7 @@ static int or51132_set_parameters(struct dvb_frontend* fe, { int ret; u8 buf[4]; - struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; + struct or51132_state* state = fe->demodulator_priv; const struct firmware *fw; /* Change only if we are actually changing the modulation */ @@ -391,7 +391,7 @@ static int or51132_set_parameters(struct dvb_frontend* fe, static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; + struct or51132_state* state = fe->demodulator_priv; unsigned char rec_buf[2]; unsigned char snd_buf[2]; *status = 0; @@ -464,7 +464,7 @@ static unsigned int i20Log10(unsigned short val) static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength) { - struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; + struct or51132_state* state = fe->demodulator_priv; unsigned char rec_buf[2]; unsigned char snd_buf[2]; u8 rcvr_stat; @@ -512,7 +512,7 @@ static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength) static int or51132_read_snr(struct dvb_frontend* fe, u16* snr) { - struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; + struct or51132_state* state = fe->demodulator_priv; unsigned char rec_buf[2]; unsigned char snd_buf[2]; u16 snr_equ; @@ -549,7 +549,7 @@ static int or51132_get_tune_settings(struct dvb_frontend* fe, struct dvb_fronten static void or51132_release(struct dvb_frontend* fe) { - struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; + struct or51132_state* state = fe->demodulator_priv; kfree(state); } diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c index 58ad34ef0a0..764a95a2e21 100644 --- a/drivers/media/dvb/frontends/sp8870.c +++ b/drivers/media/dvb/frontends/sp8870.c @@ -248,7 +248,7 @@ static int sp8870_wake_up(struct sp8870_state* state) static int sp8870_set_frontend_parameters (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; + struct sp8870_state* state = fe->demodulator_priv; int err; u16 reg0xc05; @@ -302,7 +302,7 @@ static int sp8870_set_frontend_parameters (struct dvb_frontend* fe, static int sp8870_init (struct dvb_frontend* fe) { - struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; + struct sp8870_state* state = fe->demodulator_priv; const struct firmware *fw = NULL; sp8870_wake_up(state); @@ -358,7 +358,7 @@ static int sp8870_init (struct dvb_frontend* fe) static int sp8870_read_status (struct dvb_frontend* fe, fe_status_t * fe_status) { - struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; + struct sp8870_state* state = fe->demodulator_priv; int status; int signal; @@ -384,7 +384,7 @@ static int sp8870_read_status (struct dvb_frontend* fe, fe_status_t * fe_status) static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber) { - struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; + struct sp8870_state* state = fe->demodulator_priv; int ret; u32 tmp; @@ -412,7 +412,7 @@ static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber) static int sp8870_read_signal_strength(struct dvb_frontend* fe, u16 * signal) { - struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; + struct sp8870_state* state = fe->demodulator_priv; int ret; u16 tmp; @@ -438,7 +438,7 @@ static int sp8870_read_signal_strength(struct dvb_frontend* fe, u16 * signal) static int sp8870_read_uncorrected_blocks (struct dvb_frontend* fe, u32* ublocks) { - struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; + struct sp8870_state* state = fe->demodulator_priv; int ret; *ublocks = 0; @@ -467,7 +467,7 @@ static int switches = 0; static int sp8870_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; + struct sp8870_state* state = fe->demodulator_priv; /* The firmware of the sp8870 sometimes locks up after setting frontend parameters. @@ -524,7 +524,7 @@ static int sp8870_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_par static int sp8870_sleep(struct dvb_frontend* fe) { - struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; + struct sp8870_state* state = fe->demodulator_priv; // tristate TS output and disable interface pins return sp8870_writereg(state, 0xC18, 0x000); @@ -540,7 +540,7 @@ static int sp8870_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend static void sp8870_release(struct dvb_frontend* fe) { - struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; + struct sp8870_state* state = fe->demodulator_priv; kfree(state); } @@ -552,7 +552,7 @@ struct dvb_frontend* sp8870_attach(const struct sp8870_config* config, struct sp8870_state* state = NULL; /* allocate memory for the internal state */ - state = (struct sp8870_state*) kmalloc(sizeof(struct sp8870_state), GFP_KERNEL); + state = kmalloc(sizeof(struct sp8870_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c index 7eae833ece4..d868a6927a1 100644 --- a/drivers/media/dvb/frontends/sp887x.c +++ b/drivers/media/dvb/frontends/sp887x.c @@ -135,7 +135,7 @@ static void sp887x_setup_agc (struct sp887x_state* state) */ static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware *fw) { - struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; + struct sp887x_state* state = fe->demodulator_priv; u8 buf [BLOCKSIZE+2]; int i; int fw_size = fw->size; @@ -344,7 +344,7 @@ static void sp887x_correct_offsets (struct sp887x_state* state, static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; + struct sp887x_state* state = fe->demodulator_priv; int actual_freq, err; u16 val, reg0xc05; @@ -405,7 +405,7 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe, static int sp887x_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; + struct sp887x_state* state = fe->demodulator_priv; u16 snr12 = sp887x_readreg(state, 0xf16); u16 sync0x200 = sp887x_readreg(state, 0x200); u16 sync0xf17 = sp887x_readreg(state, 0xf17); @@ -439,7 +439,7 @@ static int sp887x_read_status(struct dvb_frontend* fe, fe_status_t* status) static int sp887x_read_ber(struct dvb_frontend* fe, u32* ber) { - struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; + struct sp887x_state* state = fe->demodulator_priv; *ber = (sp887x_readreg(state, 0xc08) & 0x3f) | (sp887x_readreg(state, 0xc07) << 6); @@ -453,7 +453,7 @@ static int sp887x_read_ber(struct dvb_frontend* fe, u32* ber) static int sp887x_read_signal_strength(struct dvb_frontend* fe, u16* strength) { - struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; + struct sp887x_state* state = fe->demodulator_priv; u16 snr12 = sp887x_readreg(state, 0xf16); u32 signal = 3 * (snr12 << 4); @@ -464,7 +464,7 @@ static int sp887x_read_signal_strength(struct dvb_frontend* fe, u16* strength) static int sp887x_read_snr(struct dvb_frontend* fe, u16* snr) { - struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; + struct sp887x_state* state = fe->demodulator_priv; u16 snr12 = sp887x_readreg(state, 0xf16); *snr = (snr12 << 4) | (snr12 >> 8); @@ -474,7 +474,7 @@ static int sp887x_read_snr(struct dvb_frontend* fe, u16* snr) static int sp887x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; + struct sp887x_state* state = fe->demodulator_priv; *ucblocks = sp887x_readreg(state, 0xc0c); if (*ucblocks == 0xfff) @@ -485,7 +485,7 @@ static int sp887x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) static int sp887x_sleep(struct dvb_frontend* fe) { - struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; + struct sp887x_state* state = fe->demodulator_priv; /* tristate TS output and disable interface pins */ sp887x_writereg(state, 0xc18, 0x000); @@ -495,7 +495,7 @@ static int sp887x_sleep(struct dvb_frontend* fe) static int sp887x_init(struct dvb_frontend* fe) { - struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; + struct sp887x_state* state = fe->demodulator_priv; const struct firmware *fw = NULL; int ret; @@ -534,7 +534,7 @@ static int sp887x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend static void sp887x_release(struct dvb_frontend* fe) { - struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; + struct sp887x_state* state = fe->demodulator_priv; kfree(state); } @@ -546,7 +546,7 @@ struct dvb_frontend* sp887x_attach(const struct sp887x_config* config, struct sp887x_state* state = NULL; /* allocate memory for the internal state */ - state = (struct sp887x_state*) kmalloc(sizeof(struct sp887x_state), GFP_KERNEL); + state = kmalloc(sizeof(struct sp887x_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c index 502c6403dfc..e681263bf07 100644 --- a/drivers/media/dvb/frontends/stv0297.c +++ b/drivers/media/dvb/frontends/stv0297.c @@ -365,7 +365,7 @@ static int stv0297_set_inversion(struct stv0297_state *state, fe_spectral_invers int stv0297_enable_plli2c(struct dvb_frontend *fe) { - struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; + struct stv0297_state *state = fe->demodulator_priv; stv0297_writereg(state, 0x87, 0x78); stv0297_writereg(state, 0x86, 0xc8); @@ -375,7 +375,7 @@ int stv0297_enable_plli2c(struct dvb_frontend *fe) static int stv0297_init(struct dvb_frontend *fe) { - struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; + struct stv0297_state *state = fe->demodulator_priv; int i; /* soft reset */ @@ -416,7 +416,7 @@ static int stv0297_init(struct dvb_frontend *fe) static int stv0297_sleep(struct dvb_frontend *fe) { - struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; + struct stv0297_state *state = fe->demodulator_priv; stv0297_writereg_mask(state, 0x80, 1, 1); @@ -425,7 +425,7 @@ static int stv0297_sleep(struct dvb_frontend *fe) static int stv0297_read_status(struct dvb_frontend *fe, fe_status_t * status) { - struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; + struct stv0297_state *state = fe->demodulator_priv; u8 sync = stv0297_readreg(state, 0xDF); @@ -438,7 +438,7 @@ static int stv0297_read_status(struct dvb_frontend *fe, fe_status_t * status) static int stv0297_read_ber(struct dvb_frontend *fe, u32 * ber) { - struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; + struct stv0297_state *state = fe->demodulator_priv; u8 BER[3]; stv0297_writereg(state, 0xA0, 0x80); // Start Counting bit errors for 4096 Bytes @@ -453,7 +453,7 @@ static int stv0297_read_ber(struct dvb_frontend *fe, u32 * ber) static int stv0297_read_signal_strength(struct dvb_frontend *fe, u16 * strength) { - struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; + struct stv0297_state *state = fe->demodulator_priv; u8 STRENGTH[2]; stv0297_readregs(state, 0x41, STRENGTH, 2); @@ -464,7 +464,7 @@ static int stv0297_read_signal_strength(struct dvb_frontend *fe, u16 * strength) static int stv0297_read_snr(struct dvb_frontend *fe, u16 * snr) { - struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; + struct stv0297_state *state = fe->demodulator_priv; u8 SNR[2]; stv0297_readregs(state, 0x07, SNR, 2); @@ -475,7 +475,7 @@ static int stv0297_read_snr(struct dvb_frontend *fe, u16 * snr) static int stv0297_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks) { - struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; + struct stv0297_state *state = fe->demodulator_priv; *ucblocks = (stv0297_readreg(state, 0xD5) << 8) | stv0297_readreg(state, 0xD4); @@ -485,7 +485,7 @@ static int stv0297_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks) static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { - struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; + struct stv0297_state *state = fe->demodulator_priv; int u_threshold; int initial_u; int blind_u; @@ -689,7 +689,7 @@ timeout: static int stv0297_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { - struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; + struct stv0297_state *state = fe->demodulator_priv; int reg_00, reg_83; reg_00 = stv0297_readreg(state, 0x00); @@ -725,7 +725,7 @@ static int stv0297_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par static void stv0297_release(struct dvb_frontend *fe) { - struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; + struct stv0297_state *state = fe->demodulator_priv; kfree(state); } @@ -737,7 +737,7 @@ struct dvb_frontend *stv0297_attach(const struct stv0297_config *config, struct stv0297_state *state = NULL; /* allocate memory for the internal state */ - state = (struct stv0297_state *) kmalloc(sizeof(struct stv0297_state), GFP_KERNEL); + state = kmalloc(sizeof(struct stv0297_state), GFP_KERNEL); if (state == NULL) goto error; diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index a47cd2b32d6..cfa3928bb48 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -94,7 +94,7 @@ static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data) int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; return stv0299_writeregI(state, reg, data); } @@ -219,7 +219,7 @@ static int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout) static int stv0299_set_symbolrate (struct dvb_frontend* fe, u32 srate) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; u64 big = srate; u32 ratio; @@ -270,7 +270,7 @@ static int stv0299_get_symbolrate (struct stv0299_state* state) static int stv0299_send_diseqc_msg (struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *m) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; u8 val; int i; @@ -300,7 +300,7 @@ static int stv0299_send_diseqc_msg (struct dvb_frontend* fe, static int stv0299_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; u8 val; dprintk ("%s\n", __FUNCTION__); @@ -327,7 +327,7 @@ static int stv0299_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t static int stv0299_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; u8 val; if (stv0299_wait_diseqc_idle (state, 100) < 0) @@ -349,7 +349,7 @@ static int stv0299_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; u8 reg0x08; u8 reg0x0c; @@ -471,7 +471,7 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd) static int stv0299_init (struct dvb_frontend* fe) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; int i; dprintk("stv0299: init chip\n"); @@ -490,7 +490,7 @@ static int stv0299_init (struct dvb_frontend* fe) static int stv0299_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; u8 signal = 0xff - stv0299_readreg (state, 0x18); u8 sync = stv0299_readreg (state, 0x1b); @@ -518,7 +518,7 @@ static int stv0299_read_status(struct dvb_frontend* fe, fe_status_t* status) static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; if (state->errmode != STATUS_BER) return 0; *ber = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); @@ -528,7 +528,7 @@ static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber) static int stv0299_read_signal_strength(struct dvb_frontend* fe, u16* strength) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; s32 signal = 0xffff - ((stv0299_readreg (state, 0x18) << 8) | stv0299_readreg (state, 0x19)); @@ -545,7 +545,7 @@ static int stv0299_read_signal_strength(struct dvb_frontend* fe, u16* strength) static int stv0299_read_snr(struct dvb_frontend* fe, u16* snr) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; s32 xsnr = 0xffff - ((stv0299_readreg (state, 0x24) << 8) | stv0299_readreg (state, 0x25)); @@ -557,7 +557,7 @@ static int stv0299_read_snr(struct dvb_frontend* fe, u16* snr) static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; if (state->errmode != STATUS_UCBLOCKS) *ucblocks = 0; else *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); @@ -567,7 +567,7 @@ static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; int invval = 0; dprintk ("%s : FE_SET_FRONTEND\n", __FUNCTION__); @@ -635,7 +635,7 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par static int stv0299_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; s32 derot_freq; int invval; @@ -660,7 +660,7 @@ static int stv0299_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par static int stv0299_sleep(struct dvb_frontend* fe) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; stv0299_writeregI(state, 0x02, 0x80); state->initialised = 0; @@ -670,7 +670,7 @@ static int stv0299_sleep(struct dvb_frontend* fe) static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; fesettings->min_delay_ms = state->config->min_delay_ms; if (fesettings->parameters.u.qpsk.symbol_rate < 10000000) { @@ -685,7 +685,7 @@ static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_fronten static void stv0299_release(struct dvb_frontend* fe) { - struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + struct stv0299_state* state = fe->demodulator_priv; kfree(state); } @@ -698,7 +698,7 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, int id; /* allocate memory for the internal state */ - state = (struct stv0299_state*) kmalloc(sizeof(struct stv0299_state), GFP_KERNEL); + state = kmalloc(sizeof(struct stv0299_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c index 4e40d95ee95..87d5f4d8790 100644 --- a/drivers/media/dvb/frontends/tda10021.c +++ b/drivers/media/dvb/frontends/tda10021.c @@ -205,7 +205,7 @@ static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate static int tda10021_init (struct dvb_frontend *fe) { - struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; + struct tda10021_state* state = fe->demodulator_priv; int i; dprintk("DVB: TDA10021(%d): init chip\n", fe->adapter->num); @@ -238,7 +238,7 @@ static int tda10021_init (struct dvb_frontend *fe) static int tda10021_set_parameters (struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { - struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; + struct tda10021_state* state = fe->demodulator_priv; //table for QAM4-QAM256 ready QAM4 QAM16 QAM32 QAM64 QAM128 QAM256 //CONF @@ -278,7 +278,7 @@ static int tda10021_set_parameters (struct dvb_frontend *fe, static int tda10021_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; + struct tda10021_state* state = fe->demodulator_priv; int sync; *status = 0; @@ -303,7 +303,7 @@ static int tda10021_read_status(struct dvb_frontend* fe, fe_status_t* status) static int tda10021_read_ber(struct dvb_frontend* fe, u32* ber) { - struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; + struct tda10021_state* state = fe->demodulator_priv; u32 _ber = tda10021_readreg(state, 0x14) | (tda10021_readreg(state, 0x15) << 8) | @@ -315,7 +315,7 @@ static int tda10021_read_ber(struct dvb_frontend* fe, u32* ber) static int tda10021_read_signal_strength(struct dvb_frontend* fe, u16* strength) { - struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; + struct tda10021_state* state = fe->demodulator_priv; u8 gain = tda10021_readreg(state, 0x17); *strength = (gain << 8) | gain; @@ -325,7 +325,7 @@ static int tda10021_read_signal_strength(struct dvb_frontend* fe, u16* strength) static int tda10021_read_snr(struct dvb_frontend* fe, u16* snr) { - struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; + struct tda10021_state* state = fe->demodulator_priv; u8 quality = ~tda10021_readreg(state, 0x18); *snr = (quality << 8) | quality; @@ -335,7 +335,7 @@ static int tda10021_read_snr(struct dvb_frontend* fe, u16* snr) static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; + struct tda10021_state* state = fe->demodulator_priv; *ucblocks = tda10021_readreg (state, 0x13) & 0x7f; if (*ucblocks == 0x7f) @@ -350,7 +350,7 @@ static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; + struct tda10021_state* state = fe->demodulator_priv; int sync; s8 afc = 0; @@ -378,7 +378,7 @@ static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa static int tda10021_sleep(struct dvb_frontend* fe) { - struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; + struct tda10021_state* state = fe->demodulator_priv; tda10021_writereg (state, 0x1b, 0x02); /* pdown ADC */ tda10021_writereg (state, 0x00, 0x80); /* standby */ @@ -388,7 +388,7 @@ static int tda10021_sleep(struct dvb_frontend* fe) static void tda10021_release(struct dvb_frontend* fe) { - struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; + struct tda10021_state* state = fe->demodulator_priv; kfree(state); } @@ -401,7 +401,7 @@ struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, struct tda10021_state* state = NULL; /* allocate memory for the internal state */ - state = (struct tda10021_state*) kmalloc(sizeof(struct tda10021_state), GFP_KERNEL); + state = kmalloc(sizeof(struct tda10021_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c index da82e90d6d1..168e013d23b 100644 --- a/drivers/media/dvb/frontends/tda8083.c +++ b/drivers/media/dvb/frontends/tda8083.c @@ -226,7 +226,7 @@ static int tda8083_send_diseqc_burst (struct tda8083_state* state, fe_sec_mini_c static int tda8083_send_diseqc_msg (struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *m) { - struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + struct tda8083_state* state = fe->demodulator_priv; int i; tda8083_writereg (state, 0x29, (m->msg_len - 3) | (1 << 2)); /* enable */ @@ -243,7 +243,7 @@ static int tda8083_send_diseqc_msg (struct dvb_frontend* fe, static int tda8083_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + struct tda8083_state* state = fe->demodulator_priv; u8 signal = ~tda8083_readreg (state, 0x01); u8 sync = tda8083_readreg (state, 0x02); @@ -270,7 +270,7 @@ static int tda8083_read_status(struct dvb_frontend* fe, fe_status_t* status) static int tda8083_read_signal_strength(struct dvb_frontend* fe, u16* strength) { - struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + struct tda8083_state* state = fe->demodulator_priv; u8 signal = ~tda8083_readreg (state, 0x01); *strength = (signal << 8) | signal; @@ -280,7 +280,7 @@ static int tda8083_read_signal_strength(struct dvb_frontend* fe, u16* strength) static int tda8083_read_snr(struct dvb_frontend* fe, u16* snr) { - struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + struct tda8083_state* state = fe->demodulator_priv; u8 _snr = tda8083_readreg (state, 0x08); *snr = (_snr << 8) | _snr; @@ -290,7 +290,7 @@ static int tda8083_read_snr(struct dvb_frontend* fe, u16* snr) static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + struct tda8083_state* state = fe->demodulator_priv; state->config->pll_set(fe, p); tda8083_set_inversion (state, p->inversion); @@ -305,7 +305,7 @@ static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par static int tda8083_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + struct tda8083_state* state = fe->demodulator_priv; /* FIXME: get symbolrate & frequency offset...*/ /*p->frequency = ???;*/ @@ -319,7 +319,7 @@ static int tda8083_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par static int tda8083_sleep(struct dvb_frontend* fe) { - struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + struct tda8083_state* state = fe->demodulator_priv; tda8083_writereg (state, 0x00, 0x02); return 0; @@ -327,7 +327,7 @@ static int tda8083_sleep(struct dvb_frontend* fe) static int tda8083_init(struct dvb_frontend* fe) { - struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + struct tda8083_state* state = fe->demodulator_priv; int i; for (i=0; i<44; i++) @@ -343,7 +343,7 @@ static int tda8083_init(struct dvb_frontend* fe) static int tda8083_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) { - struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + struct tda8083_state* state = fe->demodulator_priv; tda8083_send_diseqc_burst (state, burst); tda8083_writereg (state, 0x00, 0x3c); @@ -354,7 +354,7 @@ static int tda8083_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t static int tda8083_diseqc_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) { - struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + struct tda8083_state* state = fe->demodulator_priv; tda8083_set_tone (state, tone); tda8083_writereg (state, 0x00, 0x3c); @@ -365,7 +365,7 @@ static int tda8083_diseqc_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t t static int tda8083_diseqc_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) { - struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + struct tda8083_state* state = fe->demodulator_priv; tda8083_set_voltage (state, voltage); tda8083_writereg (state, 0x00, 0x3c); @@ -376,7 +376,7 @@ static int tda8083_diseqc_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t static void tda8083_release(struct dvb_frontend* fe) { - struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + struct tda8083_state* state = fe->demodulator_priv; kfree(state); } @@ -388,7 +388,7 @@ struct dvb_frontend* tda8083_attach(const struct tda8083_config* config, struct tda8083_state* state = NULL; /* allocate memory for the internal state */ - state = (struct tda8083_state*) kmalloc(sizeof(struct tda8083_state), GFP_KERNEL); + state = kmalloc(sizeof(struct tda8083_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/tda80xx.c b/drivers/media/dvb/frontends/tda80xx.c index c9963211428..00c145521f4 100644 --- a/drivers/media/dvb/frontends/tda80xx.c +++ b/drivers/media/dvb/frontends/tda80xx.c @@ -400,7 +400,7 @@ static void tda80xx_wait_diseqc_fifo(struct tda80xx_state* state) static int tda8044_init(struct dvb_frontend* fe) { - struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + struct tda80xx_state* state = fe->demodulator_priv; int ret; /* @@ -432,7 +432,7 @@ static int tda8044_init(struct dvb_frontend* fe) static int tda8083_init(struct dvb_frontend* fe) { - struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + struct tda80xx_state* state = fe->demodulator_priv; tda80xx_write(state, 0x00, tda8083_inittab, sizeof(tda8083_inittab)); @@ -447,7 +447,7 @@ static int tda8083_init(struct dvb_frontend* fe) static int tda80xx_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) { - struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + struct tda80xx_state* state = fe->demodulator_priv; switch (voltage) { case SEC_VOLTAGE_13: @@ -463,7 +463,7 @@ static int tda80xx_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage static int tda80xx_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) { - struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + struct tda80xx_state* state = fe->demodulator_priv; switch (tone) { case SEC_TONE_OFF: @@ -477,7 +477,7 @@ static int tda80xx_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) static int tda80xx_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd) { - struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + struct tda80xx_state* state = fe->demodulator_priv; if (cmd->msg_len > 6) return -EINVAL; @@ -492,7 +492,7 @@ static int tda80xx_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma static int tda80xx_send_diseqc_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t cmd) { - struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + struct tda80xx_state* state = fe->demodulator_priv; switch (cmd) { case SEC_MINI_A: @@ -512,7 +512,7 @@ static int tda80xx_send_diseqc_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t static int tda80xx_sleep(struct dvb_frontend* fe) { - struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + struct tda80xx_state* state = fe->demodulator_priv; tda80xx_writereg(state, 0x00, 0x02); /* enter standby */ @@ -521,7 +521,7 @@ static int tda80xx_sleep(struct dvb_frontend* fe) static int tda80xx_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + struct tda80xx_state* state = fe->demodulator_priv; tda80xx_writereg(state, 0x1c, 0x80); state->config->pll_set(fe, p); @@ -537,7 +537,7 @@ static int tda80xx_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par static int tda80xx_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + struct tda80xx_state* state = fe->demodulator_priv; if (!state->config->irq) tda80xx_read_status_int(state); @@ -550,7 +550,7 @@ static int tda80xx_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par static int tda80xx_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + struct tda80xx_state* state = fe->demodulator_priv; if (!state->config->irq) tda80xx_read_status_int(state); @@ -561,7 +561,7 @@ static int tda80xx_read_status(struct dvb_frontend* fe, fe_status_t* status) static int tda80xx_read_ber(struct dvb_frontend* fe, u32* ber) { - struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + struct tda80xx_state* state = fe->demodulator_priv; int ret; u8 buf[3]; @@ -575,7 +575,7 @@ static int tda80xx_read_ber(struct dvb_frontend* fe, u32* ber) static int tda80xx_read_signal_strength(struct dvb_frontend* fe, u16* strength) { - struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + struct tda80xx_state* state = fe->demodulator_priv; u8 gain = ~tda80xx_readreg(state, 0x01); *strength = (gain << 8) | gain; @@ -585,7 +585,7 @@ static int tda80xx_read_signal_strength(struct dvb_frontend* fe, u16* strength) static int tda80xx_read_snr(struct dvb_frontend* fe, u16* snr) { - struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + struct tda80xx_state* state = fe->demodulator_priv; u8 quality = tda80xx_readreg(state, 0x08); *snr = (quality << 8) | quality; @@ -595,7 +595,7 @@ static int tda80xx_read_snr(struct dvb_frontend* fe, u16* snr) static int tda80xx_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + struct tda80xx_state* state = fe->demodulator_priv; *ucblocks = tda80xx_readreg(state, 0x0f); if (*ucblocks == 0xff) @@ -606,7 +606,7 @@ static int tda80xx_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) static int tda80xx_init(struct dvb_frontend* fe) { - struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + struct tda80xx_state* state = fe->demodulator_priv; switch(state->id) { case ID_TDA8044: @@ -620,7 +620,7 @@ static int tda80xx_init(struct dvb_frontend* fe) static void tda80xx_release(struct dvb_frontend* fe) { - struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + struct tda80xx_state* state = fe->demodulator_priv; if (state->config->irq) free_irq(state->config->irq, &state->worklet); @@ -637,7 +637,7 @@ struct dvb_frontend* tda80xx_attach(const struct tda80xx_config* config, int ret; /* allocate memory for the internal state */ - state = (struct tda80xx_state*) kmalloc(sizeof(struct tda80xx_state), GFP_KERNEL); + state = kmalloc(sizeof(struct tda80xx_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c index 9c0d23e1d9e..05dc1cdf6d5 100644 --- a/drivers/media/dvb/frontends/ves1820.c +++ b/drivers/media/dvb/frontends/ves1820.c @@ -193,7 +193,7 @@ static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate) static int ves1820_init(struct dvb_frontend* fe) { - struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; + struct ves1820_state* state = fe->demodulator_priv; int i; int val; @@ -214,7 +214,7 @@ static int ves1820_init(struct dvb_frontend* fe) static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; + struct ves1820_state* state = fe->demodulator_priv; static const u8 reg0x00[] = { 0x00, 0x04, 0x08, 0x0c, 0x10 }; static const u8 reg0x01[] = { 140, 140, 106, 100, 92 }; static const u8 reg0x05[] = { 135, 100, 70, 54, 38 }; @@ -241,7 +241,7 @@ static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_p static int ves1820_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; + struct ves1820_state* state = fe->demodulator_priv; int sync; *status = 0; @@ -267,7 +267,7 @@ static int ves1820_read_status(struct dvb_frontend* fe, fe_status_t* status) static int ves1820_read_ber(struct dvb_frontend* fe, u32* ber) { - struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; + struct ves1820_state* state = fe->demodulator_priv; u32 _ber = ves1820_readreg(state, 0x14) | (ves1820_readreg(state, 0x15) << 8) | @@ -279,7 +279,7 @@ static int ves1820_read_ber(struct dvb_frontend* fe, u32* ber) static int ves1820_read_signal_strength(struct dvb_frontend* fe, u16* strength) { - struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; + struct ves1820_state* state = fe->demodulator_priv; u8 gain = ves1820_readreg(state, 0x17); *strength = (gain << 8) | gain; @@ -289,7 +289,7 @@ static int ves1820_read_signal_strength(struct dvb_frontend* fe, u16* strength) static int ves1820_read_snr(struct dvb_frontend* fe, u16* snr) { - struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; + struct ves1820_state* state = fe->demodulator_priv; u8 quality = ~ves1820_readreg(state, 0x18); *snr = (quality << 8) | quality; @@ -299,7 +299,7 @@ static int ves1820_read_snr(struct dvb_frontend* fe, u16* snr) static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; + struct ves1820_state* state = fe->demodulator_priv; *ucblocks = ves1820_readreg(state, 0x13) & 0x7f; if (*ucblocks == 0x7f) @@ -314,7 +314,7 @@ static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; + struct ves1820_state* state = fe->demodulator_priv; int sync; s8 afc = 0; @@ -345,7 +345,7 @@ static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par static int ves1820_sleep(struct dvb_frontend* fe) { - struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; + struct ves1820_state* state = fe->demodulator_priv; ves1820_writereg(state, 0x1b, 0x02); /* pdown ADC */ ves1820_writereg(state, 0x00, 0x80); /* standby */ @@ -364,7 +364,7 @@ static int ves1820_get_tune_settings(struct dvb_frontend* fe, struct dvb_fronten static void ves1820_release(struct dvb_frontend* fe) { - struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; + struct ves1820_state* state = fe->demodulator_priv; kfree(state); } @@ -377,7 +377,7 @@ struct dvb_frontend* ves1820_attach(const struct ves1820_config* config, struct ves1820_state* state = NULL; /* allocate memory for the internal state */ - state = (struct ves1820_state*) kmalloc(sizeof(struct ves1820_state), GFP_KERNEL); + state = kmalloc(sizeof(struct ves1820_state), GFP_KERNEL); if (state == NULL) goto error; diff --git a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c index edcad283aa8..821df8e839d 100644 --- a/drivers/media/dvb/frontends/ves1x93.c +++ b/drivers/media/dvb/frontends/ves1x93.c @@ -263,7 +263,7 @@ static int ves1x93_set_symbolrate (struct ves1x93_state* state, u32 srate) static int ves1x93_init (struct dvb_frontend* fe) { - struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; + struct ves1x93_state* state = fe->demodulator_priv; int i; int val; @@ -289,7 +289,7 @@ static int ves1x93_init (struct dvb_frontend* fe) static int ves1x93_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) { - struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; + struct ves1x93_state* state = fe->demodulator_priv; switch (voltage) { case SEC_VOLTAGE_13: @@ -305,7 +305,7 @@ static int ves1x93_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag static int ves1x93_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; + struct ves1x93_state* state = fe->demodulator_priv; u8 sync = ves1x93_readreg (state, 0x0e); @@ -346,7 +346,7 @@ static int ves1x93_read_status(struct dvb_frontend* fe, fe_status_t* status) static int ves1x93_read_ber(struct dvb_frontend* fe, u32* ber) { - struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; + struct ves1x93_state* state = fe->demodulator_priv; *ber = ves1x93_readreg (state, 0x15); *ber |= (ves1x93_readreg (state, 0x16) << 8); @@ -358,7 +358,7 @@ static int ves1x93_read_ber(struct dvb_frontend* fe, u32* ber) static int ves1x93_read_signal_strength(struct dvb_frontend* fe, u16* strength) { - struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; + struct ves1x93_state* state = fe->demodulator_priv; u8 signal = ~ves1x93_readreg (state, 0x0b); *strength = (signal << 8) | signal; @@ -368,7 +368,7 @@ static int ves1x93_read_signal_strength(struct dvb_frontend* fe, u16* strength) static int ves1x93_read_snr(struct dvb_frontend* fe, u16* snr) { - struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; + struct ves1x93_state* state = fe->demodulator_priv; u8 _snr = ~ves1x93_readreg (state, 0x1c); *snr = (_snr << 8) | _snr; @@ -378,7 +378,7 @@ static int ves1x93_read_snr(struct dvb_frontend* fe, u16* snr) static int ves1x93_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; + struct ves1x93_state* state = fe->demodulator_priv; *ucblocks = ves1x93_readreg (state, 0x18) & 0x7f; @@ -393,7 +393,7 @@ static int ves1x93_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) static int ves1x93_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; + struct ves1x93_state* state = fe->demodulator_priv; ves1x93_writereg(state, 0x00, 0x11); state->config->pll_set(fe, p); @@ -408,7 +408,7 @@ static int ves1x93_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par static int ves1x93_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; + struct ves1x93_state* state = fe->demodulator_priv; int afc; afc = ((int)((char)(ves1x93_readreg (state, 0x0a) << 1)))/2; @@ -431,14 +431,14 @@ static int ves1x93_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par static int ves1x93_sleep(struct dvb_frontend* fe) { - struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; + struct ves1x93_state* state = fe->demodulator_priv; return ves1x93_writereg (state, 0x00, 0x08); } static void ves1x93_release(struct dvb_frontend* fe) { - struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; + struct ves1x93_state* state = fe->demodulator_priv; kfree(state); } @@ -451,7 +451,7 @@ struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config, u8 identity; /* allocate memory for the internal state */ - state = (struct ves1x93_state*) kmalloc(sizeof(struct ves1x93_state), GFP_KERNEL); + state = kmalloc(sizeof(struct ves1x93_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ -- cgit v1.2.3 From b1471c4f67321c09359d6fa8eb5c72c2463db081 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:32 -0700 Subject: [PATCH] dvb: dib3000: add NULL pointer check prevent NULL pointer related Oopses (Patrick Boettcher) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/dib3000mb.c | 2 +- drivers/media/dvb/frontends/dib3000mc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c index f2fbb7c1598..6f52d649e97 100644 --- a/drivers/media/dvb/frontends/dib3000mb.c +++ b/drivers/media/dvb/frontends/dib3000mb.c @@ -61,7 +61,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, fe_code_rate_t fe_cr = FEC_NONE; int search_state, seq; - if (tuner) { + if (tuner && state->config.pll_addr && state->config.pll_set) { dib3000mb_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe)); state->config.pll_set(fe, fep, NULL); dib3000mb_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe)); diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index bb0abdc78f3..888f10a5e96 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -463,7 +463,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, int search_state,auto_val; u16 val; - if (tuner) { /* initial call from dvb */ + if (tuner && state->config.pll_addr && state->config.pll_set) { /* initial call from dvb */ dib3000mc_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe)); state->config.pll_set(fe,fep,NULL); dib3000mc_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe)); -- cgit v1.2.3 From cd22d5c093faf3b123af33a8a0059f583c6b8cae Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:33 -0700 Subject: [PATCH] dvb: ves1820: remove unnecessary msleep remove unnecessary msleep(10) in writereg (Tony Glader) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/ves1820.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c index 05dc1cdf6d5..70fb44b391a 100644 --- a/drivers/media/dvb/frontends/ves1820.c +++ b/drivers/media/dvb/frontends/ves1820.c @@ -70,7 +70,6 @@ static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data) printk("ves1820: %s(): writereg error (reg == 0x%02x," "val == 0x%02x, ret == %i)\n", __FUNCTION__, reg, data, ret); - msleep(10); return (ret != 1) ? -EREMOTEIO : 0; } -- cgit v1.2.3 From 77b3bd0ccb2fae27e710b921f053ae16f34d70de Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:34 -0700 Subject: [PATCH] dvb: mt352: embed struct mt352_config in mt352_state copying the mt352_config-struct to mt352_state instead of storing just the pointer to it (Patrick Boettcher) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/mt352.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c index 50326c7248f..2d13a412ce6 100644 --- a/drivers/media/dvb/frontends/mt352.c +++ b/drivers/media/dvb/frontends/mt352.c @@ -46,7 +46,7 @@ struct mt352_state { struct dvb_frontend_ops ops; /* configuration settings */ - const struct mt352_config* config; + struct mt352_config config; }; static int debug; @@ -59,7 +59,7 @@ static int mt352_single_write(struct dvb_frontend *fe, u8 reg, u8 val) { struct mt352_state* state = fe->demodulator_priv; u8 buf[2] = { reg, val }; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, + struct i2c_msg msg = { .addr = state->config.demod_address, .flags = 0, .buf = buf, .len = 2 }; int err = i2c_transfer(state->i2c, &msg, 1); if (err != 1) { @@ -84,10 +84,10 @@ static int mt352_read_register(struct mt352_state* state, u8 reg) int ret; u8 b0 [] = { reg }; u8 b1 [] = { 0 }; - struct i2c_msg msg [] = { { .addr = state->config->demod_address, + struct i2c_msg msg [] = { { .addr = state->config.demod_address, .flags = 0, .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, + { .addr = state->config.demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; @@ -134,8 +134,8 @@ static void mt352_calc_nominal_rate(struct mt352_state* state, bw = 8; break; } - if (state->config->adc_clock) - adc_clock = state->config->adc_clock; + if (state->config.adc_clock) + adc_clock = state->config.adc_clock; value = 64 * bw * (1<<16) / (7 * 8); value = value * 1000 / adc_clock; @@ -152,10 +152,10 @@ static void mt352_calc_input_freq(struct mt352_state* state, int if2 = 36167; /* 36.166667 MHz */ int ife,value; - if (state->config->adc_clock) - adc_clock = state->config->adc_clock; - if (state->config->if2) - if2 = state->config->if2; + if (state->config.adc_clock) + adc_clock = state->config.adc_clock; + if (state->config.if2) + if2 = state->config.if2; ife = (2*adc_clock - if2); value = -16374 * ife / adc_clock; @@ -289,10 +289,10 @@ static int mt352_set_parameters(struct dvb_frontend* fe, mt352_calc_nominal_rate(state, op->bandwidth, buf+4); mt352_calc_input_freq(state, buf+6); - state->config->pll_set(fe, param, buf+8); + state->config.pll_set(fe, param, buf+8); mt352_write(fe, buf, sizeof(buf)); - if (state->config->no_tuner) { + if (state->config.no_tuner) { /* start decoding */ mt352_write(fe, fsm_go, 2); } else { @@ -516,7 +516,7 @@ static int mt352_init(struct dvb_frontend* fe) /* Do a "hard" reset */ mt352_write(fe, mt352_reset_attach, sizeof(mt352_reset_attach)); - return state->config->demod_init(fe); + return state->config.demod_init(fe); } return 0; @@ -541,8 +541,8 @@ struct dvb_frontend* mt352_attach(const struct mt352_config* config, memset(state,0,sizeof(*state)); /* setup the state */ - state->config = config; state->i2c = i2c; + memcpy(&state->config,config,sizeof(struct mt352_config)); memcpy(&state->ops, &mt352_ops, sizeof(struct dvb_frontend_ops)); /* check if the demod is there */ -- cgit v1.2.3 From dd102c752c17636b2aec7977b377c41156ed19c1 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:35 -0700 Subject: [PATCH] dvb: tda1004x: dont use bitfields use simple u8 instead of bitfields (Andreas Oberritter) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/tda1004x.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h index e452fc0bad1..196a375a16e 100644 --- a/drivers/media/dvb/frontends/tda1004x.h +++ b/drivers/media/dvb/frontends/tda1004x.h @@ -32,10 +32,10 @@ struct tda1004x_config u8 demod_address; /* does the "inversion" need inverted? */ - u8 invert:1; + u8 invert; /* Does the OCLK signal need inverted? */ - u8 invert_oclk:1; + u8 invert_oclk; /* PLL maintenance */ int (*pll_init)(struct dvb_frontend* fe); -- cgit v1.2.3 From 1dfb800f9d0391dee86d692142745415f5f65f81 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:35 -0700 Subject: [PATCH] dvb: tda1004x: allow N_I2C to be overridden by the card driver allow N_I2C to be overridden by the card driver (Andreas Oberritter) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/tda1004x.c | 4 ++-- drivers/media/dvb/frontends/tda1004x.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 6dd428b7c9e..ecfa8c7a978 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -406,7 +406,7 @@ static int tda10046_fwupload(struct dvb_frontend* fe) /* set parameters */ tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); - tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); + tda1004x_write_byteI(state, TDA10046H_CONFPLL3, state->config->n_i2c); tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c); @@ -547,7 +547,7 @@ static int tda10046_init(struct dvb_frontend* fe) tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0); // disable pulse killer tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); // PLL M = 10 - tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0 + tda1004x_write_byteI(state, TDA10046H_CONFPLL3, state->config->n_i2c); // PLL P = N = 0 tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); // FREQOFFS = 99 tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); // } PHY2 = -11221 tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c); // } diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h index 196a375a16e..c8e1d54ff26 100644 --- a/drivers/media/dvb/frontends/tda1004x.h +++ b/drivers/media/dvb/frontends/tda1004x.h @@ -37,6 +37,9 @@ struct tda1004x_config /* Does the OCLK signal need inverted? */ u8 invert_oclk; + /* value of N_I2C of the CONF_PLL3 register */ + u8 n_i2c; + /* PLL maintenance */ int (*pll_init)(struct dvb_frontend* fe); int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); -- cgit v1.2.3 From 71e3420111530273f2b26fabfac4d021c2a2b79f Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:36 -0700 Subject: [PATCH] dvb: tda10046: support for different firmware versions added support for different tda10046 firmware versions. tested with v20, v21 and v25. (Andreas Oberritter) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/dvb/get_dvb_firmware | 4 ++-- drivers/media/dvb/frontends/tda1004x.c | 36 ++++++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware index 3ffdcb39429..a750f0101d9 100644 --- a/Documentation/dvb/get_dvb_firmware +++ b/Documentation/dvb/get_dvb_firmware @@ -107,7 +107,7 @@ sub tda10045 { sub tda10046 { my $sourcefile = "tt_budget_217g.zip"; my $url = "http://www.technotrend.de/new/217g/$sourcefile"; - my $hash = "a25b579e37109af60f4a36c37893957c"; + my $hash = "6a7e1e2f2644b162ff0502367553c72d"; my $outfile = "dvb-fe-tda10046.fw"; my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); @@ -115,7 +115,7 @@ sub tda10046 { wgetfile($sourcefile, $url); unzip($sourcefile, $tmpdir); - extract("$tmpdir/software/OEM/PCI/App/ttlcdacc.dll", 0x3f731, 24479, "$tmpdir/fwtmp"); + extract("$tmpdir/software/OEM/PCI/App/ttlcdacc.dll", 0x3f731, 24478, "$tmpdir/fwtmp"); verify("$tmpdir/fwtmp", $hash); copy("$tmpdir/fwtmp", $outfile); diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index ecfa8c7a978..0beb370792a 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -49,6 +49,7 @@ struct tda1004x_state { /* private demod data */ u8 initialised; enum tda1004x_demod demod_type; + u8 fw_version; }; @@ -380,6 +381,25 @@ static int tda10045_fwupload(struct dvb_frontend* fe) return tda1004x_check_upload_ok(state, 0x2c); } +static int tda10046_get_fw_version(struct tda1004x_state *state, + const struct firmware *fw) +{ + const unsigned char pattern[] = { 0x67, 0x00, 0x50, 0x62, 0x5e, 0x18, 0x67 }; + unsigned int i; + + /* area guessed from firmware v20, v21 and v25 */ + for (i = 0x660; i < 0x700; i++) { + if (!memcmp(&fw->data[i], pattern, sizeof(pattern))) { + state->fw_version = fw->data[i + sizeof(pattern)]; + printk(KERN_INFO "tda1004x: using firmware v%02x\n", + state->fw_version); + return 0; + } + } + + return -EINVAL; +} + static int tda10046_fwupload(struct dvb_frontend* fe) { struct tda1004x_state* state = fe->demodulator_priv; @@ -393,7 +413,7 @@ static int tda10046_fwupload(struct dvb_frontend* fe) msleep(100); /* don't re-upload unless necessary */ - if (tda1004x_check_upload_ok(state, 0x20) == 0) + if (tda1004x_check_upload_ok(state, state->fw_version) == 0) return 0; /* request the firmware, this will block until someone uploads it */ @@ -404,6 +424,17 @@ static int tda10046_fwupload(struct dvb_frontend* fe) return ret; } + if (fw->size < 24478) { /* size of firmware v20, which is the smallest of v20, v21 and v25 */ + printk("tda1004x: firmware file seems to be too small (%d bytes)\n", fw->size); + return -EINVAL; + } + + ret = tda10046_get_fw_version(state, fw); + if (ret < 0) { + printk("tda1004x: unable to find firmware version\n"); + return ret; + } + /* set parameters */ tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); tda1004x_write_byteI(state, TDA10046H_CONFPLL3, state->config->n_i2c); @@ -427,7 +458,7 @@ static int tda10046_fwupload(struct dvb_frontend* fe) msleep(1); } - return tda1004x_check_upload_ok(state, 0x20); + return tda1004x_check_upload_ok(state, state->fw_version); } static int tda1004x_encode_fec(int fec) @@ -1185,6 +1216,7 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops)); state->initialised = 0; state->demod_type = TDA1004X_DEMOD_TDA10046; + state->fw_version = 0x20; /* dummy default value */ /* check if the demod is there */ if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x46) { -- cgit v1.2.3 From 5e9e7226c13135063707a0c82766a2dd748f59e5 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:37 -0700 Subject: [PATCH] dvb: dvb-pll.h: prevent multiple inclusion added missing #ifndef and #define to inhibit multiple inclusions (Patrick Boettcher) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/dvb-pll.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h index 016c794a567..c4c3c56c4a8 100644 --- a/drivers/media/dvb/frontends/dvb-pll.h +++ b/drivers/media/dvb/frontends/dvb-pll.h @@ -2,6 +2,9 @@ * $Id: dvb-pll.h,v 1.2 2005/02/10 11:43:41 kraxel Exp $ */ +#ifndef __DVB_PLL_H__ +#define __DVB_PLL_H__ + struct dvb_pll_desc { char *name; u32 min; @@ -26,9 +29,4 @@ extern struct dvb_pll_desc dvb_pll_unknown_1; int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, u32 freq, int bandwidth); -/* - * Local variables: - * c-basic-offset: 8 - * compile-command: "make DVB=1" - * End: - */ +#endif -- cgit v1.2.3 From d91b730dfb46fa889c9c7a67d8bd6596e2ac8b21 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:38 -0700 Subject: [PATCH] dvb: make needlessly global code static or drop it - make needlessly global code static - #if 0 the following unused global functions: - ttpci/av7110_hw.c: av7110_reset_arm - ttpci/av7110_hw.c: av7110_send_ci_cmd - frontends/mt352.[ch]: drop mt352_read Signed-off-by: Adrian Bunk Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/mt352.c | 12 ------------ drivers/media/dvb/frontends/mt352.h | 1 - drivers/media/dvb/ttpci/av7110.h | 1 - drivers/media/dvb/ttpci/av7110_hw.c | 12 +++++++----- drivers/media/dvb/ttpci/av7110_hw.h | 5 ----- drivers/media/dvb/ttpci/av7110_v4l.c | 2 +- drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | 2 +- drivers/media/dvb/ttusb-dec/ttusb_dec.c | 8 ++++---- 8 files changed, 13 insertions(+), 30 deletions(-) diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c index 2d13a412ce6..d32dc4de9e7 100644 --- a/drivers/media/dvb/frontends/mt352.c +++ b/drivers/media/dvb/frontends/mt352.c @@ -102,11 +102,6 @@ static int mt352_read_register(struct mt352_state* state, u8 reg) return b1[0]; } -int mt352_read(struct dvb_frontend *fe, u8 reg) -{ - return mt352_read_register(fe->demodulator_priv,reg); -} - static int mt352_sleep(struct dvb_frontend* fe) { static u8 mt352_softdown[] = { CLOCK_CTL, 0x20, 0x08 }; @@ -601,10 +596,3 @@ MODULE_LICENSE("GPL"); EXPORT_SYMBOL(mt352_attach); EXPORT_SYMBOL(mt352_write); -EXPORT_SYMBOL(mt352_read); -/* - * Local variables: - * c-basic-offset: 8 - * compile-command: "make DVB=1" - * End: - */ diff --git a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb/frontends/mt352.h index f5d8a5aed8a..8bc032f7f5c 100644 --- a/drivers/media/dvb/frontends/mt352.h +++ b/drivers/media/dvb/frontends/mt352.h @@ -61,7 +61,6 @@ extern struct dvb_frontend* mt352_attach(const struct mt352_config* config, struct i2c_adapter* i2c); extern int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen); -extern int mt352_read(struct dvb_frontend *fe, u8 reg); #endif // MT352_H diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index 5070e0523da..ee6237b926b 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -274,7 +274,6 @@ extern void av7110_ir_exit (void); extern int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val); extern u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg); extern int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val); -extern int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val); extern int av7110_init_analog_module(struct av7110 *av7110); diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index bd6e5ea4aef..7c95d63f724 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -104,7 +104,7 @@ u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count) /* av7110 ARM core boot stuff */ - +#if 0 void av7110_reset_arm(struct av7110 *av7110) { saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO); @@ -124,7 +124,7 @@ void av7110_reset_arm(struct av7110 *av7110) av7110->arm_ready = 1; dprintk(1, "reset ARM\n"); } - +#endif /* 0 */ static int waitdebi(struct av7110 *av7110, int adr, int state) { @@ -335,7 +335,7 @@ int av7110_wait_msgstate(struct av7110 *av7110, u16 flags) return 0; } -int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) +static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) { int i; unsigned long start; @@ -455,7 +455,7 @@ int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) return 0; } -int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) +static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) { int ret; @@ -500,6 +500,7 @@ int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...) return ret; } +#if 0 int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len) { int i, ret; @@ -521,6 +522,7 @@ int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len) printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret); return ret; } +#endif /* 0 */ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, int request_buf_len, u16 *reply_buf, int reply_buf_len) @@ -593,7 +595,7 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, return 0; } -int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length) +static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length) { int ret; ret = av7110_fw_request(av7110, &tag, 0, buf, length); diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h index bf901c62468..52061e17c6d 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.h +++ b/drivers/media/dvb/ttpci/av7110_hw.h @@ -364,7 +364,6 @@ enum av7110_command_type { -extern void av7110_reset_arm(struct av7110 *av7110); extern int av7110_bootarm(struct av7110 *av7110); extern int av7110_firmversion(struct av7110 *av7110); #define FW_CI_LL_SUPPORT(arm_app) ((arm_app) & 0x80000000) @@ -373,12 +372,8 @@ extern int av7110_firmversion(struct av7110 *av7110); extern int av7110_wait_msgstate(struct av7110 *av7110, u16 flags); extern int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...); -extern int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length); -extern int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length); -extern int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len); extern int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, int request_buf_len, u16 *reply_buf, int reply_buf_len); -extern int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* Buff, s16 length); /* DEBI (saa7146 data extension bus interface) access */ diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index 13aa7a42758..62c905a2d17 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -52,7 +52,7 @@ int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val) return 0; } -int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val) +static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val) { u8 msg1[3] = { dev, reg >> 8, reg & 0xff }; u8 msg2[2]; diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index 4c046ece883..dc7e81b8a2f 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -1065,7 +1065,7 @@ static int alps_tdmb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param return 0; } -struct cx22700_config alps_tdmb7_config = { +static struct cx22700_config alps_tdmb7_config = { .demod_address = 0x43, .pll_set = alps_tdmb7_pll_set, }; diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 64e771bd890..7b880aca88d 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -1565,15 +1565,15 @@ static void ttusb_dec_exit_filters(struct ttusb_dec *dec) } } -int fe_send_command(struct dvb_frontend* fe, const u8 command, - int param_length, const u8 params[], - int *result_length, u8 cmd_result[]) +static int fe_send_command(struct dvb_frontend* fe, const u8 command, + int param_length, const u8 params[], + int *result_length, u8 cmd_result[]) { struct ttusb_dec* dec = (struct ttusb_dec*) fe->dvb->priv; return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result); } -struct ttusbdecfe_config fe_config = { +static struct ttusbdecfe_config fe_config = { .send_command = fe_send_command }; -- cgit v1.2.3 From 0b3f5a57bf110b519b706365c86ada199075f34e Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:38 -0700 Subject: [PATCH] dvb: frontends: misc. minor cleanups misc. minor cleanups, select FW_LOADER and add a help text to DVB_OR51132 Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/Kconfig | 22 +++++++++++++--------- drivers/media/dvb/frontends/mt352.h | 6 ------ drivers/media/dvb/frontends/nxt2002.c | 2 -- drivers/media/dvb/frontends/tda80xx.c | 2 +- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 0bfd4df17d0..75fb556ec01 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -12,10 +12,10 @@ config DVB_STV0299 config DVB_CX24110 tristate "Conexant CX24110 based" - depends on DVB_CORE - help + depends on DVB_CORE + help A DVB-S tuner module. Say Y when you want to support this frontend. - + config DVB_TDA8083 tristate "Philips TDA8083 based" depends on DVB_CORE @@ -127,8 +127,8 @@ comment "DVB-C (cable) frontends" config DVB_ATMEL_AT76C651 tristate "Atmel AT76C651 based" depends on DVB_CORE - help - A DVB-C tuner module. Say Y when you want to support this frontend. + help + A DVB-C tuner module. Say Y when you want to support this frontend. config DVB_VES1820 tristate "VLSI VES1820 based" @@ -158,10 +158,6 @@ config DVB_NXT2002 help An ATSC 8VSB tuner module. Say Y when you want to support this frontend. -config DVB_OR51132 - tristate "OR51132 based (pcHDTV)" - depends on DVB_CORE - config DVB_OR51211 tristate "or51211 based (pcHDTV HD2000 card)" depends on DVB_CORE @@ -169,4 +165,12 @@ config DVB_OR51211 help An ATSC 8VSB tuner module. Say Y when you want to support this frontend. +config DVB_OR51132 + tristate "OR51132 based (pcHDTV HD3000 card)" + depends on DVB_CORE + select FW_LOADER + help + An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want + to support this frontend. + endmenu diff --git a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb/frontends/mt352.h index 8bc032f7f5c..03040cd595b 100644 --- a/drivers/media/dvb/frontends/mt352.h +++ b/drivers/media/dvb/frontends/mt352.h @@ -63,9 +63,3 @@ extern struct dvb_frontend* mt352_attach(const struct mt352_config* config, extern int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen); #endif // MT352_H - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/frontends/nxt2002.c b/drivers/media/dvb/frontends/nxt2002.c index 8805b0f5f61..35a1d60f192 100644 --- a/drivers/media/dvb/frontends/nxt2002.c +++ b/drivers/media/dvb/frontends/nxt2002.c @@ -343,8 +343,6 @@ static int nxt2002_setup_frontend_parameters (struct dvb_frontend* fe, /* reset the agc now that tuning has been completed */ nxt2002_agc_reset(state); - - /* set target power level */ switch (p->u.vsb.modulation) { case QAM_64: diff --git a/drivers/media/dvb/frontends/tda80xx.c b/drivers/media/dvb/frontends/tda80xx.c index 00c145521f4..032d348dafb 100644 --- a/drivers/media/dvb/frontends/tda80xx.c +++ b/drivers/media/dvb/frontends/tda80xx.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3 From fdc53a6dbfea18e621dd23ed5cfb160837d7ce52 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:39 -0700 Subject: [PATCH] dvb: modified dvb_register_adapter() to avoid kmalloc/kfree Modified dvb_register_adapter() to avoid kmalloc/kfree. Drivers have to embed struct dvb_adapter into their private data struct from now on. (Andreas Oberritter) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/b2c2/skystar2.c | 20 ++++++++-------- drivers/media/dvb/bt8xx/dvb-bt8xx.c | 20 ++++++++-------- drivers/media/dvb/bt8xx/dvb-bt8xx.h | 2 +- drivers/media/dvb/cinergyT2/cinergyT2.c | 12 +++++----- drivers/media/dvb/dibusb/dvb-dibusb-dvb.c | 10 ++++---- drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c | 4 ++-- drivers/media/dvb/dibusb/dvb-dibusb.h | 2 +- drivers/media/dvb/dvb-core/dvbdev.c | 9 +------- drivers/media/dvb/dvb-core/dvbdev.h | 2 +- drivers/media/dvb/ttpci/av7110.c | 28 +++++++++++------------ drivers/media/dvb/ttpci/av7110.h | 2 +- drivers/media/dvb/ttpci/av7110_av.c | 4 ++-- drivers/media/dvb/ttpci/av7110_ca.c | 2 +- drivers/media/dvb/ttpci/av7110_hw.c | 8 +++---- drivers/media/dvb/ttpci/av7110_v4l.c | 10 ++++---- drivers/media/dvb/ttpci/budget-av.c | 12 +++++----- drivers/media/dvb/ttpci/budget-ci.c | 6 ++--- drivers/media/dvb/ttpci/budget-core.c | 12 +++++----- drivers/media/dvb/ttpci/budget-patch.c | 4 ++-- drivers/media/dvb/ttpci/budget.c | 4 ++-- drivers/media/dvb/ttpci/budget.h | 2 +- drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | 20 ++++++++-------- drivers/media/dvb/ttusb-dec/ttusb_dec.c | 20 ++++++++-------- drivers/media/video/video-buf-dvb.c | 12 +++++----- include/media/video-buf-dvb.h | 2 +- 25 files changed, 111 insertions(+), 118 deletions(-) diff --git a/drivers/media/dvb/b2c2/skystar2.c b/drivers/media/dvb/b2c2/skystar2.c index 336c178fcd5..acbc4c34f72 100644 --- a/drivers/media/dvb/b2c2/skystar2.c +++ b/drivers/media/dvb/b2c2/skystar2.c @@ -97,7 +97,7 @@ struct adapter { u8 mac_addr[8]; u32 dw_sram_type; - struct dvb_adapter *dvb_adapter; + struct dvb_adapter dvb_adapter; struct dvb_demux demux; struct dmxdev dmxdev; struct dmx_frontend hw_frontend; @@ -2461,7 +2461,7 @@ static void frontend_init(struct adapter *skystar2) skystar2->pdev->subsystem_vendor, skystar2->pdev->subsystem_device); } else { - if (dvb_register_frontend(skystar2->dvb_adapter, skystar2->fe)) { + if (dvb_register_frontend(&skystar2->dvb_adapter, skystar2->fe)) { printk("skystar2: Frontend registration failed!\n"); if (skystar2->fe->ops->release) skystar2->fe->ops->release(skystar2->fe); @@ -2486,17 +2486,17 @@ static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret < 0) goto out; - ret = dvb_register_adapter(&dvb_adapter, skystar2_pci_driver.name, + adapter = pci_get_drvdata(pdev); + dvb_adapter = &adapter->dvb_adapter; + + ret = dvb_register_adapter(dvb_adapter, skystar2_pci_driver.name, THIS_MODULE); if (ret < 0) { printk("%s: Error registering DVB adapter\n", __FUNCTION__); goto err_halt; } - adapter = pci_get_drvdata(pdev); - dvb_adapter->priv = adapter; - adapter->dvb_adapter = dvb_adapter; init_MUTEX(&adapter->i2c_sem); @@ -2541,7 +2541,7 @@ static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->dmxdev.demux = dmx; adapter->dmxdev.capabilities = 0; - ret = dvb_dmxdev_init(&adapter->dmxdev, adapter->dvb_adapter); + ret = dvb_dmxdev_init(&adapter->dmxdev, &adapter->dvb_adapter); if (ret < 0) goto err_dmx_release; @@ -2559,7 +2559,7 @@ static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret < 0) goto err_remove_mem_frontend; - dvb_net_init(adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx); + dvb_net_init(&adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx); frontend_init(adapter); out: @@ -2576,7 +2576,7 @@ err_dmx_release: err_i2c_del: i2c_del_adapter(&adapter->i2c_adap); err_dvb_unregister: - dvb_unregister_adapter(adapter->dvb_adapter); + dvb_unregister_adapter(&adapter->dvb_adapter); err_halt: driver_halt(pdev); goto out; @@ -2605,7 +2605,7 @@ static void skystar2_remove(struct pci_dev *pdev) if (adapter->fe != NULL) dvb_unregister_frontend(adapter->fe); - dvb_unregister_adapter(adapter->dvb_adapter); + dvb_unregister_adapter(&adapter->dvb_adapter); i2c_del_adapter(&adapter->i2c_adap); diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index b735397f59a..f9572426a14 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -531,7 +531,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) card->bt->dev->subsystem_vendor, card->bt->dev->subsystem_device); } else { - if (dvb_register_frontend(card->dvb_adapter, card->fe)) { + if (dvb_register_frontend(&card->dvb_adapter, card->fe)) { printk("dvb-bt8xx: Frontend registration failed!\n"); if (card->fe->ops->release) card->fe->ops->release(card->fe); @@ -550,7 +550,7 @@ static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) return result; } - card->dvb_adapter->priv = card; + card->dvb_adapter.priv = card; card->bt->adapter = card->i2c_adapter; @@ -568,7 +568,7 @@ static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) if ((result = dvb_dmx_init(&card->demux)) < 0) { printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); - dvb_unregister_adapter(card->dvb_adapter); + dvb_unregister_adapter(&card->dvb_adapter); return result; } @@ -576,11 +576,11 @@ static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) card->dmxdev.demux = &card->demux.dmx; card->dmxdev.capabilities = 0; - if ((result = dvb_dmxdev_init(&card->dmxdev, card->dvb_adapter)) < 0) { + if ((result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter)) < 0) { printk("dvb_bt8xx: dvb_dmxdev_init failed (errno = %d)\n", result); dvb_dmx_release(&card->demux); - dvb_unregister_adapter(card->dvb_adapter); + dvb_unregister_adapter(&card->dvb_adapter); return result; } @@ -591,7 +591,7 @@ static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) dvb_dmxdev_release(&card->dmxdev); dvb_dmx_release(&card->demux); - dvb_unregister_adapter(card->dvb_adapter); + dvb_unregister_adapter(&card->dvb_adapter); return result; } @@ -603,7 +603,7 @@ static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); dvb_dmxdev_release(&card->dmxdev); dvb_dmx_release(&card->demux); - dvb_unregister_adapter(card->dvb_adapter); + dvb_unregister_adapter(&card->dvb_adapter); return result; } @@ -614,11 +614,11 @@ static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); dvb_dmxdev_release(&card->dmxdev); dvb_dmx_release(&card->demux); - dvb_unregister_adapter(card->dvb_adapter); + dvb_unregister_adapter(&card->dvb_adapter); return result; } - dvb_net_init(card->dvb_adapter, &card->dvbnet, &card->demux.dmx); + dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx); tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card); @@ -759,7 +759,7 @@ static int dvb_bt8xx_remove(struct device *dev) dvb_dmxdev_release(&card->dmxdev); dvb_dmx_release(&card->demux); if (card->fe) dvb_unregister_frontend(card->fe); - dvb_unregister_adapter(card->dvb_adapter); + dvb_unregister_adapter(&card->dvb_adapter); kfree(card); diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h index 80ef189f930..e9310e3a17a 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h @@ -40,7 +40,7 @@ struct dvb_bt8xx_card { struct semaphore lock; int nfeeds; char card_name[32]; - struct dvb_adapter *dvb_adapter; + struct dvb_adapter dvb_adapter; struct bt878 *bt; unsigned int bttv_nr; struct dvb_demux demux; diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 28d4d926de3..96c57fde95a 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -119,7 +119,7 @@ struct cinergyt2 { struct dvb_demux demux; struct usb_device *udev; struct semaphore sem; - struct dvb_adapter *adapter; + struct dvb_adapter adapter; struct dvb_device *fedev; struct dmxdev dmxdev; struct dvb_net dvbnet; @@ -813,15 +813,15 @@ static int cinergyt2_probe (struct usb_interface *intf, cinergyt2->dmxdev.demux = &cinergyt2->demux.dmx; cinergyt2->dmxdev.capabilities = 0; - if ((err = dvb_dmxdev_init(&cinergyt2->dmxdev, cinergyt2->adapter)) < 0) { + if ((err = dvb_dmxdev_init(&cinergyt2->dmxdev, &cinergyt2->adapter)) < 0) { dprintk(1, "dvb_dmxdev_init() failed (err = %d)\n", err); goto bailout; } - if (dvb_net_init(cinergyt2->adapter, &cinergyt2->dvbnet, &cinergyt2->demux.dmx)) + if (dvb_net_init(&cinergyt2->adapter, &cinergyt2->dvbnet, &cinergyt2->demux.dmx)) dprintk(1, "dvb_net_init() failed!\n"); - dvb_register_device(cinergyt2->adapter, &cinergyt2->fedev, + dvb_register_device(&cinergyt2->adapter, &cinergyt2->fedev, &cinergyt2_fe_template, cinergyt2, DVB_DEVICE_FRONTEND); @@ -848,7 +848,7 @@ static int cinergyt2_probe (struct usb_interface *intf, bailout: dvb_dmxdev_release(&cinergyt2->dmxdev); dvb_dmx_release(&cinergyt2->demux); - dvb_unregister_adapter (cinergyt2->adapter); + dvb_unregister_adapter (&cinergyt2->adapter); cinergyt2_free_stream_urbs (cinergyt2); kfree(cinergyt2); return -ENOMEM; @@ -872,7 +872,7 @@ static void cinergyt2_disconnect (struct usb_interface *intf) dvb_dmxdev_release(&cinergyt2->dmxdev); dvb_dmx_release(&cinergyt2->demux); dvb_unregister_device(cinergyt2->fedev); - dvb_unregister_adapter(cinergyt2->adapter); + dvb_unregister_adapter(&cinergyt2->adapter); cinergyt2_free_stream_urbs(cinergyt2); up(&cinergyt2->sem); diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c b/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c index 04e54ec093f..400b439e804 100644 --- a/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c +++ b/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c @@ -131,7 +131,7 @@ int dibusb_dvb_init(struct usb_dibusb *dib) deb_info("dvb_register_adapter failed: error %d", ret); goto err; } - dib->adapter->priv = dib; + dib->adapter.priv = dib; /* i2c is done in dibusb_i2c_init */ @@ -151,18 +151,18 @@ int dibusb_dvb_init(struct usb_dibusb *dib) dib->dmxdev.filternum = dib->demux.filternum; dib->dmxdev.demux = &dib->demux.dmx; dib->dmxdev.capabilities = 0; - if ((ret = dvb_dmxdev_init(&dib->dmxdev, dib->adapter)) < 0) { + if ((ret = dvb_dmxdev_init(&dib->dmxdev, &dib->adapter)) < 0) { err("dvb_dmxdev_init failed: error %d",ret); goto err_dmx_dev; } - dvb_net_init(dib->adapter, &dib->dvb_net, &dib->demux.dmx); + dvb_net_init(&dib->adapter, &dib->dvb_net, &dib->demux.dmx); goto success; err_dmx_dev: dvb_dmx_release(&dib->demux); err_dmx: - dvb_unregister_adapter(dib->adapter); + dvb_unregister_adapter(&dib->adapter); err: return ret; success: @@ -179,7 +179,7 @@ int dibusb_dvb_exit(struct usb_dibusb *dib) dib->demux.dmx.close(&dib->demux.dmx); dvb_dmxdev_release(&dib->dmxdev); dvb_dmx_release(&dib->demux); - dvb_unregister_adapter(dib->adapter); + dvb_unregister_adapter(&dib->adapter); } return 0; } diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c b/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c index 2ed89488c7c..5a71b88797d 100644 --- a/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c +++ b/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c @@ -183,7 +183,7 @@ int dibusb_fe_init(struct usb_dibusb* dib) dib->dibdev->name); return -ENODEV; } else { - if (dvb_register_frontend(dib->adapter, dib->fe)) { + if (dvb_register_frontend(&dib->adapter, dib->fe)) { err("Frontend registration failed."); if (dib->fe->ops->release) dib->fe->ops->release(dib->fe); @@ -206,7 +206,7 @@ int dibusb_i2c_init(struct usb_dibusb *dib) { int ret = 0; - dib->adapter->priv = dib; + dib->adapter.priv = dib; strncpy(dib->i2c_adap.name,dib->dibdev->name,I2C_NAME_SIZE); #ifdef I2C_ADAP_CLASS_TV_DIGITAL diff --git a/drivers/media/dvb/dibusb/dvb-dibusb.h b/drivers/media/dvb/dibusb/dvb-dibusb.h index 52cd35dd9d8..c965b64fb1a 100644 --- a/drivers/media/dvb/dibusb/dvb-dibusb.h +++ b/drivers/media/dvb/dibusb/dvb-dibusb.h @@ -181,7 +181,7 @@ struct usb_dibusb { struct semaphore i2c_sem; /* dvb */ - struct dvb_adapter *adapter; + struct dvb_adapter adapter; struct dmxdev dmxdev; struct dvb_demux demux; struct dvb_net dvb_net; diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index cf4ffe38fda..9d9662f4b8e 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -286,9 +286,8 @@ skip: } -int dvb_register_adapter(struct dvb_adapter **padap, const char *name, struct module *module) +int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module) { - struct dvb_adapter *adap; int num; if (down_interruptible (&dvbdev_register_lock)) @@ -299,11 +298,6 @@ int dvb_register_adapter(struct dvb_adapter **padap, const char *name, struct mo return -ENFILE; } - if (!(*padap = adap = kmalloc(sizeof(struct dvb_adapter), GFP_KERNEL))) { - up(&dvbdev_register_lock); - return -ENOMEM; - } - memset (adap, 0, sizeof(struct dvb_adapter)); INIT_LIST_HEAD (&adap->device_list); @@ -331,7 +325,6 @@ int dvb_unregister_adapter(struct dvb_adapter *adap) return -ERESTARTSYS; list_del (&adap->list_head); up (&dvbdev_register_lock); - kfree (adap); return 0; } EXPORT_SYMBOL(dvb_unregister_adapter); diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h index 184edba3caa..a251867f30f 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.h +++ b/drivers/media/dvb/dvb-core/dvbdev.h @@ -76,7 +76,7 @@ struct dvb_device { }; -extern int dvb_register_adapter (struct dvb_adapter **padap, const char *name, struct module *module); +extern int dvb_register_adapter (struct dvb_adapter *adap, const char *name, struct module *module); extern int dvb_unregister_adapter (struct dvb_adapter *adap); extern int dvb_register_device (struct dvb_adapter *adap, diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index e3f7bd68591..8e33a850e13 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -130,7 +130,7 @@ static void init_av7110_av(struct av7110 *av7110) av7110->current_input = 0; if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) { printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n", - av7110->dvb_adapter->num); + av7110->dvb_adapter.num); av7110->adac_type = DVB_ADAC_CRYSTAL; i2c_writereg(av7110, 0x20, 0x01, 0xd2); i2c_writereg(av7110, 0x20, 0x02, 0x49); @@ -145,13 +145,13 @@ static void init_av7110_av(struct av7110 *av7110) } else if (dev->pci->subsystem_vendor == 0x110a) { printk("dvb-ttpci: DVB-C w/o analog module @ card %d detected\n", - av7110->dvb_adapter->num); + av7110->dvb_adapter.num); av7110->adac_type = DVB_ADAC_NONE; } else { av7110->adac_type = adac; printk("dvb-ttpci: adac type set to %d @ card %d\n", - av7110->dvb_adapter->num, av7110->adac_type); + av7110->dvb_adapter.num, av7110->adac_type); } if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP) { @@ -231,7 +231,7 @@ static int arm_thread(void *data) if (newloops == av7110->arm_loops) { printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n", - av7110->dvb_adapter->num); + av7110->dvb_adapter.num); arm_error(av7110); av7710_set_video_mode(av7110, vidmode); @@ -1282,7 +1282,7 @@ static int av7110_register(struct av7110 *av7110) av7110->dmxdev.demux = &dvbdemux->dmx; av7110->dmxdev.capabilities = 0; - dvb_dmxdev_init(&av7110->dmxdev, av7110->dvb_adapter); + dvb_dmxdev_init(&av7110->dmxdev, &av7110->dvb_adapter); av7110->hw_frontend.source = DMX_FRONTEND_0; @@ -1307,11 +1307,11 @@ static int av7110_register(struct av7110 *av7110) av7110_ca_register(av7110); #ifdef CONFIG_DVB_AV7110_OSD - dvb_register_device(av7110->dvb_adapter, &av7110->osd_dev, + dvb_register_device(&av7110->dvb_adapter, &av7110->osd_dev, &dvbdev_osd, av7110, DVB_DEVICE_OSD); #endif - dvb_net_init(av7110->dvb_adapter, &av7110->dvb_net, &dvbdemux->dmx); + dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net, &dvbdemux->dmx); if (budgetpatch) { /* initialize software demux1 without its own frontend @@ -1334,9 +1334,9 @@ static int av7110_register(struct av7110 *av7110) av7110->dmxdev1.demux = &dvbdemux1->dmx; av7110->dmxdev1.capabilities = 0; - dvb_dmxdev_init(&av7110->dmxdev1, av7110->dvb_adapter); + dvb_dmxdev_init(&av7110->dmxdev1, &av7110->dvb_adapter); - dvb_net_init(av7110->dvb_adapter, &av7110->dvb_net1, &dvbdemux1->dmx); + dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net1, &dvbdemux1->dmx); printk("dvb-ttpci: additional demux1 for budget-patch registered\n"); } return 0; @@ -2246,7 +2246,7 @@ static int frontend_init(struct av7110 *av7110) FE_FUNC_OVERRIDE(av7110->fe->ops->dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command); FE_FUNC_OVERRIDE(av7110->fe->ops->set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend); - ret = dvb_register_frontend(av7110->dvb_adapter, av7110->fe); + ret = dvb_register_frontend(&av7110->dvb_adapter, av7110->fe); if (ret < 0) { printk("av7110: Frontend registration failed!\n"); if (av7110->fe->ops->release) @@ -2460,7 +2460,7 @@ static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_d goto err_dvb_unregister_adapter_2; ttpci_eeprom_parse_mac(&av7110->i2c_adap, - av7110->dvb_adapter->proposed_mac); + av7110->dvb_adapter.proposed_mac); ret = -ENOMEM; if (budgetpatch) { @@ -2631,7 +2631,7 @@ static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_d if (ret < 0) goto err_av7110_unregister_11; - av7110->dvb_adapter->priv = av7110; + av7110->dvb_adapter.priv = av7110; ret = frontend_init(av7110); if (ret < 0) goto err_av7110_exit_v4l_12; @@ -2666,7 +2666,7 @@ err_saa71466_vfree_4: err_i2c_del_3: i2c_del_adapter(&av7110->i2c_adap); err_dvb_unregister_adapter_2: - dvb_unregister_adapter(av7110->dvb_adapter); + dvb_unregister_adapter(&av7110->dvb_adapter); err_put_firmware_1: put_firmware(av7110); err_kfree_0: @@ -2712,7 +2712,7 @@ static int av7110_detach(struct saa7146_dev* saa) i2c_del_adapter(&av7110->i2c_adap); - dvb_unregister_adapter (av7110->dvb_adapter); + dvb_unregister_adapter (&av7110->dvb_adapter); av7110_num--; diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index ee6237b926b..4f69b4d0147 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -220,7 +220,7 @@ struct av7110 { struct audio_mixer mixer; - struct dvb_adapter *dvb_adapter; + struct dvb_adapter dvb_adapter; struct dvb_device *video_dev; struct dvb_device *audio_dev; struct dvb_device *ca_dev; diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index f90e1cf2419..ccf946125d0 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -1415,10 +1415,10 @@ int av7110_av_register(struct av7110 *av7110) av7110->video_events.overflow = 0; memset(&av7110->video_size, 0, sizeof (video_size_t)); - dvb_register_device(av7110->dvb_adapter, &av7110->video_dev, + dvb_register_device(&av7110->dvb_adapter, &av7110->video_dev, &dvbdev_video, av7110, DVB_DEVICE_VIDEO); - dvb_register_device(av7110->dvb_adapter, &av7110->audio_dev, + dvb_register_device(&av7110->dvb_adapter, &av7110->audio_dev, &dvbdev_audio, av7110, DVB_DEVICE_AUDIO); return 0; diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c index 75173a22f5c..c3801e328fe 100644 --- a/drivers/media/dvb/ttpci/av7110_ca.c +++ b/drivers/media/dvb/ttpci/av7110_ca.c @@ -370,7 +370,7 @@ static struct dvb_device dvbdev_ca = { int av7110_ca_register(struct av7110 *av7110) { - return dvb_register_device(av7110->dvb_adapter, &av7110->ca_dev, + return dvb_register_device(&av7110->dvb_adapter, &av7110->ca_dev, &dvbdev_ca, av7110, DVB_DEVICE_CA); } diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index 7c95d63f724..7fa4a0ebe13 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -619,7 +619,7 @@ int av7110_firmversion(struct av7110 *av7110) if (av7110_fw_query(av7110, tag, buf, 16)) { printk("dvb-ttpci: failed to boot firmware @ card %d\n", - av7110->dvb_adapter->num); + av7110->dvb_adapter.num); return -EIO; } @@ -630,16 +630,16 @@ int av7110_firmversion(struct av7110 *av7110) av7110->avtype = (buf[8] << 16) + buf[9]; printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n", - av7110->dvb_adapter->num, av7110->arm_fw, + av7110->dvb_adapter.num, av7110->arm_fw, av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app); /* print firmware capabilities */ if (FW_CI_LL_SUPPORT(av7110->arm_app)) printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n", - av7110->dvb_adapter->num); + av7110->dvb_adapter.num); else printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n", - av7110->dvb_adapter->num); + av7110->dvb_adapter.num); return 0; } diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index 62c905a2d17..e65fc36e2ce 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -46,7 +46,7 @@ int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val) if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) { dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n", - av7110->dvb_adapter->num, reg, val); + av7110->dvb_adapter.num, reg, val); return -EIO; } return 0; @@ -63,7 +63,7 @@ static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val) if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) { dprintk(1, "dvb-ttpci: failed @ card %d, %u\n", - av7110->dvb_adapter->num, reg); + av7110->dvb_adapter.num, reg); return -EIO; } *val = (msg2[0] << 8) | msg2[1]; @@ -552,13 +552,13 @@ int av7110_init_analog_module(struct av7110 *av7110) return -ENODEV; printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n", - av7110->dvb_adapter->num); + av7110->dvb_adapter.num); av7110->adac_type = DVB_ADAC_MSP; msleep(100); // the probing above resets the msp... msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1); msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2); dprintk(1, "dvb-ttpci: @ card %d MSP3400 version 0x%04x 0x%04x\n", - av7110->dvb_adapter->num, version1, version2); + av7110->dvb_adapter.num, version1, version2); msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00); msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source @@ -596,7 +596,7 @@ int av7110_init_analog_module(struct av7110 *av7110) /* init the saa7113 */ while (*i != 0xff) { if (i2c_writereg(av7110, 0x48, i[0], i[1]) != 1) { - dprintk(1, "saa7113 initialization failed @ card %d", av7110->dvb_adapter->num); + dprintk(1, "saa7113 initialization failed @ card %d", av7110->dvb_adapter.num); break; } i += 2; diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 9860caf3249..7891f3f06f0 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -297,7 +297,7 @@ static int ciintf_init(struct budget_av *budget_av) budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable; budget_av->ca.poll_slot_status = ciintf_poll_slot_status; budget_av->ca.data = budget_av; - if ((result = dvb_ca_en50221_init(budget_av->budget.dvb_adapter, + if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter, &budget_av->ca, 0, 1)) != 0) { printk("budget_av: CI interface detected, but initialisation failed.\n"); goto error; @@ -767,7 +767,7 @@ static void frontend_init(struct budget_av *budget_av) budget_av->budget.dev->pci->subsystem_device); } else { if (dvb_register_frontend - (budget_av->budget.dvb_adapter, budget_av->budget.dvb_frontend)) { + (&budget_av->budget.dvb_adapter, budget_av->budget.dvb_frontend)) { printk("budget-av: Frontend registration failed!\n"); if (budget_av->budget.dvb_frontend->ops->release) budget_av->budget.dvb_frontend->ops->release(budget_av->budget.dvb_frontend); @@ -875,18 +875,18 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio /* fixme: find some sane values here... */ saa7146_write(dev, PCI_BT_V1, 0x1c00101f); - mac = budget_av->budget.dvb_adapter->proposed_mac; + mac = budget_av->budget.dvb_adapter.proposed_mac; if (i2c_readregs(&budget_av->budget.i2c_adap, 0xa0, 0x30, mac, 6)) { printk("KNC1-%d: Could not read MAC from KNC1 card\n", - budget_av->budget.dvb_adapter->num); + budget_av->budget.dvb_adapter.num); memset(mac, 0, 6); } else { printk("KNC1-%d: MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", - budget_av->budget.dvb_adapter->num, + budget_av->budget.dvb_adapter.num, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } - budget_av->budget.dvb_adapter->priv = budget_av; + budget_av->budget.dvb_adapter.priv = budget_av; frontend_init(budget_av); if (enable_ci) diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 521111be355..dce11611137 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -395,7 +395,7 @@ static int ciintf_init(struct budget_ci *budget_ci) budget_ci->ca.slot_shutdown = ciintf_slot_shutdown; budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable; budget_ci->ca.data = budget_ci; - if ((result = dvb_ca_en50221_init(budget_ci->budget.dvb_adapter, + if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter, &budget_ci->ca, DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE | DVB_CA_EN50221_FLAG_IRQ_FR | @@ -881,7 +881,7 @@ static void frontend_init(struct budget_ci *budget_ci) budget_ci->budget.dev->pci->subsystem_device); } else { if (dvb_register_frontend - (budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) { + (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) { printk("budget-ci: Frontend registration failed!\n"); if (budget_ci->budget.dvb_frontend->ops->release) budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend); @@ -916,7 +916,7 @@ static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio ciintf_init(budget_ci); - budget_ci->budget.dvb_adapter->priv = budget_ci; + budget_ci->budget.dvb_adapter.priv = budget_ci; frontend_init(budget_ci); return 0; diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c index 93a9b40917e..0498a055a4c 100644 --- a/drivers/media/dvb/ttpci/budget-core.c +++ b/drivers/media/dvb/ttpci/budget-core.c @@ -298,7 +298,7 @@ static int budget_register(struct budget *budget) budget->dmxdev.demux = &dvbdemux->dmx; budget->dmxdev.capabilities = 0; - dvb_dmxdev_init(&budget->dmxdev, budget->dvb_adapter); + dvb_dmxdev_init(&budget->dmxdev, &budget->dvb_adapter); budget->hw_frontend.source = DMX_FRONTEND_0; @@ -316,7 +316,7 @@ static int budget_register(struct budget *budget) if (ret < 0) return ret; - dvb_net_init(budget->dvb_adapter, &budget->dvb_net, &dvbdemux->dmx); + dvb_net_init(&budget->dvb_adapter, &budget->dvb_net, &dvbdemux->dmx); return 0; } @@ -385,11 +385,11 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, strcpy(budget->i2c_adap.name, budget->card->name); if (i2c_add_adapter(&budget->i2c_adap) < 0) { - dvb_unregister_adapter(budget->dvb_adapter); + dvb_unregister_adapter(&budget->dvb_adapter); return -ENOMEM; } - ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter->proposed_mac); + ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter.proposed_mac); if (NULL == (budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, length, &budget->pt))) { @@ -417,7 +417,7 @@ err: vfree(budget->grabbing); - dvb_unregister_adapter(budget->dvb_adapter); + dvb_unregister_adapter(&budget->dvb_adapter); return ret; } @@ -432,7 +432,7 @@ int ttpci_budget_deinit(struct budget *budget) i2c_del_adapter(&budget->i2c_adap); - dvb_unregister_adapter(budget->dvb_adapter); + dvb_unregister_adapter(&budget->dvb_adapter); tasklet_kill(&budget->vpe_tasklet); diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c index 5d524a4f213..8142e26b47f 100644 --- a/drivers/media/dvb/ttpci/budget-patch.c +++ b/drivers/media/dvb/ttpci/budget-patch.c @@ -453,7 +453,7 @@ static void frontend_init(struct budget_patch* budget) budget->dev->pci->subsystem_vendor, budget->dev->pci->subsystem_device); } else { - if (dvb_register_frontend(budget->dvb_adapter, budget->dvb_frontend)) { + if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) { printk("budget-av: Frontend registration failed!\n"); if (budget->dvb_frontend->ops->release) budget->dvb_frontend->ops->release(budget->dvb_frontend); @@ -702,7 +702,7 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte dev->ext_priv = budget; - budget->dvb_adapter->priv = budget; + budget->dvb_adapter.priv = budget; frontend_init(budget); return 0; diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index 5e6a10f4ad9..083fd44e5f9 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -468,7 +468,7 @@ static void frontend_init(struct budget *budget) budget->dev->pci->subsystem_vendor, budget->dev->pci->subsystem_device); } else { - if (dvb_register_frontend(budget->dvb_adapter, budget->dvb_frontend)) { + if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) { printk("budget: Frontend registration failed!\n"); if (budget->dvb_frontend->ops->release) budget->dvb_frontend->ops->release(budget->dvb_frontend); @@ -497,7 +497,7 @@ static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_ return err; } - budget->dvb_adapter->priv = budget; + budget->dvb_adapter.priv = budget; frontend_init(budget); return 0; diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h index 6d82a6f4e43..c6ef496ba70 100644 --- a/drivers/media/dvb/ttpci/budget.h +++ b/drivers/media/dvb/ttpci/budget.h @@ -64,7 +64,7 @@ struct budget { spinlock_t debilock; - struct dvb_adapter *dvb_adapter; + struct dvb_adapter dvb_adapter; struct dvb_frontend *dvb_frontend; void *priv; }; diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index dc7e81b8a2f..afa0e7a0e50 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -84,7 +84,7 @@ struct ttusb { struct semaphore semi2c; struct semaphore semusb; - struct dvb_adapter *adapter; + struct dvb_adapter adapter; struct usb_device *dev; struct i2c_adapter i2c_adap; @@ -1412,7 +1412,7 @@ static void frontend_init(struct ttusb* ttusb) le16_to_cpu(ttusb->dev->descriptor.idVendor), le16_to_cpu(ttusb->dev->descriptor.idProduct)); } else { - if (dvb_register_frontend(ttusb->adapter, ttusb->fe)) { + if (dvb_register_frontend(&ttusb->adapter, ttusb->fe)) { printk("dvb-ttusb-budget: Frontend registration failed!\n"); if (ttusb->fe->ops->release) ttusb->fe->ops->release(ttusb->fe); @@ -1462,7 +1462,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i up(&ttusb->semi2c); dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE); - ttusb->adapter->priv = ttusb; + ttusb->adapter.priv = ttusb; /* i2c */ memset(&ttusb->i2c_adap, 0, sizeof(struct i2c_adapter)); @@ -1481,7 +1481,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i result = i2c_add_adapter(&ttusb->i2c_adap); if (result) { - dvb_unregister_adapter (ttusb->adapter); + dvb_unregister_adapter (&ttusb->adapter); return result; } @@ -1503,7 +1503,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i if ((result = dvb_dmx_init(&ttusb->dvb_demux)) < 0) { printk("ttusb_dvb: dvb_dmx_init failed (errno = %d)\n", result); i2c_del_adapter(&ttusb->i2c_adap); - dvb_unregister_adapter (ttusb->adapter); + dvb_unregister_adapter (&ttusb->adapter); return -ENODEV; } //FIXME dmxdev (nur WAS?) @@ -1511,21 +1511,21 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i ttusb->dmxdev.demux = &ttusb->dvb_demux.dmx; ttusb->dmxdev.capabilities = 0; - if ((result = dvb_dmxdev_init(&ttusb->dmxdev, ttusb->adapter)) < 0) { + if ((result = dvb_dmxdev_init(&ttusb->dmxdev, &ttusb->adapter)) < 0) { printk("ttusb_dvb: dvb_dmxdev_init failed (errno = %d)\n", result); dvb_dmx_release(&ttusb->dvb_demux); i2c_del_adapter(&ttusb->i2c_adap); - dvb_unregister_adapter (ttusb->adapter); + dvb_unregister_adapter (&ttusb->adapter); return -ENODEV; } - if (dvb_net_init(ttusb->adapter, &ttusb->dvbnet, &ttusb->dvb_demux.dmx)) { + if (dvb_net_init(&ttusb->adapter, &ttusb->dvbnet, &ttusb->dvb_demux.dmx)) { printk("ttusb_dvb: dvb_net_init failed!\n"); dvb_dmxdev_release(&ttusb->dmxdev); dvb_dmx_release(&ttusb->dvb_demux); i2c_del_adapter(&ttusb->i2c_adap); - dvb_unregister_adapter (ttusb->adapter); + dvb_unregister_adapter (&ttusb->adapter); return -ENODEV; } @@ -1559,7 +1559,7 @@ static void ttusb_disconnect(struct usb_interface *intf) dvb_dmx_release(&ttusb->dvb_demux); if (ttusb->fe != NULL) dvb_unregister_frontend(ttusb->fe); i2c_del_adapter(&ttusb->i2c_adap); - dvb_unregister_adapter(ttusb->adapter); + dvb_unregister_adapter(&ttusb->adapter); ttusb_free_iso_urbs(ttusb); diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 7b880aca88d..505bdaff5a7 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -98,7 +98,7 @@ struct ttusb_dec { int can_playback; /* DVB bits */ - struct dvb_adapter *adapter; + struct dvb_adapter adapter; struct dmxdev dmxdev; struct dvb_demux demux; struct dmx_frontend frontend; @@ -1435,7 +1435,7 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec) printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__, result); - dvb_unregister_adapter(dec->adapter); + dvb_unregister_adapter(&dec->adapter); return result; } @@ -1444,12 +1444,12 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec) dec->dmxdev.demux = &dec->demux.dmx; dec->dmxdev.capabilities = 0; - if ((result = dvb_dmxdev_init(&dec->dmxdev, dec->adapter)) < 0) { + if ((result = dvb_dmxdev_init(&dec->dmxdev, &dec->adapter)) < 0) { printk("%s: dvb_dmxdev_init failed: error %d\n", __FUNCTION__, result); dvb_dmx_release(&dec->demux); - dvb_unregister_adapter(dec->adapter); + dvb_unregister_adapter(&dec->adapter); return result; } @@ -1463,7 +1463,7 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec) dvb_dmxdev_release(&dec->dmxdev); dvb_dmx_release(&dec->demux); - dvb_unregister_adapter(dec->adapter); + dvb_unregister_adapter(&dec->adapter); return result; } @@ -1476,12 +1476,12 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec) dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); dvb_dmxdev_release(&dec->dmxdev); dvb_dmx_release(&dec->demux); - dvb_unregister_adapter(dec->adapter); + dvb_unregister_adapter(&dec->adapter); return result; } - dvb_net_init(dec->adapter, &dec->dvb_net, &dec->demux.dmx); + dvb_net_init(&dec->adapter, &dec->dvb_net, &dec->demux.dmx); return 0; } @@ -1496,7 +1496,7 @@ static void ttusb_dec_exit_dvb(struct ttusb_dec *dec) dvb_dmxdev_release(&dec->dmxdev); dvb_dmx_release(&dec->demux); if (dec->fe) dvb_unregister_frontend(dec->fe); - dvb_unregister_adapter(dec->adapter); + dvb_unregister_adapter(&dec->adapter); } static void ttusb_dec_exit_rc(struct ttusb_dec *dec) @@ -1620,7 +1620,7 @@ static int ttusb_dec_probe(struct usb_interface *intf, } ttusb_dec_init_dvb(dec); - dec->adapter->priv = dec; + dec->adapter.priv = dec; switch (le16_to_cpu(id->idProduct)) { case 0x1006: dec->fe = ttusbdecfe_dvbs_attach(&fe_config); @@ -1637,7 +1637,7 @@ static int ttusb_dec_probe(struct usb_interface *intf, le16_to_cpu(dec->udev->descriptor.idVendor), le16_to_cpu(dec->udev->descriptor.idProduct)); } else { - if (dvb_register_frontend(dec->adapter, dec->fe)) { + if (dvb_register_frontend(&dec->adapter, dec->fe)) { printk("budget-ci: Frontend registration failed!\n"); if (dec->fe->ops->release) dec->fe->ops->release(dec->fe); diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c index 31cc4ed9b74..5f870075b55 100644 --- a/drivers/media/video/video-buf-dvb.c +++ b/drivers/media/video/video-buf-dvb.c @@ -149,10 +149,10 @@ int videobuf_dvb_register(struct videobuf_dvb *dvb, dvb->name, result); goto fail_adapter; } - dvb->adapter->priv = adapter_priv; + dvb->adapter.priv = adapter_priv; /* register frontend */ - result = dvb_register_frontend(dvb->adapter, dvb->frontend); + result = dvb_register_frontend(&dvb->adapter, dvb->frontend); if (result < 0) { printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n", dvb->name, result); @@ -178,7 +178,7 @@ int videobuf_dvb_register(struct videobuf_dvb *dvb, dvb->dmxdev.filternum = 256; dvb->dmxdev.demux = &dvb->demux.dmx; dvb->dmxdev.capabilities = 0; - result = dvb_dmxdev_init(&dvb->dmxdev, dvb->adapter); + result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); if (result < 0) { printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n", dvb->name, result); @@ -209,7 +209,7 @@ int videobuf_dvb_register(struct videobuf_dvb *dvb, } /* register network adapter */ - dvb_net_init(dvb->adapter, &dvb->net, &dvb->demux.dmx); + dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); return 0; fail_fe_conn: @@ -223,7 +223,7 @@ fail_dmxdev: fail_dmx: dvb_unregister_frontend(dvb->frontend); fail_frontend: - dvb_unregister_adapter(dvb->adapter); + dvb_unregister_adapter(&dvb->adapter); fail_adapter: return result; } @@ -236,7 +236,7 @@ void videobuf_dvb_unregister(struct videobuf_dvb *dvb) dvb_dmxdev_release(&dvb->dmxdev); dvb_dmx_release(&dvb->demux); dvb_unregister_frontend(dvb->frontend); - dvb_unregister_adapter(dvb->adapter); + dvb_unregister_adapter(&dvb->adapter); } EXPORT_SYMBOL(videobuf_dvb_register); diff --git a/include/media/video-buf-dvb.h b/include/media/video-buf-dvb.h index 94bd33619aa..ad0a07a3a89 100644 --- a/include/media/video-buf-dvb.h +++ b/include/media/video-buf-dvb.h @@ -16,7 +16,7 @@ struct videobuf_dvb { int nfeeds; /* videobuf_dvb_(un)register manges this */ - struct dvb_adapter *adapter; + struct dvb_adapter adapter; struct dvb_demux demux; struct dmxdev dmxdev; struct dmx_frontend fe_hw; -- cgit v1.2.3 From daeb6aa40be55b0750aea92dea78b8ebc40ca9a8 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:40 -0700 Subject: [PATCH] dvb: bt8xx: update documentation update bt8xx documentation (Uwe Bugla) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/dvb/bt8xx.txt | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/Documentation/dvb/bt8xx.txt b/Documentation/dvb/bt8xx.txt index e3cacf4f234..d84df8072d7 100644 --- a/Documentation/dvb/bt8xx.txt +++ b/Documentation/dvb/bt8xx.txt @@ -17,34 +17,23 @@ Because of this, you need to enable "Device drivers" => "Multimedia devices" => "Video For Linux" => "BT848 Video For Linux" +Furthermore you need to enable +"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices" + => "DVB for Linux" "DVB Core Support" "Nebula/Pinnacle PCTV/TwinHan PCI Cards" + 2) Loading Modules ================== In general you need to load the bttv driver, which will handle the gpio and -i2c communication for us. Next you need the common dvb-bt8xx device driver -and one frontend driver. - -The bttv driver will HANG YOUR SYSTEM IF YOU DO NOT SPECIFY THE CORRECT -CARD ID! - -(If you don't get your card running and you suspect that the card id you're -using is wrong, have a look at "bttv-cards.c" for a list of possible card -ids.) - -Pay attention to failures when you load the frontend drivers -(e.g. dmesg, /var/log/messages). +i2c communication for us, plus the common dvb-bt8xx device driver. +The frontends for Nebula (nxt6000), Pinnacle PCTV (cx24110) and +TwinHan (dst) are loaded automatically by the dvb-bt8xx device driver. 3a) Nebula / Pinnacle PCTV -------------------------- - $ modprobe bttv i2c_hw=1 card=0x68 - $ modprobe dvb-bt8xx - -For Nebula cards use the "nxt6000" frontend driver: - $ modprobe nxt6000 - -For Pinnacle PCTV cards use the "cx24110" frontend driver: - $ modprobe cx24110 + $ modprobe bttv (normally bttv is being loaded automatically by kmod) + $ modprobe dvb-bt8xx (or just place dvb-bt8xx in /etc/modules for automatic loading) 3b) TwinHan ----------- -- cgit v1.2.3 From 50b215a05878ce9636dace6cd21f7e91ff005058 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:41 -0700 Subject: [PATCH] dvb: DST: reorganize Twinhan DST driver to support CI - reorganize Twinhan DST driver to support CI - add support for more cards (Manu Abraham) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/dvb/ci.txt | 219 +++++++++ drivers/media/dvb/bt8xx/Kconfig | 3 +- drivers/media/dvb/bt8xx/Makefile | 4 +- drivers/media/dvb/bt8xx/bt878.c | 18 +- drivers/media/dvb/bt8xx/dst.c | 832 +++++++++++++++++++++------------ drivers/media/dvb/bt8xx/dst.h | 40 -- drivers/media/dvb/bt8xx/dst_ca.c | 868 +++++++++++++++++++++++++++++++++++ drivers/media/dvb/bt8xx/dst_ca.h | 58 +++ drivers/media/dvb/bt8xx/dst_common.h | 153 ++++++ drivers/media/dvb/bt8xx/dst_priv.h | 1 - drivers/media/dvb/bt8xx/dvb-bt8xx.c | 101 ++-- drivers/media/dvb/bt8xx/dvb-bt8xx.h | 2 +- 12 files changed, 1922 insertions(+), 377 deletions(-) create mode 100644 Documentation/dvb/ci.txt delete mode 100644 drivers/media/dvb/bt8xx/dst.h create mode 100644 drivers/media/dvb/bt8xx/dst_ca.c create mode 100644 drivers/media/dvb/bt8xx/dst_ca.h create mode 100644 drivers/media/dvb/bt8xx/dst_common.h diff --git a/Documentation/dvb/ci.txt b/Documentation/dvb/ci.txt new file mode 100644 index 00000000000..62e0701b542 --- /dev/null +++ b/Documentation/dvb/ci.txt @@ -0,0 +1,219 @@ +* For the user +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +NOTE: This document describes the usage of the high level CI API as +in accordance to the Linux DVB API. This is a not a documentation for the, +existing low level CI API. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To utilize the High Level CI capabilities, + +(1*) This point is valid only for the Twinhan/clones + For the Twinhan/Twinhan clones, the dst_ca module handles the CI + hardware handling.This module is loaded automatically if a CI + (Common Interface, that holds the CAM (Conditional Access Module) + is detected. + +(2) one requires a userspace application, ca_zap. This small userland + application is in charge of sending the descrambling related information + to the CAM. + +This application requires the following to function properly as of now. + + (a) Tune to a valid channel, with szap. + eg: $ szap -c channels.conf -r "TMC" -x + + (b) a channels.conf containing a valid PMT PID + + eg: TMC:11996:h:0:27500:278:512:650:321 + + here 278 is a valid PMT PID. the rest of the values are the + same ones that szap uses. + + (c) after running a szap, you have to run ca_zap, for the + descrambler to function, + + eg: $ ca_zap patched_channels.conf "TMC" + + The patched means a patch to apply to scan, such that scan can + generate a channels.conf_with pmt, which has this PMT PID info + (NOTE: szap cannot use this channels.conf with the PMT_PID) + + + (d) Hopeflly Enjoy your favourite subscribed channel as you do with + a FTA card. + +(3) Currently ca_zap, and dst_test, both are meant for demonstration + purposes only, they can become full fledged applications if necessary. + + +* Cards that fall in this category +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +At present the cards that fall in this category are the Twinhan and it's +clones, these cards are available as VVMER, Tomato, Hercules, Orange and +so on. + +* CI modules that are supported +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The CI module support is largely dependant upon the firmware on the cards +Some cards do support almost all of the available CI modules. There is +nothing much that can be done in order to make additional CI modules +working with these cards. + +Modules that have been tested by this driver at present are + +(1) Irdeto 1 and 2 from SCM +(2) Viaccess from SCM +(3) Dragoncam + +* The High level CI API +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* For the programmer +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +With the High Level CI approach any new card with almost any random +architecture can be implemented with this style, the definitions +insidethe switch statement can be easily adapted for any card, thereby +eliminating the need for any additional ioctls. + +The disadvantage is that the driver/hardware has to manage the rest. For +the application programmer it would be as simple as sending/receiving an +array to/from the CI ioctls as defined in the Linux DVB API. No changes +have been made in the API to accomodate this feature. + + +* Why the need for another CI interface ? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This is one of the most commonly asked question. Well a nice question. +Strictly speaking this is not a new interface. + +The CI interface is defined in the DVB API in ca.h as + +typedef struct ca_slot_info { + int num; /* slot number */ + + int type; /* CA interface this slot supports */ +#define CA_CI 1 /* CI high level interface */ +#define CA_CI_LINK 2 /* CI link layer level interface */ +#define CA_CI_PHYS 4 /* CI physical layer level interface */ +#define CA_DESCR 8 /* built-in descrambler */ +#define CA_SC 128 /* simple smart card interface */ + + unsigned int flags; +#define CA_CI_MODULE_PRESENT 1 /* module (or card) inserted */ +#define CA_CI_MODULE_READY 2 +} ca_slot_info_t; + + + +This CI interface follows the CI high level interface, which is not +implemented by most applications. Hence this area is revisited. + +This CI interface is quite different in the case that it tries to +accomodate all other CI based devices, that fall into the other categories + +This means that this CI interface handles the EN50221 style tags in the +Application layer only and no session management is taken care of by the +application. The driver/hardware will take care of all that. + +This interface is purely an EN50221 interface exchanging APDU's. This +means that no session management, link layer or a transport layer do +exist in this case in the application to driver communication. It is +as simple as that. The driver/hardware has to take care of that. + + +With this High Level CI interface, the interface can be defined with the +regular ioctls. + +All these ioctls are also valid for the High level CI interface + +#define CA_RESET _IO('o', 128) +#define CA_GET_CAP _IOR('o', 129, ca_caps_t) +#define CA_GET_SLOT_INFO _IOR('o', 130, ca_slot_info_t) +#define CA_GET_DESCR_INFO _IOR('o', 131, ca_descr_info_t) +#define CA_GET_MSG _IOR('o', 132, ca_msg_t) +#define CA_SEND_MSG _IOW('o', 133, ca_msg_t) +#define CA_SET_DESCR _IOW('o', 134, ca_descr_t) +#define CA_SET_PID _IOW('o', 135, ca_pid_t) + + +On querying the device, the device yields information thus + +CA_GET_SLOT_INFO +---------------------------- +Command = [info] +APP: Number=[1] +APP: Type=[1] +APP: flags=[1] +APP: CI High level interface +APP: CA/CI Module Present + +CA_GET_CAP +---------------------------- +Command = [caps] +APP: Slots=[1] +APP: Type=[1] +APP: Descrambler keys=[16] +APP: Type=[1] + +CA_SEND_MSG +---------------------------- +Descriptors(Program Level)=[ 09 06 06 04 05 50 ff f1] +Found CA descriptor @ program level + +(20) ES type=[2] ES pid=[201] ES length =[0 (0x0)] +(25) ES type=[4] ES pid=[301] ES length =[0 (0x0)] +ca_message length is 25 (0x19) bytes +EN50221 CA MSG=[ 9f 80 32 19 03 01 2d d1 f0 08 01 09 06 06 04 05 50 ff f1 02 e0 c9 00 00 04 e1 2d 00 00] + + +Not all ioctl's are implemented in the driver from the API, the other +features of the hardware that cannot be implemented by the API are achieved +using the CA_GET_MSG and CA_SEND_MSG ioctls. An EN50221 style wrapper is +used to exchange the data to maintain compatibility with other hardware. + + +/* a message to/from a CI-CAM */ +typedef struct ca_msg { + unsigned int index; + unsigned int type; + unsigned int length; + unsigned char msg[256]; +} ca_msg_t; + + +The flow of data can be described thus, + + + + + + App (User) + ----- + parse + | + | + v + en50221 APDU (package) + -------------------------------------- + | | | High Level CI driver + | | | + | v | + | en50221 APDU (unpackage) | + | | | + | | | + | v | + | sanity checks | + | | | + | | | + | v | + | do (H/W dep) | + -------------------------------------- + | Hardware + | + v + + + + +The High Level CI interface uses the EN50221 DVB standard, following a +standard ensures futureproofness. diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig index e7d11e0667a..b12545f093f 100644 --- a/drivers/media/dvb/bt8xx/Kconfig +++ b/drivers/media/dvb/bt8xx/Kconfig @@ -11,9 +11,8 @@ config DVB_BT8XX the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards and pcHDTV HD2000 cards. - Since these cards have no MPEG decoder onboard, they transmit + Since these cards have no MPEG decoder onboard, they transmit only compressed MPEG data over the PCI bus, so you need an external software decoder to watch TV on your computer. Say Y if you own such a device and want to use it. - diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile index 9da8604b9e1..d188e4c670b 100644 --- a/drivers/media/dvb/bt8xx/Makefile +++ b/drivers/media/dvb/bt8xx/Makefile @@ -1,5 +1,3 @@ - -obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o +obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video -Idrivers/media/dvb/frontends - diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c index 213ff790202..7e51530b587 100644 --- a/drivers/media/dvb/bt8xx/bt878.c +++ b/drivers/media/dvb/bt8xx/bt878.c @@ -4,8 +4,8 @@ * Copyright (C) 2002 Peter Hettkamp * * large parts based on the bttv driver - * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - * & Marcus Metzler (mocm@thp.uni-koeln.de) + * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@metzlerbros.de) + * & Marcus Metzler (mocm@metzlerbros.de) * (c) 1999,2000 Gerd Knorr * * This program is free software; you can redistribute it and/or @@ -461,9 +461,9 @@ static int __devinit bt878_probe(struct pci_dev *dev, pci_set_drvdata(dev, bt); /* if(init_bt878(btv) < 0) { - bt878_remove(dev); - return -EIO; - } + bt878_remove(dev); + return -EIO; + } */ if ((result = bt878_mem_alloc(bt))) { @@ -536,10 +536,10 @@ static struct pci_device_id bt878_pci_tbl[] __devinitdata = { MODULE_DEVICE_TABLE(pci, bt878_pci_tbl); static struct pci_driver bt878_pci_driver = { - .name = "bt878", + .name = "bt878", .id_table = bt878_pci_tbl, - .probe = bt878_probe, - .remove = bt878_remove, + .probe = bt878_probe, + .remove = bt878_remove, }; static int bt878_pci_driver_registered = 0; @@ -558,7 +558,7 @@ static int bt878_init_module(void) (BT878_VERSION_CODE >> 8) & 0xff, BT878_VERSION_CODE & 0xff); /* - bt878_check_chipset(); + bt878_check_chipset(); */ /* later we register inside of bt878_find_audio_dma() * because we may want to ignore certain cards */ diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index eac83768dfd..a28b7351eac 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -1,25 +1,25 @@ /* - Frontend-driver for TwinHan DST Frontend - Copyright (C) 2003 Jamie Honan + Frontend/Card driver for TwinHan DST Frontend + Copyright (C) 2003 Jamie Honan + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include #include #include @@ -31,59 +31,28 @@ #include "dvb_frontend.h" #include "dst_priv.h" -#include "dst.h" - -struct dst_state { - - struct i2c_adapter* i2c; - - struct bt878* bt; - - struct dvb_frontend_ops ops; - - /* configuration settings */ - const struct dst_config* config; - - struct dvb_frontend frontend; - - /* private demodulator data */ - u8 tx_tuna[10]; - u8 rx_tuna[10]; - u8 rxbuffer[10]; - u8 diseq_flags; - u8 dst_type; - u32 type_flags; - u32 frequency; /* intermediate frequency in kHz for QPSK */ - fe_spectral_inversion_t inversion; - u32 symbol_rate; /* symbol rate in Symbols per second */ - fe_code_rate_t fec; - fe_sec_voltage_t voltage; - fe_sec_tone_mode_t tone; - u32 decode_freq; - u8 decode_lock; - u16 decode_strength; - u16 decode_snr; - unsigned long cur_jiff; - u8 k22; - fe_bandwidth_t bandwidth; -}; +#include "dst_common.h" + + +static unsigned int verbose = 1; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); + +static unsigned int debug = 1; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "debug messages, default is 0 (yes)"); + +static unsigned int dst_addons; +module_param(dst_addons, int, 0644); +MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (no)"); -static unsigned int dst_verbose = 0; -module_param(dst_verbose, int, 0644); -MODULE_PARM_DESC(dst_verbose, "verbose startup messages, default is 1 (yes)"); -static unsigned int dst_debug = 0; -module_param(dst_debug, int, 0644); -MODULE_PARM_DESC(dst_debug, "debug messages, default is 0 (no)"); +static unsigned int new_fw; +module_param(new_fw, int, 0644); +MODULE_PARM_DESC(new_fw, "Support for the new interface firmware, default 0"); -#define dprintk if (dst_debug) printk -#define DST_TYPE_IS_SAT 0 -#define DST_TYPE_IS_TERR 1 -#define DST_TYPE_IS_CABLE 2 -#define DST_TYPE_HAS_NEWTUNE 1 -#define DST_TYPE_HAS_TS204 2 -#define DST_TYPE_HAS_SYMDIV 4 +#define dprintk if (debug) printk #define HAS_LOCK 1 #define ATTEMPT_TUNE 2 @@ -97,7 +66,7 @@ static void dst_packsize(struct dst_state* state, int psize) bt878_device_control(state->bt, DST_IG_TS, &bits); } -static int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh) +int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int delay) { union dst_gpio_packet enb; union dst_gpio_packet bits; @@ -105,26 +74,35 @@ static int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhig enb.enb.mask = mask; enb.enb.enable = enbb; + if (verbose > 4) + dprintk("%s: mask=[%04x], enbb=[%04x], outhigh=[%04x]\n", __FUNCTION__, mask, enbb, outhigh); + if ((err = bt878_device_control(state->bt, DST_IG_ENABLE, &enb)) < 0) { - dprintk("%s: dst_gpio_enb error (err == %i, mask == 0x%02x, enb == 0x%02x)\n", __FUNCTION__, err, mask, enbb); + dprintk("%s: dst_gpio_enb error (err == %i, mask == %02x, enb == %02x)\n", __FUNCTION__, err, mask, enbb); return -EREMOTEIO; } + msleep(1); + /* because complete disabling means no output, no need to do output packet */ if (enbb == 0) return 0; + if (delay) + msleep(10); + bits.outp.mask = enbb; bits.outp.highvals = outhigh; if ((err = bt878_device_control(state->bt, DST_IG_WRITE, &bits)) < 0) { - dprintk("%s: dst_gpio_outb error (err == %i, enbb == 0x%02x, outhigh == 0x%02x)\n", __FUNCTION__, err, enbb, outhigh); + dprintk("%s: dst_gpio_outb error (err == %i, enbb == %02x, outhigh == %02x)\n", __FUNCTION__, err, enbb, outhigh); return -EREMOTEIO; } return 0; } +EXPORT_SYMBOL(dst_gpio_outb); -static int dst_gpio_inb(struct dst_state *state, u8 * result) +int dst_gpio_inb(struct dst_state *state, u8 * result) { union dst_gpio_packet rd_packet; int err; @@ -139,135 +117,211 @@ static int dst_gpio_inb(struct dst_state *state, u8 * result) *result = (u8) rd_packet.rd.value; return 0; } +EXPORT_SYMBOL(dst_gpio_inb); -#define DST_I2C_ENABLE 1 -#define DST_8820 2 - -static int dst_reset8820(struct dst_state *state) +int rdc_reset_state(struct dst_state *state) { - int retval; - /* pull 8820 gpio pin low, wait, high, wait, then low */ - // dprintk ("%s: reset 8820\n", __FUNCTION__); - retval = dst_gpio_outb(state, DST_8820, DST_8820, 0); - if (retval < 0) - return retval; + if (verbose > 1) + dprintk("%s: Resetting state machine\n", __FUNCTION__); + + if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, 0, NO_DELAY) < 0) { + dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); + return -1; + } + msleep(10); - retval = dst_gpio_outb(state, DST_8820, DST_8820, DST_8820); - if (retval < 0) - return retval; - /* wait for more feedback on what works here * - msleep(10); - retval = dst_gpio_outb(dst, DST_8820, DST_8820, 0); - if (retval < 0) - return retval; - */ + + if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, RDC_8820_INT, NO_DELAY) < 0) { + dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); + msleep(10); + return -1; + } + return 0; } +EXPORT_SYMBOL(rdc_reset_state); -static int dst_i2c_enable(struct dst_state *state) +int rdc_8820_reset(struct dst_state *state) { - int retval; - /* pull I2C enable gpio pin low, wait */ - // dprintk ("%s: i2c enable\n", __FUNCTION__); - retval = dst_gpio_outb(state, ~0, DST_I2C_ENABLE, 0); - if (retval < 0) - return retval; - // dprintk ("%s: i2c enable delay\n", __FUNCTION__); - msleep(33); + if (verbose > 1) + dprintk("%s: Resetting DST\n", __FUNCTION__); + + if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) { + dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); + return -1; + } + msleep(1); + + if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, RDC_8820_RESET, DELAY) < 0) { + dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); + return -1; + } + return 0; } +EXPORT_SYMBOL(rdc_8820_reset); -static int dst_i2c_disable(struct dst_state *state) +int dst_pio_enable(struct dst_state *state) { - int retval; - /* release I2C enable gpio pin, wait */ - // dprintk ("%s: i2c disable\n", __FUNCTION__); - retval = dst_gpio_outb(state, ~0, 0, 0); - if (retval < 0) - return retval; - // dprintk ("%s: i2c disable delay\n", __FUNCTION__); - msleep(33); + if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) { + dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); + return -1; + } + msleep(1); + + return 0; +} +EXPORT_SYMBOL(dst_pio_enable); + +int dst_pio_disable(struct dst_state *state) +{ + if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_DISABLE, RDC_8820_PIO_0_DISABLE, NO_DELAY) < 0) { + dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); + return -1; + } + return 0; } +EXPORT_SYMBOL(dst_pio_disable); -static int dst_wait_dst_ready(struct dst_state *state) +int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode) { u8 reply; - int retval; int i; + for (i = 0; i < 200; i++) { - retval = dst_gpio_inb(state, &reply); - if (retval < 0) - return retval; - if ((reply & DST_I2C_ENABLE) == 0) { - dprintk("%s: dst wait ready after %d\n", __FUNCTION__, i); + if (dst_gpio_inb(state, &reply) < 0) { + dprintk("%s: dst_gpio_inb ERROR !\n", __FUNCTION__); + return -1; + } + + if ((reply & RDC_8820_PIO_0_ENABLE) == 0) { + if (verbose > 4) + dprintk("%s: dst wait ready after %d\n", __FUNCTION__, i); return 1; } - msleep(10); + msleep(1); + } + if (verbose > 1) + dprintk("%s: dst wait NOT ready after %d\n", __FUNCTION__, i); + + return 0; +} +EXPORT_SYMBOL(dst_wait_dst_ready); + +int dst_error_recovery(struct dst_state *state) +{ + dprintk("%s: Trying to return from previous errors...\n", __FUNCTION__); + dst_pio_disable(state); + msleep(10); + dst_pio_enable(state); + msleep(10); + + return 0; +} +EXPORT_SYMBOL(dst_error_recovery); + +int dst_error_bailout(struct dst_state *state) +{ + dprintk("%s: Trying to bailout from previous error...\n", __FUNCTION__); + rdc_8820_reset(state); + dst_pio_disable(state); + msleep(10); + + return 0; +} +EXPORT_SYMBOL(dst_error_bailout); + + +int dst_comm_init(struct dst_state* state) +{ + if (verbose > 1) + dprintk ("%s: Initializing DST..\n", __FUNCTION__); + if ((dst_pio_enable(state)) < 0) { + dprintk("%s: PIO Enable Failed.\n", __FUNCTION__); + return -1; + } + if ((rdc_reset_state(state)) < 0) { + dprintk("%s: RDC 8820 State RESET Failed.\n", __FUNCTION__); + return -1; } - dprintk("%s: dst wait NOT ready after %d\n", __FUNCTION__, i); return 0; } +EXPORT_SYMBOL(dst_comm_init); -static int write_dst(struct dst_state *state, u8 * data, u8 len) + +int write_dst(struct dst_state *state, u8 *data, u8 len) { struct i2c_msg msg = { .addr = state->config->demod_address,.flags = 0,.buf = data,.len = len }; + int err; int cnt; - - if (dst_debug && dst_verbose) { + if (debug && (verbose > 4)) { u8 i; - dprintk("%s writing", __FUNCTION__); - for (i = 0; i < len; i++) { - dprintk(" 0x%02x", data[i]); + if (verbose > 4) { + dprintk("%s writing", __FUNCTION__); + for (i = 0; i < len; i++) + dprintk(" %02x", data[i]); + dprintk("\n"); } - dprintk("\n"); } - msleep(30); - for (cnt = 0; cnt < 4; cnt++) { + for (cnt = 0; cnt < 2; cnt++) { if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { - dprintk("%s: write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, data[0]); - dst_i2c_disable(state); - msleep(500); - dst_i2c_enable(state); - msleep(500); + dprintk("%s: _write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, data[0]); + dst_error_recovery(state); continue; } else break; } - if (cnt >= 4) - return -EREMOTEIO; + + if (cnt >= 2) { + if (verbose > 1) + printk("%s: RDC 8820 RESET...\n", __FUNCTION__); + dst_error_bailout(state); + + return -1; + } + return 0; } +EXPORT_SYMBOL(write_dst); -static int read_dst(struct dst_state *state, u8 * ret, u8 len) +int read_dst(struct dst_state *state, u8 * ret, u8 len) { struct i2c_msg msg = {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = ret,.len = len }; int err; int cnt; - for (cnt = 0; cnt < 4; cnt++) { + for (cnt = 0; cnt < 2; cnt++) { if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { + dprintk("%s: read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, ret[0]); - dst_i2c_disable(state); - dst_i2c_enable(state); + dst_error_recovery(state); + continue; } else break; } - if (cnt >= 4) - return -EREMOTEIO; - dprintk("%s reply is 0x%x\n", __FUNCTION__, ret[0]); - if (dst_debug && dst_verbose) { + if (cnt >= 2) { + if (verbose > 1) + printk("%s: RDC 8820 RESET...\n", __FUNCTION__); + dst_error_bailout(state); + + return -1; + } + if (debug && (verbose > 4)) { + dprintk("%s reply is 0x%x\n", __FUNCTION__, ret[0]); for (err = 1; err < len; err++) dprintk(" 0x%x", ret[err]); if (err > 1) dprintk("\n"); } + return 0; } +EXPORT_SYMBOL(read_dst); static int dst_set_freq(struct dst_state *state, u32 freq) { @@ -422,7 +476,7 @@ static int dst_set_symbolrate(struct dst_state* state, u32 srate) return 0; } -static u8 dst_check_sum(u8 * buf, u32 len) +u8 dst_check_sum(u8 * buf, u32 len) { u32 i; u8 val = 0; @@ -433,28 +487,7 @@ static u8 dst_check_sum(u8 * buf, u32 len) } return ((~val) + 1); } - -struct dst_types { - char *mstr; - int offs; - u8 dst_type; - u32 type_flags; -}; - -static struct dst_types dst_tlist[] = { - {"DST-020", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV}, - {"DST-030", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE}, - {"DST-03T", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204}, - {"DST-MOT", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV}, - {"DST-CI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE}, - {"DSTMCI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE}, - {"DSTFCI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE}, - {"DCTNEW", 1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE}, - {"DCT-CI", 1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_TS204}, - {"DTTDIG", 1, DST_TYPE_IS_TERR, 0} -}; - -/* DCTNEW and DCT-CI are guesses */ +EXPORT_SYMBOL(dst_check_sum); static void dst_type_flags_print(u32 type_flags) { @@ -465,93 +498,260 @@ static void dst_type_flags_print(u32 type_flags) printk(" 0x%x ts204", DST_TYPE_HAS_TS204); if (type_flags & DST_TYPE_HAS_SYMDIV) printk(" 0x%x symdiv", DST_TYPE_HAS_SYMDIV); + if (type_flags & DST_TYPE_HAS_FW_1) + printk(" 0x%x firmware version = 1", DST_TYPE_HAS_FW_1); + if (type_flags & DST_TYPE_HAS_FW_2) + printk(" 0x%x firmware version = 2", DST_TYPE_HAS_FW_2); + if (type_flags & DST_TYPE_HAS_FW_3) + printk(" 0x%x firmware version = 3", DST_TYPE_HAS_FW_3); + printk("\n"); } -static int dst_type_print(u8 type) + +static int dst_type_print (u8 type) { char *otype; switch (type) { case DST_TYPE_IS_SAT: otype = "satellite"; break; + case DST_TYPE_IS_TERR: otype = "terrestrial"; break; + case DST_TYPE_IS_CABLE: otype = "cable"; break; + default: printk("%s: invalid dst type %d\n", __FUNCTION__, type); return -EINVAL; } printk("DST type : %s\n", otype); + return 0; } -static int dst_check_ci(struct dst_state *state) +/* + Known cards list + Satellite + ------------------- + + VP-1020 DST-MOT LG(old), TS=188 + + VP-1020 DST-03T LG(new), TS=204 + VP-1022 DST-03T LG(new), TS=204 + VP-1025 DST-03T LG(new), TS=204 + + VP-1030 DSTMCI, LG(new), TS=188 + VP-1032 DSTMCI, LG(new), TS=188 + + Cable + ------------------- + VP-2030 DCT-CI, Samsung, TS=204 + VP-2021 DCT-CI, Unknown, TS=204 + VP-2031 DCT-CI, Philips, TS=188 + VP-2040 DCT-CI, Philips, TS=188, with CA daughter board + VP-2040 DCT-CI, Philips, TS=204, without CA daughter board + + Terrestrial + ------------------- + VP-3050 DTTNXT TS=188 + VP-3040 DTT-CI, Philips, TS=188 + VP-3040 DTT-CI, Philips, TS=204 + + ATSC + ------------------- + VP-3220 ATSCDI, TS=188 + VP-3250 ATSCAD, TS=188 + +*/ + +struct dst_types dst_tlist[] = { + { + .device_id = "DST-020", + .offset = 0, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, + .dst_feature = 0 + }, /* obsolete */ + + { + .device_id = "DST-030", + .offset = 0, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1, + .dst_feature = 0 + }, /* obsolete */ + + { + .device_id = "DST-03T", + .offset = 0, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2, + .dst_feature = DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_DISEQC5 + | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO + }, + + { + .device_id = "DST-MOT", + .offset = 0, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, + .dst_feature = 0 + }, /* obsolete */ + + { + .device_id = "DST-CI", + .offset = 1, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1, + .dst_feature = DST_TYPE_HAS_CA + }, /* unknown to vendor */ + + { + .device_id = "DSTMCI", + .offset = 1, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2, + .dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 + | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC + }, + + { + .device_id = "DSTFCI", + .offset = 1, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1, + .dst_feature = 0 + }, /* unknown to vendor */ + + { + .device_id = "DCT-CI", + .offset = 1, + .dst_type = DST_TYPE_IS_CABLE, + .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_FW_2, + .dst_feature = DST_TYPE_HAS_CA + }, + + { + .device_id = "DCTNEW", + .offset = 1, + .dst_type = DST_TYPE_IS_CABLE, + .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_3, + .dst_feature = 0 + }, + + { + .device_id = "DTT-CI", + .offset = 1, + .dst_type = DST_TYPE_IS_TERR, + .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2, + .dst_feature = 0 + }, + + { + .device_id = "DTTDIG", + .offset = 1, + .dst_type = DST_TYPE_IS_TERR, + .type_flags = DST_TYPE_HAS_FW_2, + .dst_feature = 0 + }, + + { + .device_id = "DTTNXT", + .offset = 1, + .dst_type = DST_TYPE_IS_TERR, + .type_flags = DST_TYPE_HAS_FW_2, + .dst_feature = DST_TYPE_HAS_ANALOG + }, + + { + .device_id = "ATSCDI", + .offset = 1, + .dst_type = DST_TYPE_IS_ATSC, + .type_flags = DST_TYPE_HAS_FW_2, + .dst_feature = 0 + }, + + { + .device_id = "ATSCAD", + .offset = 1, + .dst_type = DST_TYPE_IS_ATSC, + .type_flags = DST_TYPE_HAS_FW_2, + .dst_feature = 0 + }, + + { } + +}; + + +static int dst_get_device_id(struct dst_state *state) { - u8 txbuf[8]; - u8 rxbuf[8]; - int retval; + u8 reply; + int i; - struct dst_types *dsp; - u8 use_dst_type; - u32 use_type_flags; + struct dst_types *p_dst_type; + u8 use_dst_type = 0; + u32 use_type_flags = 0; - memset(txbuf, 0, sizeof(txbuf)); - txbuf[1] = 6; - txbuf[7] = dst_check_sum(txbuf, 7); + static u8 device_type[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}; - dst_i2c_enable(state); - dst_reset8820(state); - retval = write_dst(state, txbuf, 8); - if (retval < 0) { - dst_i2c_disable(state); - dprintk("%s: write not successful, maybe no card?\n", __FUNCTION__); - return retval; - } - msleep(3); - retval = read_dst(state, rxbuf, 1); - dst_i2c_disable(state); - if (retval < 0) { - dprintk("%s: read not successful, maybe no card?\n", __FUNCTION__); - return retval; - } - if (rxbuf[0] != 0xff) { - dprintk("%s: write reply not 0xff, not ci (%02x)\n", __FUNCTION__, rxbuf[0]); - return retval; - } - if (!dst_wait_dst_ready(state)) - return 0; - // dst_i2c_enable(i2c); Dimitri - retval = read_dst(state, rxbuf, 8); - dst_i2c_disable(state); - if (retval < 0) { - dprintk("%s: read not successful\n", __FUNCTION__); - return retval; + device_type[7] = dst_check_sum(device_type, 7); + + if (write_dst(state, device_type, FIXED_COMM)) + return -1; /* Write failed */ + + if ((dst_pio_disable(state)) < 0) + return -1; + + if (read_dst(state, &reply, GET_ACK)) + return -1; /* Read failure */ + + if (reply != ACK) { + dprintk("%s: Write not Acknowledged! [Reply=0x%02x]\n", __FUNCTION__, reply); + return -1; /* Unack'd write */ } - if (rxbuf[7] != dst_check_sum(rxbuf, 7)) { - dprintk("%s: checksum failure\n", __FUNCTION__); - return retval; + + if (!dst_wait_dst_ready(state, DEVICE_INIT)) + return -1; /* DST not ready yet */ + + if (read_dst(state, state->rxbuffer, FIXED_COMM)) + return -1; + + dst_pio_disable(state); + + if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { + dprintk("%s: Checksum failure! \n", __FUNCTION__); + return -1; /* Checksum failure */ } - rxbuf[7] = '\0'; - for (i = 0, dsp = &dst_tlist[0]; i < sizeof(dst_tlist) / sizeof(dst_tlist[0]); i++, dsp++) { - if (!strncmp(&rxbuf[dsp->offs], dsp->mstr, strlen(dsp->mstr))) { - use_type_flags = dsp->type_flags; - use_dst_type = dsp->dst_type; - printk("%s: recognize %s\n", __FUNCTION__, dsp->mstr); + + state->rxbuffer[7] = '\0'; + + for (i = 0, p_dst_type = dst_tlist; i < ARRAY_SIZE (dst_tlist); i++, p_dst_type++) { + if (!strncmp (&state->rxbuffer[p_dst_type->offset], p_dst_type->device_id, strlen (p_dst_type->device_id))) { + use_type_flags = p_dst_type->type_flags; + use_dst_type = p_dst_type->dst_type; + + /* Card capabilities */ + state->dst_hw_cap = p_dst_type->dst_feature; + printk ("%s: Recognise [%s]\n", __FUNCTION__, p_dst_type->device_id); + break; } } - if (i >= sizeof(dst_tlist) / sizeof(dst_tlist[0])) { - printk("%s: unable to recognize %s or %s\n", __FUNCTION__, &rxbuf[0], &rxbuf[1]); - printk("%s please email linux-dvb@linuxtv.org with this type in\n", __FUNCTION__); + + if (i >= sizeof (dst_tlist) / sizeof (dst_tlist [0])) { + printk("%s: Unable to recognize %s or %s\n", __FUNCTION__, &state->rxbuffer[0], &state->rxbuffer[1]); + printk("%s: please email linux-dvb@linuxtv.org with this type in\n", __FUNCTION__); use_dst_type = DST_TYPE_IS_SAT; use_type_flags = DST_TYPE_HAS_SYMDIV; } - dst_type_print(use_dst_type); + dst_type_print(use_dst_type); state->type_flags = use_type_flags; state->dst_type = use_dst_type; dst_type_flags_print(state->type_flags); @@ -559,50 +759,89 @@ static int dst_check_ci(struct dst_state *state) if (state->type_flags & DST_TYPE_HAS_TS204) { dst_packsize(state, 204); } + return 0; } -static int dst_command(struct dst_state* state, u8 * data, u8 len) +static int dst_probe(struct dst_state *state) +{ + if ((rdc_8820_reset(state)) < 0) { + dprintk("%s: RDC 8820 RESET Failed.\n", __FUNCTION__); + return -1; + } + msleep(4000); + if ((dst_comm_init(state)) < 0) { + dprintk("%s: DST Initialization Failed.\n", __FUNCTION__); + return -1; + } + + if (dst_get_device_id(state) < 0) { + dprintk("%s: unknown device.\n", __FUNCTION__); + return -1; + } + + return 0; +} + +int dst_command(struct dst_state* state, u8 * data, u8 len) { - int retval; u8 reply; + if ((dst_comm_init(state)) < 0) { + dprintk("%s: DST Communication Initialization Failed.\n", __FUNCTION__); + return -1; + } - dst_i2c_enable(state); - dst_reset8820(state); - retval = write_dst(state, data, len); - if (retval < 0) { - dst_i2c_disable(state); - dprintk("%s: write not successful\n", __FUNCTION__); - return retval; + if (write_dst(state, data, len)) { + if (verbose > 1) + dprintk("%s: Tring to recover.. \n", __FUNCTION__); + if ((dst_error_recovery(state)) < 0) { + dprintk("%s: Recovery Failed.\n", __FUNCTION__); + return -1; + } + return -1; } - msleep(33); - retval = read_dst(state, &reply, 1); - dst_i2c_disable(state); - if (retval < 0) { - dprintk("%s: read verify not successful\n", __FUNCTION__); - return retval; + if ((dst_pio_disable(state)) < 0) { + dprintk("%s: PIO Disable Failed.\n", __FUNCTION__); + return -1; } - if (reply != 0xff) { - dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply); - return 0; + + if (read_dst(state, &reply, GET_ACK)) { + if (verbose > 1) + dprintk("%s: Trying to recover.. \n", __FUNCTION__); + if ((dst_error_recovery(state)) < 0) { + dprintk("%s: Recovery Failed.\n", __FUNCTION__); + return -1; + } + return -1; + } + + if (reply != ACK) { + dprintk("%s: write not acknowledged 0x%02x \n", __FUNCTION__, reply); + return -1; } if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3)) return 0; - if (!dst_wait_dst_ready(state)) - return 0; - // dst_i2c_enable(i2c); Per dimitri - retval = read_dst(state, state->rxbuffer, 8); - dst_i2c_disable(state); - if (retval < 0) { - dprintk("%s: read not successful\n", __FUNCTION__); - return 0; + if (!dst_wait_dst_ready(state, NO_DELAY)) + return -1; + + if (read_dst(state, state->rxbuffer, FIXED_COMM)) { + if (verbose > 1) + dprintk("%s: Trying to recover.. \n", __FUNCTION__); + if ((dst_error_recovery(state)) < 0) { + dprintk("%s: Recovery failed.\n", __FUNCTION__); + return -1; + } + return -1; } + if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { dprintk("%s: checksum failure\n", __FUNCTION__); - return 0; + return -1; } + return 0; } +EXPORT_SYMBOL(dst_command); static int dst_get_signal(struct dst_state* state) { @@ -646,11 +885,17 @@ static int dst_tone_power_cmd(struct dst_state* state) paket[4] = 0; else paket[4] = 1; + if (state->tone == SEC_TONE_ON) - paket[2] = state->k22; + paket[2] = 0x02; else paket[2] = 0; - paket[7] = dst_check_sum(&paket[0], 7); + if (state->minicmd == SEC_MINI_A) + paket[3] = 0x02; + else + paket[3] = 0; + + paket[7] = dst_check_sum (paket, 7); dst_command(state, paket, 8); return 0; } @@ -658,21 +903,28 @@ static int dst_tone_power_cmd(struct dst_state* state) static int dst_get_tuna(struct dst_state* state) { int retval; + if ((state->diseq_flags & ATTEMPT_TUNE) == 0) return 0; + state->diseq_flags &= ~(HAS_LOCK); - if (!dst_wait_dst_ready(state)) + if (!dst_wait_dst_ready(state, NO_DELAY)) return 0; + + msleep(10); + if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { /* how to get variable length reply ???? */ retval = read_dst(state, state->rx_tuna, 10); } else { - retval = read_dst(state, &state->rx_tuna[2], 8); + retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM); } + if (retval < 0) { dprintk("%s: read not successful\n", __FUNCTION__); return 0; } + if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) { dprintk("%s: checksum failure?\n", __FUNCTION__); @@ -717,32 +969,41 @@ static int dst_write_tuna(struct dvb_frontend* fe) dst_set_voltage(fe, SEC_VOLTAGE_13); } state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE); - dst_i2c_enable(state); + + if ((dst_comm_init(state)) < 0) { + dprintk("%s: DST Communication initialization failed.\n", __FUNCTION__); + return -1; + } + if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { - dst_reset8820(state); state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9); retval = write_dst(state, &state->tx_tuna[0], 10); + } else { state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7); - retval = write_dst(state, &state->tx_tuna[2], 8); + retval = write_dst(state, &state->tx_tuna[2], FIXED_COMM); } if (retval < 0) { - dst_i2c_disable(state); + dst_pio_disable(state); dprintk("%s: write not successful\n", __FUNCTION__); return retval; } - msleep(3); - retval = read_dst(state, &reply, 1); - dst_i2c_disable(state); - if (retval < 0) { - dprintk("%s: read verify not successful\n", __FUNCTION__); - return retval; + + if ((dst_pio_disable(state)) < 0) { + dprintk("%s: DST PIO disable failed !\n", __FUNCTION__); + return -1; + } + + if ((read_dst(state, &reply, GET_ACK) < 0)) { + dprintk("%s: read verify not successful.\n", __FUNCTION__); + return -1; } - if (reply != 0xff) { - dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply); + if (reply != ACK) { + dprintk("%s: write not acknowledged 0x%02x \n", __FUNCTION__, reply); return 0; } state->diseq_flags |= ATTEMPT_TUNE; + return dst_get_tuna(state); } @@ -796,22 +1057,25 @@ static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) need_cmd = 1; state->diseq_flags |= HAS_POWER; break; + case SEC_VOLTAGE_18: if ((state->diseq_flags & HAS_POWER) == 0) need_cmd = 1; state->diseq_flags |= HAS_POWER; val[8] |= 0x40; break; + case SEC_VOLTAGE_OFF: need_cmd = 1; state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE); break; + default: return -EINVAL; } - if (need_cmd) { + if (need_cmd) dst_tone_power_cmd(state); - } + return 0; } @@ -832,13 +1096,16 @@ static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) switch (tone) { case SEC_TONE_OFF: break; + case SEC_TONE_ON: val[8] |= 1; break; + default: return -EINVAL; } dst_tone_power_cmd(state); + return 0; } @@ -913,10 +1180,16 @@ static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet struct dst_state* state = (struct dst_state*) fe->demodulator_priv; dst_set_freq(state, p->frequency); + if (verbose > 4) + dprintk("Set Frequency = [%d]\n", p->frequency); + dst_set_inversion(state, p->inversion); if (state->dst_type == DST_TYPE_IS_SAT) { dst_set_fec(state, p->u.qpsk.fec_inner); dst_set_symbolrate(state, p->u.qpsk.symbol_rate); + if (verbose > 4) + dprintk("Set Symbolrate = [%d]\n", p->u.qpsk.symbol_rate); + } else if (state->dst_type == DST_TYPE_IS_TERR) { dst_set_bandwidth(state, p->u.ofdm.bandwidth); } else if (state->dst_type == DST_TYPE_IS_CABLE) { @@ -958,50 +1231,47 @@ static struct dvb_frontend_ops dst_dvbt_ops; static struct dvb_frontend_ops dst_dvbs_ops; static struct dvb_frontend_ops dst_dvbc_ops; -struct dvb_frontend* dst_attach(const struct dst_config* config, - struct i2c_adapter* i2c, - struct bt878 *bt) +struct dst_state* dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter) { - struct dst_state* state = NULL; - - /* allocate memory for the internal state */ - state = (struct dst_state*) kmalloc(sizeof(struct dst_state), GFP_KERNEL); - if (state == NULL) goto error; - /* setup the state */ - state->config = config; - state->i2c = i2c; - state->bt = bt; - - /* check if the demod is there */ - if (dst_check_ci(state) < 0) goto error; + /* check if the ASIC is there */ + if (dst_probe(state) < 0) { + if (state) + kfree(state); + return NULL; + } /* determine settings based on type */ switch (state->dst_type) { case DST_TYPE_IS_TERR: memcpy(&state->ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops)); break; + case DST_TYPE_IS_CABLE: memcpy(&state->ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops)); break; + case DST_TYPE_IS_SAT: memcpy(&state->ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops)); break; + default: - printk("dst: unknown frontend type. please report to the LinuxTV.org DVB mailinglist.\n"); - goto error; + printk("%s: unknown DST type. please report to the LinuxTV.org DVB mailinglist.\n", __FUNCTION__); + if (state) + kfree(state); + + return NULL; } /* create dvb_frontend */ state->frontend.ops = &state->ops; state->frontend.demodulator_priv = state; - return &state->frontend; -error: - kfree(state); - return NULL; + return state; /* Manu (DST is a card not a frontend) */ } +EXPORT_SYMBOL(dst_attach); + static struct dvb_frontend_ops dst_dvbt_ops = { .info = { @@ -1051,6 +1321,7 @@ static struct dvb_frontend_ops dst_dvbs_ops = { .read_signal_strength = dst_read_signal_strength, .read_snr = dst_read_snr, + .diseqc_send_burst = dst_set_tone, .diseqc_send_master_cmd = dst_set_diseqc, .set_voltage = dst_set_voltage, .set_tone = dst_set_tone, @@ -1082,8 +1353,7 @@ static struct dvb_frontend_ops dst_dvbc_ops = { .read_snr = dst_read_snr, }; + MODULE_DESCRIPTION("DST DVB-S/T/C Combo Frontend driver"); -MODULE_AUTHOR("Jamie Honan"); +MODULE_AUTHOR("Jamie Honan, Manu Abraham"); MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(dst_attach); diff --git a/drivers/media/dvb/bt8xx/dst.h b/drivers/media/dvb/bt8xx/dst.h deleted file mode 100644 index bcb418c5c12..00000000000 --- a/drivers/media/dvb/bt8xx/dst.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - Frontend-driver for TwinHan DST Frontend - - Copyright (C) 2003 Jamie Honan - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef DST_H -#define DST_H - -#include -#include -#include "bt878.h" - -struct dst_config -{ - /* the demodulator's i2c address */ - u8 demod_address; -}; - -extern struct dvb_frontend* dst_attach(const struct dst_config* config, - struct i2c_adapter* i2c, - struct bt878 *bt); - -#endif // DST_H diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c new file mode 100644 index 00000000000..206aee3336b --- /dev/null +++ b/drivers/media/dvb/bt8xx/dst_ca.c @@ -0,0 +1,868 @@ +/* + CA-driver for TwinHan DST Frontend/Card + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.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 + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + + +#include +#include +#include +#include + +#include +#include "dvbdev.h" +#include "dvb_frontend.h" + +#include "dst_ca.h" +#include "dst_common.h" + +static unsigned int verbose = 1; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); + +static unsigned int debug = 1; +module_param(debug, int, 0644); +MODULE_PARM_DESC(dst_ca_debug, "debug messages, default is 0 (yes)"); + +static unsigned int session; +module_param(session, int, 0644); +MODULE_PARM_DESC(session, "Support for hardware that has multiple sessions, default 0"); + +static unsigned int new_ca; +module_param(new_ca, int, 0644); +MODULE_PARM_DESC(new_ca, "Support for the new CA interface firmware, default 0"); + +#define dprintk if (debug) printk + + +static int ca_set_slot_descr(void) +{ + /* We could make this more graceful ? */ + return -EOPNOTSUPP; +} + +static int ca_set_pid(void) +{ + /* We could make this more graceful ? */ + return -EOPNOTSUPP; +} + + +static int put_checksum(u8 *check_string, int length) +{ + u8 i = 0, checksum = 0; + + if (verbose > 3) { + dprintk("%s: ========================= Checksum calculation ===========================\n", __FUNCTION__); + dprintk("%s: String Length=[0x%02x]\n", __FUNCTION__, length); + + dprintk("%s: String=[", __FUNCTION__); + } + while (i < length) { + if (verbose > 3) + dprintk(" %02x", check_string[i]); + checksum += check_string[i]; + i++; + } + if (verbose > 3) { + dprintk(" ]\n"); + dprintk("%s: Sum=[%02x]\n", __FUNCTION__, checksum); + } + check_string[length] = ~checksum + 1; + if (verbose > 3) { + dprintk("%s: Checksum=[%02x]\n", __FUNCTION__, check_string[length]); + dprintk("%s: ==========================================================================\n", __FUNCTION__); + } + + return 0; +} + +static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 len, int read) +{ + u8 reply; + + dst_comm_init(state); + msleep(65); + + if (write_dst(state, data, len)) { + dprintk("%s: Write not successful, trying to recover\n", __FUNCTION__); + dst_error_recovery(state); + return -1; + } + + if ((dst_pio_disable(state)) < 0) { + dprintk("%s: DST PIO disable failed.\n", __FUNCTION__); + return -1; + } + + if (read_dst(state, &reply, GET_ACK) < 0) { + dprintk("%s: Read not successful, trying to recover\n", __FUNCTION__); + dst_error_recovery(state); + return -1; + } + + if (read) { + if (! dst_wait_dst_ready(state, LONG_DELAY)) { + dprintk("%s: 8820 not ready\n", __FUNCTION__); + return -1; + } + + if (read_dst(state, ca_string, 128) < 0) { /* Try to make this dynamic */ + dprintk("%s: Read not successful, trying to recover\n", __FUNCTION__); + dst_error_recovery(state); + return -1; + } + } + + return 0; +} + + +static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, int read) +{ + u8 dst_ca_comm_err = 0; + + while (dst_ca_comm_err < RETRIES) { + dst_comm_init(state); + if (verbose > 2) + dprintk("%s: Put Command\n", __FUNCTION__); + if (dst_ci_command(state, data, ca_string, len, read)) { // If error + dst_error_recovery(state); + dst_ca_comm_err++; // work required here. + } + break; + } + + return 0; +} + + + +static int ca_get_app_info(struct dst_state *state) +{ + static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff}; + + put_checksum(&command[0], command[0]); + if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) { + dprintk("%s: -->dst_put_ci FAILED !\n", __FUNCTION__); + return -1; + } + if (verbose > 1) { + dprintk("%s: -->dst_put_ci SUCCESS !\n", __FUNCTION__); + + dprintk("%s: ================================ CI Module Application Info ======================================\n", __FUNCTION__); + dprintk("%s: Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]\n", + __FUNCTION__, state->messages[7], (state->messages[8] << 8) | state->messages[9], + (state->messages[10] << 8) | state->messages[11], __FUNCTION__, (char *)(&state->messages[11])); + dprintk("%s: ==================================================================================================\n", __FUNCTION__); + } + + return 0; +} + +static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void *arg) +{ + int i; + u8 slot_cap[256]; + static u8 slot_command[8] = {0x07, 0x40, 0x02, 0x00, 0x02, 0x00, 0x00, 0xff}; + + put_checksum(&slot_command[0], slot_command[0]); + if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_cap, GET_REPLY)) < 0) { + dprintk("%s: -->dst_put_ci FAILED !\n", __FUNCTION__); + return -1; + } + if (verbose > 1) + dprintk("%s: -->dst_put_ci SUCCESS !\n", __FUNCTION__); + + /* Will implement the rest soon */ + + if (verbose > 1) { + dprintk("%s: Slot cap = [%d]\n", __FUNCTION__, slot_cap[7]); + dprintk("===================================\n"); + for (i = 0; i < 8; i++) + dprintk(" %d", slot_cap[i]); + dprintk("\n"); + } + + p_ca_caps->slot_num = 1; + p_ca_caps->slot_type = 1; + p_ca_caps->descr_num = slot_cap[7]; + p_ca_caps->descr_type = 1; + + + if (copy_to_user((struct ca_caps *)arg, p_ca_caps, sizeof (struct ca_caps))) { + return -EFAULT; + } + + return 0; +} + + +static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void *arg) +{ + return -EOPNOTSUPP; +} + + +static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void *arg) +{ + int i; + static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}; + + u8 *slot_info = state->rxbuffer; + + put_checksum(&slot_command[0], 7); + if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) { + dprintk("%s: -->dst_put_ci FAILED !\n", __FUNCTION__); + return -1; + } + if (verbose > 1) + dprintk("%s: -->dst_put_ci SUCCESS !\n", __FUNCTION__); + + /* Will implement the rest soon */ + + if (verbose > 1) { + dprintk("%s: Slot info = [%d]\n", __FUNCTION__, slot_info[3]); + dprintk("===================================\n"); + for (i = 0; i < 8; i++) + dprintk(" %d", slot_info[i]); + dprintk("\n"); + } + + if (slot_info[4] & 0x80) { + p_ca_slot_info->flags = CA_CI_MODULE_PRESENT; + p_ca_slot_info->num = 1; + p_ca_slot_info->type = CA_CI; + } + else if (slot_info[4] & 0x40) { + p_ca_slot_info->flags = CA_CI_MODULE_READY; + p_ca_slot_info->num = 1; + p_ca_slot_info->type = CA_CI; + } + else { + p_ca_slot_info->flags = 0; + } + + if (copy_to_user((struct ca_slot_info *)arg, p_ca_slot_info, sizeof (struct ca_slot_info))) { + return -EFAULT; + } + + return 0; +} + + + + +static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void *arg) +{ + u8 i = 0; + u32 command = 0; + + if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg))) + return -EFAULT; + + + if (p_ca_message->msg) { + if (verbose > 3) + dprintk("Message = [%02x %02x %02x]\n", p_ca_message->msg[0], p_ca_message->msg[1], p_ca_message->msg[2]); + + for (i = 0; i < 3; i++) { + command = command | p_ca_message->msg[i]; + if (i < 2) + command = command << 8; + } + if (verbose > 3) + dprintk("%s:Command=[0x%x]\n", __FUNCTION__, command); + + switch (command) { + case CA_APP_INFO: + memcpy(p_ca_message->msg, state->messages, 128); + if (copy_to_user((void *)arg, p_ca_message, sizeof (struct ca_msg)) ) + return -EFAULT; + break; + } + } + + return 0; +} + +static int handle_en50221_tag(struct ca_msg *p_ca_message, struct ca_msg *hw_buffer) +{ + if (session) { + hw_buffer->msg[2] = p_ca_message->msg[1]; /* MSB */ + hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */ + } + else { + hw_buffer->msg[2] = 0x03; + hw_buffer->msg[3] = 0x00; + } + return 0; +} + +static int debug_8820_buffer(struct ca_msg *hw_buffer) +{ + unsigned int i; + + dprintk("%s:Debug=[", __FUNCTION__); + for (i = 0; i < (hw_buffer->msg[0] + 1); i++) + dprintk(" %02x", hw_buffer->msg[i]); + dprintk("]\n"); + + return 0; +} + +static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 reply) +{ + if ((dst_put_ci(state, hw_buffer->msg, (hw_buffer->length + 1), hw_buffer->msg, reply)) < 0) { + dprintk("%s: DST-CI Command failed.\n", __FUNCTION__); + dprintk("%s: Resetting DST.\n", __FUNCTION__); + rdc_reset_state(state); + return -1; + } + if (verbose > 2) + dprintk("%s: DST-CI Command succes.\n", __FUNCTION__); + + return 0; +} + + +static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query) +{ + u32 hw_offset, buf_offset, i, k; + u32 program_info_length = 0, es_info_length = 0, length = 0, words = 0; + u8 found_prog_ca_desc = 0, found_stream_ca_desc = 0, error_condition = 0, hw_buffer_length = 0; + + if (verbose > 3) + dprintk("%s, p_ca_message length %d (0x%x)\n", __FUNCTION__,p_ca_message->length,p_ca_message->length ); + + handle_en50221_tag(p_ca_message, hw_buffer); /* EN50221 tag */ + + /* Handle the length field (variable) */ + if (!(p_ca_message->msg[3] & 0x80)) { /* Length = 1 */ + length = p_ca_message->msg[3] & 0x7f; + words = 0; /* domi's suggestion */ + } + else { /* Length = words */ + words = p_ca_message->msg[3] & 0x7f; + for (i = 0; i < words; i++) { + length = length << 8; + length = length | p_ca_message->msg[4 + i]; + } + } + if (verbose > 4) { + dprintk("%s:Length=[%d (0x%x)], Words=[%d]\n", __FUNCTION__, length,length, words); + + /* Debug Input string */ + for (i = 0; i < length; i++) + dprintk(" %02x", p_ca_message->msg[i]); + dprintk("]\n"); + } + + hw_offset = 7; + buf_offset = words + 4; + + /* Program Header */ + if (verbose > 4) + dprintk("\n%s:Program Header=[", __FUNCTION__); + for (i = 0; i < 6; i++) { + hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset]; + if (verbose > 4) + dprintk(" %02x", p_ca_message->msg[buf_offset]); + hw_offset++, buf_offset++, hw_buffer_length++; + } + if (verbose > 4) + dprintk("]\n"); + + program_info_length = 0; + program_info_length = (((program_info_length | p_ca_message->msg[words + 8]) & 0x0f) << 8) | p_ca_message->msg[words + 9]; + if (verbose > 4) + dprintk("%s:Program info Length=[%d][%02x], hw_offset=[%d], buf_offset=[%d] \n", + __FUNCTION__, program_info_length, program_info_length, hw_offset, buf_offset); + + if (program_info_length && (program_info_length < 256)) { /* If program_info_length */ + hw_buffer->msg[11] = hw_buffer->msg[11] & 0x0f; /* req only 4 bits */ + hw_buffer->msg[12] = hw_buffer->msg[12] + 1; /* increment! ASIC bug! */ + + if (p_ca_message->msg[buf_offset + 1] == 0x09) { /* Check CA descriptor */ + found_prog_ca_desc = 1; + if (verbose > 4) + dprintk("%s: Found CA descriptor @ Program level\n", __FUNCTION__); + } + + if (found_prog_ca_desc) { /* Command only if CA descriptor */ + hw_buffer->msg[13] = p_ca_message->msg[buf_offset]; /* CA PMT command ID */ + hw_offset++, buf_offset++, hw_buffer_length++; + } + + /* Program descriptors */ + if (verbose > 4) { + dprintk("%s:**********>buf_offset=[%d], hw_offset=[%d]\n", __FUNCTION__, buf_offset, hw_offset); + dprintk("%s:Program descriptors=[", __FUNCTION__); + } + while (program_info_length && !error_condition) { /* Copy prog descriptors */ + if (program_info_length > p_ca_message->length) { /* Error situation */ + dprintk ("%s:\"WARNING\" Length error, line=[%d], prog_info_length=[%d]\n", + __FUNCTION__, __LINE__, program_info_length); + dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__); + error_condition = 1; + break; + } + + hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset]; + dprintk(" %02x", p_ca_message->msg[buf_offset]); + hw_offset++, buf_offset++, hw_buffer_length++, program_info_length--; + } + if (verbose > 4) { + dprintk("]\n"); + dprintk("%s:**********>buf_offset=[%d], hw_offset=[%d]\n", __FUNCTION__, buf_offset, hw_offset); + } + if (found_prog_ca_desc) { + if (!reply) { + hw_buffer->msg[13] = 0x01; /* OK descrambling */ + if (verbose > 1) + dprintk("CA PMT Command = OK Descrambling\n"); + } + else { + hw_buffer->msg[13] = 0x02; /* Ok MMI */ + if (verbose > 1) + dprintk("CA PMT Command = Ok MMI\n"); + } + if (query) { + hw_buffer->msg[13] = 0x03; /* Query */ + if (verbose > 1) + dprintk("CA PMT Command = CA PMT query\n"); + } + } + } + else { + hw_buffer->msg[11] = hw_buffer->msg[11] & 0xf0; /* Don't write to ASIC */ + hw_buffer->msg[12] = hw_buffer->msg[12] = 0x00; + } + if (verbose > 4) + dprintk("%s:**********>p_ca_message->length=[%d], buf_offset=[%d], hw_offset=[%d]\n", + __FUNCTION__, p_ca_message->length, buf_offset, hw_offset); + + while ((buf_offset < p_ca_message->length) && !error_condition) { + /* Bail out in case of an indefinite loop */ + if ((es_info_length > p_ca_message->length) || (buf_offset > p_ca_message->length)) { + dprintk("%s:\"WARNING\" Length error, line=[%d], prog_info_length=[%d], buf_offset=[%d]\n", + __FUNCTION__, __LINE__, program_info_length, buf_offset); + + dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__); + error_condition = 1; + break; + } + + /* Stream Header */ + + for (k = 0; k < 5; k++) { + hw_buffer->msg[hw_offset + k] = p_ca_message->msg[buf_offset + k]; + } + + es_info_length = 0; + es_info_length = (es_info_length | (p_ca_message->msg[buf_offset + 3] & 0x0f)) << 8 | p_ca_message->msg[buf_offset + 4]; + + if (verbose > 4) { + dprintk("\n%s:----->Stream header=[%02x %02x %02x %02x %02x]\n", __FUNCTION__, + p_ca_message->msg[buf_offset + 0], p_ca_message->msg[buf_offset + 1], + p_ca_message->msg[buf_offset + 2], p_ca_message->msg[buf_offset + 3], + p_ca_message->msg[buf_offset + 4]); + + dprintk("%s:----->Stream type=[%02x], es length=[%d (0x%x)], Chars=[%02x] [%02x], buf_offset=[%d]\n", __FUNCTION__, + p_ca_message->msg[buf_offset + 0], es_info_length, es_info_length, + p_ca_message->msg[buf_offset + 3], p_ca_message->msg[buf_offset + 4], buf_offset); + } + + hw_buffer->msg[hw_offset + 3] &= 0x0f; /* req only 4 bits */ + + if (found_prog_ca_desc) { + hw_buffer->msg[hw_offset + 3] = 0x00; + hw_buffer->msg[hw_offset + 4] = 0x00; + } + + hw_offset += 5, buf_offset += 5, hw_buffer_length += 5; + + /* Check for CA descriptor */ + if (p_ca_message->msg[buf_offset + 1] == 0x09) { + if (verbose > 4) + dprintk("%s:Found CA descriptor @ Stream level\n", __FUNCTION__); + found_stream_ca_desc = 1; + } + + /* ES descriptors */ + + if (es_info_length && !error_condition && !found_prog_ca_desc && found_stream_ca_desc) { +// if (!ca_pmt_done) { + hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset]; /* CA PMT cmd(es) */ + if (verbose > 4) + printk("%s:----->CA PMT Command ID=[%02x]\n", __FUNCTION__, p_ca_message->msg[buf_offset]); +// hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--, ca_pmt_done = 1; + hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--; +// } + if (verbose > 4) + dprintk("%s:----->ES descriptors=[", __FUNCTION__); + + while (es_info_length && !error_condition) { /* ES descriptors */ + if ((es_info_length > p_ca_message->length) || (buf_offset > p_ca_message->length)) { + if (verbose > 4) { + dprintk("%s:\"WARNING\" ES Length error, line=[%d], es_info_length=[%d], buf_offset=[%d]\n", + __FUNCTION__, __LINE__, es_info_length, buf_offset); + + dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__); + } + error_condition = 1; + break; + } + + hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset]; + if (verbose > 3) + dprintk("%02x ", hw_buffer->msg[hw_offset]); + hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--; + } + found_stream_ca_desc = 0; /* unset for new streams */ + dprintk("]\n"); + } + } + + /* MCU Magic words */ + + hw_buffer_length += 7; + hw_buffer->msg[0] = hw_buffer_length; + hw_buffer->msg[1] = 64; + hw_buffer->msg[4] = 3; + hw_buffer->msg[5] = hw_buffer->msg[0] - 7; + hw_buffer->msg[6] = 0; + + + /* Fix length */ + hw_buffer->length = hw_buffer->msg[0]; + + put_checksum(&hw_buffer->msg[0], hw_buffer->msg[0]); + /* Do the actual write */ + if (verbose > 4) { + dprintk("%s:======================DEBUGGING================================\n", __FUNCTION__); + dprintk("%s: Actual Length=[%d]\n", __FUNCTION__, hw_buffer_length); + } + /* Only for debugging! */ + if (verbose > 2) + debug_8820_buffer(hw_buffer); + if (verbose > 3) + dprintk("%s: Reply = [%d]\n", __FUNCTION__, reply); + write_to_8820(state, hw_buffer, reply); + + return 0; +} + +/* Board supports CA PMT reply ? */ +static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer) +{ + int ca_pmt_reply_test = 0; + + /* Do test board */ + /* Not there yet but soon */ + + + /* CA PMT Reply capable */ + if (ca_pmt_reply_test) { + if ((ca_set_pmt(state, p_ca_message, hw_buffer, 1, GET_REPLY)) < 0) { + dprintk("%s: ca_set_pmt.. failed !\n", __FUNCTION__); + return -1; + } + + /* Process CA PMT Reply */ + /* will implement soon */ + dprintk("%s: Not there yet\n", __FUNCTION__); + } + /* CA PMT Reply not capable */ + if (!ca_pmt_reply_test) { + if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) { + dprintk("%s: ca_set_pmt.. failed !\n", __FUNCTION__); + return -1; + } + if (verbose > 3) + dprintk("%s: ca_set_pmt.. success !\n", __FUNCTION__); + /* put a dummy message */ + + } + return 0; +} + +static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void *arg) +{ + int i = 0; + unsigned int ca_message_header_len; + + u32 command = 0; + struct ca_msg *hw_buffer; + + if ((hw_buffer = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) { + printk("%s: Memory allocation failure\n", __FUNCTION__); + return -ENOMEM; + } + if (verbose > 3) + dprintk("%s\n", __FUNCTION__); + + if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg))) + return -EFAULT; + + if (p_ca_message->msg) { + ca_message_header_len = p_ca_message->length; /* Restore it back when you are done */ + /* EN50221 tag */ + command = 0; + + for (i = 0; i < 3; i++) { + command = command | p_ca_message->msg[i]; + if (i < 2) + command = command << 8; + } + if (verbose > 3) + dprintk("%s:Command=[0x%x]\n", __FUNCTION__, command); + + switch (command) { + case CA_PMT: + if (verbose > 3) + dprintk("Command = SEND_CA_PMT\n"); + if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { + dprintk("%s: -->CA_PMT Failed !\n", __FUNCTION__); + return -1; + } + if (verbose > 3) + dprintk("%s: -->CA_PMT Success !\n", __FUNCTION__); +// retval = dummy_set_pmt(state, p_ca_message, hw_buffer, 0, 0); + + break; + + case CA_PMT_REPLY: + if (verbose > 3) + dprintk("Command = CA_PMT_REPLY\n"); + /* Have to handle the 2 basic types of cards here */ + if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) { + dprintk("%s: -->CA_PMT_REPLY Failed !\n", __FUNCTION__); + return -1; + } + if (verbose > 3) + dprintk("%s: -->CA_PMT_REPLY Success !\n", __FUNCTION__); + + /* Certain boards do behave different ? */ +// retval = ca_set_pmt(state, p_ca_message, hw_buffer, 1, 1); + + case CA_APP_INFO_ENQUIRY: // only for debugging + if (verbose > 3) + dprintk("%s: Getting Cam Application information\n", __FUNCTION__); + + if ((ca_get_app_info(state)) < 0) { + dprintk("%s: -->CA_APP_INFO_ENQUIRY Failed !\n", __FUNCTION__); + return -1; + } + if (verbose > 3) + printk("%s: -->CA_APP_INFO_ENQUIRY Success !\n", __FUNCTION__); + + break; + } + } + return 0; +} + +static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg) +{ + struct dvb_device* dvbdev = (struct dvb_device*) file->private_data; + struct dst_state* state = (struct dst_state*) dvbdev->priv; + struct ca_slot_info *p_ca_slot_info; + struct ca_caps *p_ca_caps; + struct ca_msg *p_ca_message; + + if ((p_ca_message = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) { + printk("%s: Memory allocation failure\n", __FUNCTION__); + return -ENOMEM; + } + + if ((p_ca_slot_info = (struct ca_slot_info *) kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL)) == NULL) { + printk("%s: Memory allocation failure\n", __FUNCTION__); + return -ENOMEM; + } + + if ((p_ca_caps = (struct ca_caps *) kmalloc(sizeof (struct ca_caps), GFP_KERNEL)) == NULL) { + printk("%s: Memory allocation failure\n", __FUNCTION__); + return -ENOMEM; + } + + /* We have now only the standard ioctl's, the driver is upposed to handle internals. */ + switch (cmd) { + case CA_SEND_MSG: + if (verbose > 1) + dprintk("%s: Sending message\n", __FUNCTION__); + if ((ca_send_message(state, p_ca_message, arg)) < 0) { + dprintk("%s: -->CA_SEND_MSG Failed !\n", __FUNCTION__); + return -1; + } + + break; + + case CA_GET_MSG: + if (verbose > 1) + dprintk("%s: Getting message\n", __FUNCTION__); + if ((ca_get_message(state, p_ca_message, arg)) < 0) { + dprintk("%s: -->CA_GET_MSG Failed !\n", __FUNCTION__); + return -1; + } + if (verbose > 1) + dprintk("%s: -->CA_GET_MSG Success !\n", __FUNCTION__); + + break; + + case CA_RESET: + if (verbose > 1) + dprintk("%s: Resetting DST\n", __FUNCTION__); + dst_error_bailout(state); + msleep(4000); + + break; + + case CA_GET_SLOT_INFO: + if (verbose > 1) + dprintk("%s: Getting Slot info\n", __FUNCTION__); + if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) { + dprintk("%s: -->CA_GET_SLOT_INFO Failed !\n", __FUNCTION__); + return -1; + } + if (verbose > 1) + dprintk("%s: -->CA_GET_SLOT_INFO Success !\n", __FUNCTION__); + + break; + + case CA_GET_CAP: + if (verbose > 1) + dprintk("%s: Getting Slot capabilities\n", __FUNCTION__); + if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) { + dprintk("%s: -->CA_GET_CAP Failed !\n", __FUNCTION__); + return -1; + } + if (verbose > 1) + dprintk("%s: -->CA_GET_CAP Success !\n", __FUNCTION__); + + break; + + case CA_GET_DESCR_INFO: + if (verbose > 1) + dprintk("%s: Getting descrambler description\n", __FUNCTION__); + if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) { + dprintk("%s: -->CA_GET_DESCR_INFO Failed !\n", __FUNCTION__); + return -1; + } + if (verbose > 1) + dprintk("%s: -->CA_GET_DESCR_INFO Success !\n", __FUNCTION__); + + break; + + case CA_SET_DESCR: + if (verbose > 1) + dprintk("%s: Setting descrambler\n", __FUNCTION__); + if ((ca_set_slot_descr()) < 0) { + dprintk("%s: -->CA_SET_DESCR Failed !\n", __FUNCTION__); + return -1; + } + if (verbose > 1) + dprintk("%s: -->CA_SET_DESCR Success !\n", __FUNCTION__); + + break; + + case CA_SET_PID: + if (verbose > 1) + dprintk("%s: Setting PID\n", __FUNCTION__); + if ((ca_set_pid()) < 0) { + dprintk("%s: -->CA_SET_PID Failed !\n", __FUNCTION__); + return -1; + } + if (verbose > 1) + dprintk("%s: -->CA_SET_PID Success !\n", __FUNCTION__); + + default: + return -EOPNOTSUPP; + }; + + return 0; +} + +static int dst_ca_open(struct inode *inode, struct file *file) +{ + if (verbose > 4) + dprintk("%s:Device opened [%p]\n", __FUNCTION__, file); + try_module_get(THIS_MODULE); + + return 0; +} + +static int dst_ca_release(struct inode *inode, struct file *file) +{ + if (verbose > 4) + dprintk("%s:Device closed.\n", __FUNCTION__); + module_put(THIS_MODULE); + + return 0; +} + +static int dst_ca_read(struct file *file, char __user * buffer, size_t length, loff_t * offset) +{ + int bytes_read = 0; + + if (verbose > 4) + dprintk("%s:Device read.\n", __FUNCTION__); + + return bytes_read; +} + +static int dst_ca_write(struct file *file, const char __user * buffer, size_t length, loff_t * offset) +{ + if (verbose > 4) + dprintk("%s:Device write.\n", __FUNCTION__); + + return 0; +} + +static struct file_operations dst_ca_fops = { + .owner = THIS_MODULE, + .ioctl = (void *)dst_ca_ioctl, + .open = dst_ca_open, + .release = dst_ca_release, + .read = dst_ca_read, + .write = dst_ca_write +}; + +static struct dvb_device dvbdev_ca = { + .priv = NULL, + .users = 1, + .readers = 1, + .writers = 1, + .fops = &dst_ca_fops +}; + +int dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter) +{ + struct dvb_device *dvbdev; + if (verbose > 4) + dprintk("%s:registering DST-CA device\n", __FUNCTION__); + dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA); + return 0; +} + +EXPORT_SYMBOL(dst_ca_attach); + +MODULE_DESCRIPTION("DST DVB-S/T/C Combo CA driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/bt8xx/dst_ca.h b/drivers/media/dvb/bt8xx/dst_ca.h new file mode 100644 index 00000000000..59cd0ddd6d8 --- /dev/null +++ b/drivers/media/dvb/bt8xx/dst_ca.h @@ -0,0 +1,58 @@ +/* + CA-driver for TwinHan DST Frontend/Card + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.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 + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _DST_CA_H_ +#define _DST_CA_H_ + +#define RETRIES 5 + + +#define CA_APP_INFO_ENQUIRY 0x9f8020 +#define CA_APP_INFO 0x9f8021 +#define CA_ENTER_MENU 0x9f8022 +#define CA_INFO_ENQUIRY 0x9f8030 +#define CA_INFO 0x9f8031 +#define CA_PMT 0x9f8032 +#define CA_PMT_REPLY 0x9f8033 + +#define CA_CLOSE_MMI 0x9f8800 +#define CA_DISPLAY_CONTROL 0x9f8801 +#define CA_DISPLAY_REPLY 0x9f8802 +#define CA_TEXT_LAST 0x9f8803 +#define CA_TEXT_MORE 0x9f8804 +#define CA_KEYPAD_CONTROL 0x9f8805 +#define CA_KEYPRESS 0x9f8806 + +#define CA_ENQUIRY 0x9f8807 +#define CA_ANSWER 0x9f8808 +#define CA_MENU_LAST 0x9f8809 +#define CA_MENU_MORE 0x9f880a +#define CA_MENU_ANSWER 0x9f880b +#define CA_LIST_LAST 0x9f880c +#define CA_LIST_MORE 0x9f880d + + +struct dst_ca_private { + struct dst_state *dst; + struct dvb_device *dvbdev; +}; + + +#endif diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h new file mode 100644 index 00000000000..10046d6292b --- /dev/null +++ b/drivers/media/dvb/bt8xx/dst_common.h @@ -0,0 +1,153 @@ +/* + Frontend-driver for TwinHan DST Frontend + + Copyright (C) 2003 Jamie Honan + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.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 + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef DST_COMMON_H +#define DST_COMMON_H + +#include +#include +#include "bt878.h" + +#include "dst_ca.h" + + +#define NO_DELAY 0 +#define LONG_DELAY 1 +#define DEVICE_INIT 2 + +#define DELAY 1 + +#define DST_TYPE_IS_SAT 0 +#define DST_TYPE_IS_TERR 1 +#define DST_TYPE_IS_CABLE 2 +#define DST_TYPE_IS_ATSC 3 + +#define DST_TYPE_HAS_NEWTUNE 1 +#define DST_TYPE_HAS_TS204 2 +#define DST_TYPE_HAS_SYMDIV 4 +#define DST_TYPE_HAS_FW_1 8 +#define DST_TYPE_HAS_FW_2 16 +#define DST_TYPE_HAS_FW_3 32 + + + +/* Card capability list */ + +#define DST_TYPE_HAS_MAC 1 +#define DST_TYPE_HAS_DISEQC3 2 +#define DST_TYPE_HAS_DISEQC4 4 +#define DST_TYPE_HAS_DISEQC5 8 +#define DST_TYPE_HAS_MOTO 16 +#define DST_TYPE_HAS_CA 32 +#define DST_TYPE_HAS_ANALOG 64 /* Analog inputs */ + + +#define RDC_8820_PIO_0_DISABLE 0 +#define RDC_8820_PIO_0_ENABLE 1 +#define RDC_8820_INT 2 +#define RDC_8820_RESET 4 + +/* DST Communication */ +#define GET_REPLY 1 +#define NO_REPLY 0 + +#define GET_ACK 1 +#define FIXED_COMM 8 + +#define ACK 0xff + +struct dst_state { + + struct i2c_adapter* i2c; + + struct bt878* bt; + + struct dvb_frontend_ops ops; + + /* configuration settings */ + const struct dst_config* config; + + struct dvb_frontend frontend; + + /* private ASIC data */ + u8 tx_tuna[10]; + u8 rx_tuna[10]; + u8 rxbuffer[10]; + u8 diseq_flags; + u8 dst_type; + u32 type_flags; + u32 frequency; /* intermediate frequency in kHz for QPSK */ + fe_spectral_inversion_t inversion; + u32 symbol_rate; /* symbol rate in Symbols per second */ + fe_code_rate_t fec; + fe_sec_voltage_t voltage; + fe_sec_tone_mode_t tone; + u32 decode_freq; + u8 decode_lock; + u16 decode_strength; + u16 decode_snr; + unsigned long cur_jiff; + u8 k22; + fe_bandwidth_t bandwidth; + u8 dst_hw_cap; + u8 dst_fw_version; + fe_sec_mini_cmd_t minicmd; + u8 messages[256]; +}; + +struct dst_types { + char *device_id; + int offset; + u8 dst_type; + u32 type_flags; + u8 dst_feature; +}; + + + +struct dst_config +{ + /* the ASIC i2c address */ + u8 demod_address; +}; + + +int rdc_reset_state(struct dst_state *state); +int rdc_8820_reset(struct dst_state *state); + +int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode); +int dst_pio_enable(struct dst_state *state); +int dst_pio_disable(struct dst_state *state); +int dst_error_recovery(struct dst_state* state); +int dst_error_bailout(struct dst_state *state); +int dst_comm_init(struct dst_state* state); + +int write_dst(struct dst_state *state, u8 * data, u8 len); +int read_dst(struct dst_state *state, u8 * ret, u8 len); +u8 dst_check_sum(u8 * buf, u32 len); +struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter); +int dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter); +int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int delay); + +int dst_command(struct dst_state* state, u8 * data, u8 len); + + +#endif // DST_COMMON_H diff --git a/drivers/media/dvb/bt8xx/dst_priv.h b/drivers/media/dvb/bt8xx/dst_priv.h index 80488aa628b..3974a4c6ebe 100644 --- a/drivers/media/dvb/bt8xx/dst_priv.h +++ b/drivers/media/dvb/bt8xx/dst_priv.h @@ -33,4 +33,3 @@ union dst_gpio_packet { struct bt878; int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp); - diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index f9572426a14..6f857c6091f 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -142,7 +142,7 @@ static int thomson_dtt7579_demod_init(struct dvb_frontend* fe) mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); - mt352_write(fe, mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg)); + mt352_write(fe, mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg)); mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); return 0; @@ -161,7 +161,7 @@ static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_ else if (params->frequency < 771000000) cp = 0xbc; else cp = 0xf4; - if (params->frequency == 0) bs = 0x03; + if (params->frequency == 0) bs = 0x03; else if (params->frequency < 443250000) bs = 0x02; else bs = 0x08; @@ -190,44 +190,44 @@ static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_paramete u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000, - 1576000,1718000,1856000,2036000,2150000}; + 1576000,1718000,1856000,2036000,2150000}; u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000, - 0x00102000,0x00104000,0x00108000,0x00110000, - 0x00120000,0x00140000}; + 0x00102000,0x00104000,0x00108000,0x00110000, + 0x00120000,0x00140000}; #define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */ - printk("cx24108 debug: entering SetTunerFreq, freq=%d\n",freq); - - /* This is really the bit driving the tuner chip cx24108 */ - - if(freq<950000) freq=950000; /* kHz */ - if(freq>2150000) freq=2150000; /* satellite IF is 950..2150MHz */ - - /* decide which VCO to use for the input frequency */ - for(i=1;(i2150000) freq=2150000; /* satellite IF is 950..2150MHz */ + + /* decide which VCO to use for the input frequency */ + for(i=1;(ife = dst_attach(&dst_config, card->i2c_adapter, card->bt); + /* DST is not a frontend driver !!! */ + state = (struct dst_state *) kmalloc(sizeof (struct dst_state), GFP_KERNEL); + /* Setup the Card */ + state->config = &dst_config; + state->i2c = card->i2c_adapter; + state->bt = card->bt; + + /* DST is not a frontend, attaching the ASIC */ + if ((dst_attach(state, &card->dvb_adapter)) == NULL) { + printk("%s: Could not find a Twinhan DST.\n", __FUNCTION__); + break; + } + card->fe = &state->frontend; + + /* Attach other DST peripherals if any */ + /* Conditional Access device */ + if (state->dst_hw_cap & DST_TYPE_HAS_CA) { + ret = dst_ca_attach(state, &card->dvb_adapter); + } if (card->fe != NULL) { break; } @@ -648,7 +669,7 @@ static int dvb_bt8xx_probe(struct device *dev) case BTTV_PINNACLESAT: card->gpio_mode = 0x0400c060; /* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR, - BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */ + BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */ card->op_sync_orin = 0; card->irq_err_ignore = 0; break; diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h index e9310e3a17a..2923b3b0dd3 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h @@ -31,7 +31,7 @@ #include "bttv.h" #include "mt352.h" #include "sp887x.h" -#include "dst.h" +#include "dst_common.h" #include "nxt6000.h" #include "cx24110.h" #include "or51211.h" -- cgit v1.2.3 From e6ac699a4f991e84b4bcdc07d9dfa8e019cf6116 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:42 -0700 Subject: [PATCH] dvb: DST: add support for Twinhan 200103A add support for the old Twinhan 200103A card (Steffen Motzer) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/dst.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index a28b7351eac..0f42ac90ee2 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -538,7 +538,7 @@ static int dst_type_print (u8 type) Known cards list Satellite ------------------- - + 200103A VP-1020 DST-MOT LG(old), TS=188 VP-1020 DST-03T LG(new), TS=204 @@ -570,6 +570,14 @@ static int dst_type_print (u8 type) */ struct dst_types dst_tlist[] = { + { + .device_id = "200103A", + .offset = 0, + .dst_type = DST_TYPE_IS_SAT, + .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, + .dst_feature = 0 + }, /* obsolete */ + { .device_id = "DST-020", .offset = 0, -- cgit v1.2.3 From 8385e46fbf7c9b80008b915440f256ce88633eeb Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:43 -0700 Subject: [PATCH] dvb: DST: fixed tuning problem fixed a tuning problem for cards based on the old firmware (Steffen Motzer, Manu Abraham) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/dst.c | 57 ++++++++++++++++++++++++------------ drivers/media/dvb/bt8xx/dst_common.h | 6 ++-- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 0f42ac90ee2..f4158567342 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -81,9 +81,7 @@ int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int dprintk("%s: dst_gpio_enb error (err == %i, mask == %02x, enb == %02x)\n", __FUNCTION__, err, mask, enbb); return -EREMOTEIO; } - - msleep(1); - + udelay(1000); /* because complete disabling means no output, no need to do output packet */ if (enbb == 0) return 0; @@ -150,8 +148,7 @@ int rdc_8820_reset(struct dst_state *state) dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); return -1; } - msleep(1); - + udelay(1000); if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, RDC_8820_RESET, DELAY) < 0) { dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); return -1; @@ -167,8 +164,7 @@ int dst_pio_enable(struct dst_state *state) dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); return -1; } - msleep(1); - + udelay(1000); return 0; } EXPORT_SYMBOL(dst_pio_enable); @@ -179,6 +175,8 @@ int dst_pio_disable(struct dst_state *state) dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); return -1; } + if (state->type_flags & DST_TYPE_HAS_FW_1) + udelay(1000); return 0; } @@ -200,7 +198,7 @@ int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode) dprintk("%s: dst wait ready after %d\n", __FUNCTION__, i); return 1; } - msleep(1); + msleep(35); } if (verbose > 1) dprintk("%s: dst wait NOT ready after %d\n", __FUNCTION__, i); @@ -245,6 +243,11 @@ int dst_comm_init(struct dst_state* state) dprintk("%s: RDC 8820 State RESET Failed.\n", __FUNCTION__); return -1; } + if (state->type_flags & DST_TYPE_HAS_FW_1) + msleep(100); + else + msleep(5); + return 0; } EXPORT_SYMBOL(dst_comm_init); @@ -328,8 +331,9 @@ static int dst_set_freq(struct dst_state *state, u32 freq) u8 *val; state->frequency = freq; + if (debug > 4) + dprintk("%s: set Frequency %u\n", __FUNCTION__, freq); - // dprintk("%s: set frequency %u\n", __FUNCTION__, freq); if (state->dst_type == DST_TYPE_IS_SAT) { freq = freq / 1000; if (freq < 950 || freq > 2150) @@ -452,7 +456,8 @@ static int dst_set_symbolrate(struct dst_state* state, u32 srate) if (state->dst_type == DST_TYPE_IS_TERR) { return 0; } - // dprintk("%s: set srate %u\n", __FUNCTION__, srate); + if (debug > 4) + dprintk("%s: set symrate %u\n", __FUNCTION__, srate); srate /= 1000; val = &state->tx_tuna[0]; @@ -461,7 +466,10 @@ static int dst_set_symbolrate(struct dst_state* state, u32 srate) sval <<= 20; do_div(sval, 88000); symcalc = (u32) sval; - // dprintk("%s: set symcalc %u\n", __FUNCTION__, symcalc); + + if (debug > 4) + dprintk("%s: set symcalc %u\n", __FUNCTION__, symcalc); + val[5] = (u8) (symcalc >> 12); val[6] = (u8) (symcalc >> 4); val[7] = (u8) (symcalc << 4); @@ -504,6 +512,7 @@ static void dst_type_flags_print(u32 type_flags) printk(" 0x%x firmware version = 2", DST_TYPE_HAS_FW_2); if (type_flags & DST_TYPE_HAS_FW_3) printk(" 0x%x firmware version = 3", DST_TYPE_HAS_FW_3); +// if ((type_flags & DST_TYPE_HAS_FW_BUILD) && new_fw) printk("\n"); } @@ -617,13 +626,13 @@ struct dst_types dst_tlist[] = { .dst_type = DST_TYPE_IS_SAT, .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1, .dst_feature = DST_TYPE_HAS_CA - }, /* unknown to vendor */ + }, /* An OEM board */ { .device_id = "DSTMCI", .offset = 1, .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2, + .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD, .dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC }, @@ -640,7 +649,8 @@ struct dst_types dst_tlist[] = { .device_id = "DCT-CI", .offset = 1, .dst_type = DST_TYPE_IS_CABLE, - .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_FW_2, + .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1 + | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD, .dst_feature = DST_TYPE_HAS_CA }, @@ -656,7 +666,7 @@ struct dst_types dst_tlist[] = { .device_id = "DTT-CI", .offset = 1, .dst_type = DST_TYPE_IS_TERR, - .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2, + .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD, .dst_feature = 0 }, @@ -782,7 +792,7 @@ static int dst_probe(struct dst_state *state) dprintk("%s: DST Initialization Failed.\n", __FUNCTION__); return -1; } - + msleep(100); if (dst_get_device_id(state) < 0) { dprintk("%s: unknown device.\n", __FUNCTION__); return -1; @@ -812,6 +822,8 @@ int dst_command(struct dst_state* state, u8 * data, u8 len) dprintk("%s: PIO Disable Failed.\n", __FUNCTION__); return -1; } + if (state->type_flags & DST_TYPE_HAS_FW_1) + udelay(3000); if (read_dst(state, &reply, GET_ACK)) { if (verbose > 1) @@ -829,6 +841,13 @@ int dst_command(struct dst_state* state, u8 * data, u8 len) } if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3)) return 0; + +// udelay(3000); + if (state->type_flags & DST_TYPE_HAS_FW_1) + udelay(3000); + else + udelay(2000); + if (!dst_wait_dst_ready(state, NO_DELAY)) return -1; @@ -919,8 +938,6 @@ static int dst_get_tuna(struct dst_state* state) if (!dst_wait_dst_ready(state, NO_DELAY)) return 0; - msleep(10); - if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { /* how to get variable length reply ???? */ retval = read_dst(state, state->rx_tuna, 10); @@ -969,7 +986,9 @@ static int dst_write_tuna(struct dvb_frontend* fe) int retval; u8 reply; - dprintk("%s: type_flags 0x%x \n", __FUNCTION__, state->type_flags); + if (debug > 4) + dprintk("%s: type_flags 0x%x \n", __FUNCTION__, state->type_flags); + state->decode_freq = 0; state->decode_lock = state->decode_strength = state->decode_snr = 0; if (state->dst_type == DST_TYPE_IS_SAT) { diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h index 10046d6292b..e3b59f16c7a 100644 --- a/drivers/media/dvb/bt8xx/dst_common.h +++ b/drivers/media/dvb/bt8xx/dst_common.h @@ -46,7 +46,7 @@ #define DST_TYPE_HAS_FW_1 8 #define DST_TYPE_HAS_FW_2 16 #define DST_TYPE_HAS_FW_3 32 - +#define DST_TYPE_HAS_FW_BUILD 64 /* Card capability list */ @@ -117,8 +117,8 @@ struct dst_types { char *device_id; int offset; u8 dst_type; - u32 type_flags; - u8 dst_feature; + u64 type_flags; + u64 dst_feature; }; -- cgit v1.2.3 From b46dd4456f87fbad634d9a63d607fc54e4381cb4 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:44 -0700 Subject: [PATCH] dvb: DST: fix for descrambling failure fix for descrambling failure (Dominique Dumont, Manu Abraham) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/dst.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index f4158567342..fc74f409785 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -198,7 +198,7 @@ int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode) dprintk("%s: dst wait ready after %d\n", __FUNCTION__, i); return 1; } - msleep(35); + msleep(10); } if (verbose > 1) dprintk("%s: dst wait NOT ready after %d\n", __FUNCTION__, i); -- cgit v1.2.3 From 4a2cc1269b6c1404e6e882cee604d55c90927467 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:45 -0700 Subject: [PATCH] dvb: DST: misc. fixes removed unused module parameter session removed unnecesary delay for FTA cards (Manu Abraham) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/dst.c | 14 ++++++-------- drivers/media/dvb/bt8xx/dst_ca.c | 19 ++++++------------- drivers/media/dvb/bt8xx/dst_common.h | 8 ++++---- 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index fc74f409785..d047e349d70 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -44,13 +44,7 @@ MODULE_PARM_DESC(debug, "debug messages, default is 0 (yes)"); static unsigned int dst_addons; module_param(dst_addons, int, 0644); -MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (no)"); - -static unsigned int new_fw; -module_param(new_fw, int, 0644); -MODULE_PARM_DESC(new_fw, "Support for the new interface firmware, default 0"); - - +MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)"); #define dprintk if (debug) printk @@ -787,7 +781,11 @@ static int dst_probe(struct dst_state *state) dprintk("%s: RDC 8820 RESET Failed.\n", __FUNCTION__); return -1; } - msleep(4000); + if (dst_addons & DST_TYPE_HAS_CA) + msleep(4000); + else + msleep(100); + if ((dst_comm_init(state)) < 0) { dprintk("%s: DST Initialization Failed.\n", __FUNCTION__); return -1; diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c index 206aee3336b..9160bdf479a 100644 --- a/drivers/media/dvb/bt8xx/dst_ca.c +++ b/drivers/media/dvb/bt8xx/dst_ca.c @@ -40,23 +40,16 @@ static unsigned int debug = 1; module_param(debug, int, 0644); MODULE_PARM_DESC(dst_ca_debug, "debug messages, default is 0 (yes)"); -static unsigned int session; -module_param(session, int, 0644); -MODULE_PARM_DESC(session, "Support for hardware that has multiple sessions, default 0"); - -static unsigned int new_ca; -module_param(new_ca, int, 0644); -MODULE_PARM_DESC(new_ca, "Support for the new CA interface firmware, default 0"); - #define dprintk if (debug) printk - +/* Need some more work */ static int ca_set_slot_descr(void) { /* We could make this more graceful ? */ return -EOPNOTSUPP; } +/* Need some more work */ static int ca_set_pid(void) { /* We could make this more graceful ? */ @@ -213,7 +206,7 @@ static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, return 0; } - +/* Need some more work */ static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void *arg) { return -EOPNOTSUPP; @@ -302,9 +295,9 @@ static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, return 0; } -static int handle_en50221_tag(struct ca_msg *p_ca_message, struct ca_msg *hw_buffer) +static int handle_en50221_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer) { - if (session) { + if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) { hw_buffer->msg[2] = p_ca_message->msg[1]; /* MSB */ hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */ } @@ -351,7 +344,7 @@ static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, stru if (verbose > 3) dprintk("%s, p_ca_message length %d (0x%x)\n", __FUNCTION__,p_ca_message->length,p_ca_message->length ); - handle_en50221_tag(p_ca_message, hw_buffer); /* EN50221 tag */ + handle_en50221_tag(state, p_ca_message, hw_buffer); /* EN50221 tag */ /* Handle the length field (variable) */ if (!(p_ca_message->msg[3] & 0x80)) { /* Length = 1 */ diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h index e3b59f16c7a..0b3da29245f 100644 --- a/drivers/media/dvb/bt8xx/dst_common.h +++ b/drivers/media/dvb/bt8xx/dst_common.h @@ -48,7 +48,6 @@ #define DST_TYPE_HAS_FW_3 32 #define DST_TYPE_HAS_FW_BUILD 64 - /* Card capability list */ #define DST_TYPE_HAS_MAC 1 @@ -58,6 +57,7 @@ #define DST_TYPE_HAS_MOTO 16 #define DST_TYPE_HAS_CA 32 #define DST_TYPE_HAS_ANALOG 64 /* Analog inputs */ +#define DST_TYPE_HAS_SESSION 128 #define RDC_8820_PIO_0_DISABLE 0 @@ -107,7 +107,7 @@ struct dst_state { unsigned long cur_jiff; u8 k22; fe_bandwidth_t bandwidth; - u8 dst_hw_cap; + u32 dst_hw_cap; u8 dst_fw_version; fe_sec_mini_cmd_t minicmd; u8 messages[256]; @@ -117,8 +117,8 @@ struct dst_types { char *device_id; int offset; u8 dst_type; - u64 type_flags; - u64 dst_feature; + u32 type_flags; + u32 dst_feature; }; -- cgit v1.2.3 From df481ae59074756f1d0b2712d8b3fe8d04eb16c1 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:45 -0700 Subject: [PATCH] dvb: bt8xx: updated documentation updated documentation (Manu Abraham) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/dvb/bt8xx.txt | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/Documentation/dvb/bt8xx.txt b/Documentation/dvb/bt8xx.txt index d84df8072d7..d64430bf4bb 100644 --- a/Documentation/dvb/bt8xx.txt +++ b/Documentation/dvb/bt8xx.txt @@ -35,45 +35,35 @@ TwinHan (dst) are loaded automatically by the dvb-bt8xx device driver. $ modprobe bttv (normally bttv is being loaded automatically by kmod) $ modprobe dvb-bt8xx (or just place dvb-bt8xx in /etc/modules for automatic loading) -3b) TwinHan ------------ + +3b) TwinHan and Clones +-------------------------- $ modprobe bttv i2c_hw=1 card=0x71 $ modprobe dvb-bt8xx $ modprobe dst -The value 0x71 will override the PCI type detection for dvb-bt8xx, which -is necessary for TwinHan cards.# +The value 0x71 will override the PCI type detection for dvb-bt8xx, +which is necessary for TwinHan cards. -If you're having an older card (blue color circuit) and card=0x71 locks your -machine, try using 0x68, too. If that does not work, ask on the DVB mailing list. +If you're having an older card (blue color circuit) and card=0x71 locks +your machine, try using 0x68, too. If that does not work, ask on the +mailing list. -The DST module takes a couple of useful parameters, in case the -dst drivers fails to detect your type of card correctly. +The DST module takes a couple of useful parameters. -dst_type takes values 0 (satellite), 1 (terrestial TV), 2 (cable). +verbose takes values 0 to 5. These values control the verbosity level. -dst_type_flags takes bit combined values: -1 = new tuner type packets. You can use this if your card is detected - and you have debug and you continually see the tuner packets not - working (make sure not a basic problem like dish alignment etc.) +debug takes values 0 and 1. You can either disable or enable debugging. -2 = TS 204. If your card tunes OK, but the picture is terrible, seemingly - breaking up in one half continually, and crc fails a lot, then - this is worth a try (or trying to turn off) +dst_addons takes values 0 and 0x20. A value of 0 means it is a FTA card. +0x20 means it has a Conditional Access slot. -4 = has symdiv. Some cards, mostly without new tuner packets, require - a symbol division algorithm. Doesn't apply to terrestial TV. - -You can also specify a value to have the autodetected values turned off -(e.g. 0). The autodected values are determined bythe cards 'response +The autodected values are determined bythe cards 'response string' which you can see in your logs e.g. -dst_check_ci: recognize DST-MOT - -or +dst_get_device_id: Recognise [DSTMCI] -dst_check_ci: unable to recognize DSTXCI or STXCI -- -Authors: Richard Walker, Jamie Honan, Michael Hunold +Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham -- cgit v1.2.3 From 42dc6617fe41ea65a94399821058353d0b12c0ab Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:47 -0700 Subject: [PATCH] dvb: DST: fix a bug in the module parameter fix a bug in the module parameter (Dominique Dumont) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/dst_ca.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c index 9160bdf479a..0945bb97871 100644 --- a/drivers/media/dvb/bt8xx/dst_ca.c +++ b/drivers/media/dvb/bt8xx/dst_ca.c @@ -38,7 +38,7 @@ MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); static unsigned int debug = 1; module_param(debug, int, 0644); -MODULE_PARM_DESC(dst_ca_debug, "debug messages, default is 0 (yes)"); +MODULE_PARM_DESC(debug, "debug messages, default is 1 (yes)"); #define dprintk if (debug) printk -- cgit v1.2.3 From b98b79da032584b4c077568d28dde2d2fe226b54 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:47 -0700 Subject: [PATCH] dvb: DST: fixed CI debug output fixed CI debug output (Dominique Dumont) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/dst_ca.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c index 0945bb97871..d781504cc2f 100644 --- a/drivers/media/dvb/bt8xx/dst_ca.c +++ b/drivers/media/dvb/bt8xx/dst_ca.c @@ -162,7 +162,7 @@ static int ca_get_app_info(struct dst_state *state) dprintk("%s: ================================ CI Module Application Info ======================================\n", __FUNCTION__); dprintk("%s: Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]\n", __FUNCTION__, state->messages[7], (state->messages[8] << 8) | state->messages[9], - (state->messages[10] << 8) | state->messages[11], __FUNCTION__, (char *)(&state->messages[11])); + (state->messages[10] << 8) | state->messages[11], __FUNCTION__, (char *)(&state->messages[12])); dprintk("%s: ==================================================================================================\n", __FUNCTION__); } -- cgit v1.2.3 From 43f1a8f8c09aa1e368157039715812139a023d20 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:49 -0700 Subject: [PATCH] dvb: bt8xx: whitespace cleanup whitespace cleanup Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/bt878.c | 36 ++++++++++++++++++------------------ drivers/media/dvb/bt8xx/bt878.h | 6 +++--- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c index 7e51530b587..3c5a8e273c4 100644 --- a/drivers/media/dvb/bt8xx/bt878.c +++ b/drivers/media/dvb/bt8xx/bt878.c @@ -12,19 +12,19 @@ * 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. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - * + * */ #include @@ -58,7 +58,7 @@ module_param_named(verbose, bt878_verbose, int, 0444); MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); module_param_named(debug, bt878_debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); +MODULE_PARM_DESC(debug, "Turn on/off debugging, default is 0 (off)."); int bt878_num; struct bt878 bt878[BT878_MAX]; @@ -128,21 +128,21 @@ static int bt878_mem_alloc(struct bt878 *bt) } /* RISC instructions */ -#define RISC_WRITE (0x01 << 28) -#define RISC_JUMP (0x07 << 28) -#define RISC_SYNC (0x08 << 28) +#define RISC_WRITE (0x01 << 28) +#define RISC_JUMP (0x07 << 28) +#define RISC_SYNC (0x08 << 28) /* RISC bits */ -#define RISC_WR_SOL (1 << 27) -#define RISC_WR_EOL (1 << 26) -#define RISC_IRQ (1 << 24) +#define RISC_WR_SOL (1 << 27) +#define RISC_WR_EOL (1 << 26) +#define RISC_IRQ (1 << 24) #define RISC_STATUS(status) ((((~status) & 0x0F) << 20) | ((status & 0x0F) << 16)) -#define RISC_SYNC_RESYNC (1 << 15) -#define RISC_SYNC_FM1 0x06 -#define RISC_SYNC_VRO 0x0C +#define RISC_SYNC_RESYNC (1 << 15) +#define RISC_SYNC_FM1 0x06 +#define RISC_SYNC_VRO 0x0C #define RISC_FLUSH() bt->risc_pos = 0 -#define RISC_INSTR(instr) bt->risc_cpu[bt->risc_pos++] = cpu_to_le32(instr) +#define RISC_INSTR(instr) bt->risc_cpu[bt->risc_pos++] = cpu_to_le32(instr) static int bt878_make_risc(struct bt878 *bt) { @@ -173,7 +173,7 @@ static void bt878_risc_program(struct bt878 *bt, u32 op_sync_orin) RISC_INSTR(RISC_SYNC | RISC_SYNC_FM1 | op_sync_orin); RISC_INSTR(0); - dprintk("bt878: risc len lines %u, bytes per line %u\n", + dprintk("bt878: risc len lines %u, bytes per line %u\n", bt->line_count, bt->line_bytes); for (line = 0; line < bt->line_count; line++) { // At the beginning of every block we issue an IRQ with previous (finished) block number set @@ -228,14 +228,14 @@ void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin, * Hacked for DST to: * SCERR | OCERR | FDSR | FTRGT | FBUS | RISCI */ - int_mask = BT878_ASCERR | BT878_AOCERR | BT878_APABORT | - BT878_ARIPERR | BT878_APPERR | BT878_AFDSR | BT878_AFTRGT | + int_mask = BT878_ASCERR | BT878_AOCERR | BT878_APABORT | + BT878_ARIPERR | BT878_APPERR | BT878_AFDSR | BT878_AFTRGT | BT878_AFBUS | BT878_ARISCI; /* ignore pesky bits */ int_mask &= ~irq_err_ignore; - + btwrite(int_mask, BT878_AINT_MASK); btwrite(controlreg, BT878_AGPIO_DMA_CTL); } diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h index e1b9809d1b0..837623f7fcd 100644 --- a/drivers/media/dvb/bt8xx/bt878.h +++ b/drivers/media/dvb/bt8xx/bt878.h @@ -1,4 +1,4 @@ -/* +/* bt878.h - Bt878 audio module (register offsets) Copyright (C) 2002 Peter Hettkamp @@ -120,14 +120,14 @@ struct bt878 { u32 risc_pos; struct tasklet_struct tasklet; - int shutdown; + int shutdown; }; extern struct bt878 bt878[BT878_MAX]; void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin, u32 irq_err_ignore); -void bt878_stop(struct bt878 *bt); +void bt878_stop(struct bt878 *bt); #if defined(__powerpc__) /* big-endian */ extern __inline__ void io_st_le32(volatile unsigned __iomem *addr, unsigned val) -- cgit v1.2.3 From b82a96a7f28b9939576bf79a817c7a238d784b47 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 16 May 2005 21:54:49 -0700 Subject: [PATCH] dvb: budget-av: CI fixes - remove enable_ci, ci interface is assumed to be present if the saa7113 is not found. - reduce the delay when checking for saa7113 - clean up the cam reset according to specifications - turn off Vcc to the cam slot if cam is removed or fails reset - remove cam reset in ciintf_init - clean up printks (KERN_) - move gpio setting into saa7113_init - clean up unreadable frontend_init (Kenneth Aafloy) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/budget-av.c | 216 ++++++++++++++++++++---------------- 1 file changed, 118 insertions(+), 98 deletions(-) diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 7891f3f06f0..6e0f5d307c5 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -59,8 +59,12 @@ struct budget_av { struct dvb_ca_en50221 ca; }; -static int enable_ci = 0; - +/* GPIO CI Connections: + * 0 - Vcc/Reset (Reset is controlled by capacitor) + * 1 - Attribute Memory + * 2 - Card Enable (Active Low) + * 3 - Card Detect + */ /**************************************************************************** * INITIALIZATION @@ -188,22 +192,35 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) { struct budget_av *budget_av = (struct budget_av *) ca->data; struct saa7146_dev *saa = budget_av->budget.dev; - int max = 20; + int timeout = 50; // 5 seconds (4.4.6 Ready) if (slot != 0) return -EINVAL; dprintk(1, "ciintf_slot_reset\n"); - /* reset the card */ - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); - msleep(100); - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); + saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ - while (--max > 0 && ciintf_read_attribute_mem(ca, slot, 0) != 0x1d) + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */ + msleep(2); + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); /* Vcc on */ + msleep(20); /* 20 ms Vcc settling time */ + + saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */ + + /* This should have been based on pin 16 READY of the pcmcia port, + * but AFAICS it is not routed to the saa7146 */ + while (--timeout > 0 && ciintf_read_attribute_mem(ca, slot, 0) != 0x1d) msleep(100); - ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); + if (timeout <= 0) + { + printk(KERN_ERR "budget-av: cam reset failed (timeout).\n"); + saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */ + return -ETIMEDOUT; + } + return 0; } @@ -240,7 +257,6 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open { struct budget_av *budget_av = (struct budget_av *) ca->data; struct saa7146_dev *saa = budget_av->budget.dev; - int cam = 0; if (slot != 0) return -EINVAL; @@ -248,15 +264,21 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open if (!budget_av->slot_status) { saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); udelay(1); - cam = saa7146_read(saa, PSR) & MASK_06; - saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); - - if (cam) + if (saa7146_read(saa, PSR) & MASK_06) + { + printk(KERN_INFO "budget-av: cam inserted\n"); budget_av->slot_status = 1; + } + saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); } else if (!open) { saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT) + { + printk(KERN_INFO "budget-av: cam ejected\n"); + saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */ budget_av->slot_status = 0; + } } if (budget_av->slot_status == 1) @@ -272,17 +294,11 @@ static int ciintf_init(struct budget_av *budget_av) memset(&budget_av->ca, 0, sizeof(struct dvb_ca_en50221)); - /* setup GPIOs */ - saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI); + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); + saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO); saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); - /* Reset the card */ - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); - msleep(50); - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); - msleep(100); - /* Enable DEBI pins */ saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800); @@ -297,13 +313,14 @@ static int ciintf_init(struct budget_av *budget_av) budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable; budget_av->ca.poll_slot_status = ciintf_poll_slot_status; budget_av->ca.data = budget_av; + if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter, &budget_av->ca, 0, 1)) != 0) { - printk("budget_av: CI interface detected, but initialisation failed.\n"); + printk(KERN_ERR "budget-av: ci initialisation failed.\n"); goto error; } - // success! - printk("ciintf_init: CI interface initialised\n"); + + printk(KERN_INFO "budget-av: ci interface initialised.\n"); budget_av->budget.ci_present = 1; return 0; @@ -361,8 +378,12 @@ static const u8 saa7113_tab[] = { static int saa7113_init(struct budget_av *budget_av) { struct budget *budget = &budget_av->budget; + struct saa7146_dev *saa = budget->dev; const u8 *data = saa7113_tab; + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); + msleep(200); + if (i2c_writereg(&budget->i2c_adap, 0x4a, 0x01, 0x08) != 1) { dprintk(1, "saa7113 not found on KNC card\n"); return -ENODEV; @@ -697,82 +718,90 @@ static u8 read_pwm(struct budget_av *budget_av) return pwm; } +#define SUBID_DVBS_KNC1 0x0010 +#define SUBID_DVBS_KNC1_PLUS 0x0011 +#define SUBID_DVBS_TYPHOON 0x4f56 +#define SUBID_DVBS_CINERGY1200 0x1154 + +#define SUBID_DVBC_KNC1 0x0020 +#define SUBID_DVBC_KNC1_PLUS 0x0021 +#define SUBID_DVBC_CINERGY1200 0x1156 + +#define SUBID_DVBT_KNC1_PLUS 0x0031 +#define SUBID_DVBT_KNC1 0x0030 +#define SUBID_DVBT_CINERGY1200 0x1157 static void frontend_init(struct budget_av *budget_av) { - switch (budget_av->budget.dev->pci->subsystem_device) { - case 0x0011: // KNC1 DVB-S Plus budget with AV IN (stv0299/Philips SU1278(tsa5059)) - saa7146_write(budget_av->budget.dev, GPIO_CTRL, 0x50000000); // Enable / PowerON Frontend - case 0x4f56: // Typhoon/KNC1 DVB-S budget (stv0299/Philips SU1278(tsa5059)) - case 0x0010: // KNC1 DVB-S budget (stv0299/Philips SU1278(tsa5059)) - budget_av->budget.dvb_frontend = - stv0299_attach(&typhoon_config, &budget_av->budget.i2c_adap); - if (budget_av->budget.dvb_frontend != NULL) { + struct saa7146_dev * saa = budget_av->budget.dev; + struct dvb_frontend * fe = NULL; + + switch (saa->pci->subsystem_device) { + case SUBID_DVBS_KNC1_PLUS: + case SUBID_DVBC_KNC1_PLUS: + case SUBID_DVBT_KNC1_PLUS: + // Enable / PowerON Frontend + saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI); break; - } + } + + switch (saa->pci->subsystem_device) { + + case SUBID_DVBS_KNC1: + case SUBID_DVBS_KNC1_PLUS: + case SUBID_DVBS_TYPHOON: + fe = stv0299_attach(&typhoon_config, + &budget_av->budget.i2c_adap); break; - case 0x0021: // KNC1 DVB-C Plus budget with AV IN (tda10021/Philips CU1216(tua6034)) - saa7146_write(budget_av->budget.dev, GPIO_CTRL, 0x50000000); // Enable / PowerON Frontend - case 0x0020: // KNC1 DVB-C budget (tda10021/Philips CU1216(tua6034)) - budget_av->budget.dvb_frontend = - tda10021_attach(&philips_cu1216_config, - &budget_av->budget.i2c_adap, read_pwm(budget_av)); - if (budget_av->budget.dvb_frontend != NULL) { - break; - } + case SUBID_DVBS_CINERGY1200: + fe = stv0299_attach(&cinergy_1200s_config, + &budget_av->budget.i2c_adap); break; - case 0x0031: // KNC1 DVB-T Plus budget with AV IN (tda10046/Philips TU1216(tda6651tt)) - saa7146_write(budget_av->budget.dev, GPIO_CTRL, 0x50000000); // Enable / PowerON Frontend - case 0x0030: // KNC1 DVB-T budget (tda10046/Philips TU1216(tda6651tt)) - budget_av->budget.dvb_frontend = - tda10046_attach(&philips_tu1216_config, &budget_av->budget.i2c_adap); - if (budget_av->budget.dvb_frontend != NULL) { - break; - } + case SUBID_DVBC_KNC1: + case SUBID_DVBC_KNC1_PLUS: + fe = tda10021_attach(&philips_cu1216_config, + &budget_av->budget.i2c_adap, + read_pwm(budget_av)); break; - case 0x1154: // TerraTec Cinergy 1200 DVB-S (stv0299/Philips SU1278(tsa5059)) - budget_av->budget.dvb_frontend = - stv0299_attach(&cinergy_1200s_config, &budget_av->budget.i2c_adap); - if (budget_av->budget.dvb_frontend != NULL) { - break; - } + case SUBID_DVBT_KNC1: + case SUBID_DVBT_KNC1_PLUS: + fe = tda10046_attach(&philips_tu1216_config, + &budget_av->budget.i2c_adap); break; - case 0x1156: // Terratec Cinergy 1200 DVB-C (tda10021/Philips CU1216(tua6034)) - budget_av->budget.dvb_frontend = - tda10021_attach(&philips_cu1216_config, - &budget_av->budget.i2c_adap, read_pwm(budget_av)); - if (budget_av->budget.dvb_frontend) { - break; - } + case SUBID_DVBC_CINERGY1200: + fe = tda10021_attach(&philips_cu1216_config, + &budget_av->budget.i2c_adap, + read_pwm(budget_av)); break; - case 0x1157: // Terratec Cinergy 1200 DVB-T (tda10046/Philips TU1216(tda6651tt)) - budget_av->budget.dvb_frontend = - tda10046_attach(&philips_tu1216_config, &budget_av->budget.i2c_adap); - if (budget_av->budget.dvb_frontend) { - break; - } + case SUBID_DVBT_CINERGY1200: + fe = tda10046_attach(&philips_tu1216_config, + &budget_av->budget.i2c_adap); break; } - if (budget_av->budget.dvb_frontend == NULL) { - printk("budget_av: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", - budget_av->budget.dev->pci->vendor, - budget_av->budget.dev->pci->device, - budget_av->budget.dev->pci->subsystem_vendor, - budget_av->budget.dev->pci->subsystem_device); - } else { - if (dvb_register_frontend - (&budget_av->budget.dvb_adapter, budget_av->budget.dvb_frontend)) { - printk("budget-av: Frontend registration failed!\n"); - if (budget_av->budget.dvb_frontend->ops->release) - budget_av->budget.dvb_frontend->ops->release(budget_av->budget.dvb_frontend); - budget_av->budget.dvb_frontend = NULL; - } + if (fe == NULL) { + printk(KERN_ERR "budget-av: A frontend driver was not found " + "for device %04x/%04x subsystem %04x/%04x\n", + saa->pci->vendor, + saa->pci->device, + saa->pci->subsystem_vendor, + saa->pci->subsystem_device); + return; + } + + budget_av->budget.dvb_frontend = fe; + + if (dvb_register_frontend(&budget_av->budget.dvb_adapter, + budget_av->budget.dvb_frontend)) { + printk(KERN_ERR "budget-av: Frontend registration failed!\n"); + if (budget_av->budget.dvb_frontend->ops->release) + budget_av->budget.dvb_frontend->ops->release(budget_av->budget.dvb_frontend); + budget_av->budget.dvb_frontend = NULL; } } @@ -829,6 +858,7 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio memset(budget_av, 0, sizeof(struct budget_av)); + budget_av->has_saa7113 = 0; budget_av->budget.ci_present = 0; dev->ext_priv = budget_av; @@ -843,10 +873,7 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio saa7146_write(dev, DD1_INIT, 0x07000600); saa7146_write(dev, MC2, MASK_09 | MASK_25 | MASK_10 | MASK_26); - saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI); - msleep(500); - - if (0 == saa7113_init(budget_av)) { + if (saa7113_init(budget_av) == 0) { budget_av->has_saa7113 = 1; if (0 != saa7146_vv_init(dev, &vv_data)) { @@ -867,9 +894,7 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio saa7113_setinput(budget_av, 0); } else { - budget_av->has_saa7113 = 0; - - saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO); + ciintf_init(budget_av); } /* fixme: find some sane values here... */ @@ -877,11 +902,11 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio mac = budget_av->budget.dvb_adapter.proposed_mac; if (i2c_readregs(&budget_av->budget.i2c_adap, 0xa0, 0x30, mac, 6)) { - printk("KNC1-%d: Could not read MAC from KNC1 card\n", + printk(KERN_ERR "KNC1-%d: Could not read MAC from KNC1 card\n", budget_av->budget.dvb_adapter.num); memset(mac, 0, 6); } else { - printk("KNC1-%d: MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", + printk(KERN_INFO "KNC1-%d: MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", budget_av->budget.dvb_adapter.num, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } @@ -889,9 +914,6 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio budget_av->budget.dvb_adapter.priv = budget_av; frontend_init(budget_av); - if (enable_ci) - ciintf_init(budget_av); - return 0; } @@ -1024,5 +1046,3 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others"); MODULE_DESCRIPTION("driver for the SAA7146 based so-called " "budget PCI DVB w/ analog input and CI-module (e.g. the KNC cards)"); -module_param_named(enable_ci, enable_ci, int, 0644); -MODULE_PARM_DESC(enable_ci, "Turn on/off CI module (default:off)."); -- cgit v1.2.3 From 19bbdf0e510471ecebb3fe09bd8b00773cc63b88 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 17 May 2005 16:48:39 +1000 Subject: [PATCH] ppc32: enable use of early_param We need to call parse_early_param() early on to allow usage of early_param() for command line parsing. Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras Signed-off-by: Linus Torvalds --- arch/ppc/kernel/setup.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 5dfb42f1a15..309797d7f96 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -753,6 +753,8 @@ void __init setup_arch(char **cmdline_p) strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); *cmdline_p = cmd_line; + parse_early_param(); + /* set up the bootmem stuff with available memory */ do_init_bootmem(); if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab); -- cgit v1.2.3 From 8c41a5f50deab01aca11155154d7e6737b3a1d9f Mon Sep 17 00:00:00 2001 From: randy_dunlap Date: Tue, 17 May 2005 07:12:56 -0700 Subject: [PATCH] update CREDITS free agent Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- CREDITS | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CREDITS b/CREDITS index 3b9e160d6f7..9bd099d960f 100644 --- a/CREDITS +++ b/CREDITS @@ -882,13 +882,12 @@ S: Blacksburg, Virginia 24061 S: USA N: Randy Dunlap -E: rddunlap@osdl.org +E: rdunlap@xenotime.net W: http://www.xenotime.net/linux/linux.html W: http://www.linux-usb.org D: Linux-USB subsystem, USB core/UHCI/printer/storage drivers D: x86 SMP, ACPI, bootflag hacking -S: 12725 SW Millikan Way, Suite 400 -S: Beaverton, Oregon 97005 +S: (ask for current address) S: USA N: Bob Dunlop -- cgit v1.2.3 From ff0d2f90fdc4b564d47a7c26b16de81a16cfa28e Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Tue, 17 May 2005 08:48:16 -0700 Subject: [PATCH] fix memory scribble in arch/i386/pci/fixup.c The GET_INDEX() macro should use just the low three bits of the devfn, otherwise we have a memory scribble in pcie_rootport_aspm_quirk that overwrites ptype_all Fix it to be more careful about its arguments while at it. Acked by Dely Sy Signed-off-by: Linus Torvalds --- arch/i386/pci/fixup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c index be52c5ac4e0..8e8e895e1b5 100644 --- a/arch/i386/pci/fixup.c +++ b/arch/i386/pci/fixup.c @@ -253,7 +253,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2, pci #define MAX_PCIEROOT 6 static int quirk_aspm_offset[MAX_PCIEROOT << 3]; -#define GET_INDEX(a, b) (((a - PCI_DEVICE_ID_INTEL_MCH_PA) << 3) + b) +#define GET_INDEX(a, b) ((((a) - PCI_DEVICE_ID_INTEL_MCH_PA) << 3) + ((b) & 7)) static int quirk_pcie_aspm_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { -- cgit v1.2.3 From ee17fd93a5892c162b0a02d58cdfdb9c50cf8467 Mon Sep 17 00:00:00 2001 From: Dely Sy Date: Thu, 5 May 2005 11:57:25 -0700 Subject: [PATCH] PCI Hotplug: Fix echoing 1 to power file of enabled slot problem with SHPC driver Here is a patch to fix the problem of echoing 1 to "power" file to enabled slot causing the slot to power down, and echoing 0 to disabled slot causing shpchp_disabled_slot() to be called twice. This problem was reported by kenji Kaneshige. Thanks, Dely Signed-off-by: Dely Sy Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_core.c | 2 +- drivers/pci/hotplug/shpchp_ctrl.c | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index f0c53f850ae..a70a5c5705f 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -95,7 +95,7 @@ static struct hotplug_slot_ops shpchp_hotplug_slot_ops = { */ static void release_slot(struct hotplug_slot *hotplug_slot) { - struct slot *slot = (struct slot *)hotplug_slot->private; + struct slot *slot = hotplug_slot->private; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 9f90eb8e6ec..490a9553a06 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -1885,7 +1885,7 @@ int shpchp_enable_slot (struct slot *p_slot) func = shpchp_slot_find(p_slot->bus, p_slot->device, 0); if (!func) { dbg("%s: Error! slot NULL\n", __FUNCTION__); - return 1; + return -ENODEV; } /* Check to see if (latch closed, card present, power off) */ @@ -1894,19 +1894,19 @@ int shpchp_enable_slot (struct slot *p_slot) if (rc || !getstatus) { info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return 1; + return -ENODEV; } rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return 1; + return -ENODEV; } rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return 1; + return -ENODEV; } up(&p_slot->ctrl->crit_sect); @@ -1914,7 +1914,7 @@ int shpchp_enable_slot (struct slot *p_slot) func = shpchp_slot_create(p_slot->bus); if (func == NULL) - return 1; + return -ENOMEM; func->bus = p_slot->bus; func->device = p_slot->device; @@ -1939,7 +1939,7 @@ int shpchp_enable_slot (struct slot *p_slot) /* Setup slot structure with entry for empty slot */ func = shpchp_slot_create(p_slot->bus); if (func == NULL) - return (1); /* Out of memory */ + return -ENOMEM; /* Out of memory */ func->bus = p_slot->bus; func->device = p_slot->device; @@ -1972,7 +1972,7 @@ int shpchp_disable_slot (struct slot *p_slot) struct pci_func *func; if (!p_slot->ctrl) - return 1; + return -ENODEV; pci_bus = p_slot->ctrl->pci_dev->subordinate; @@ -1983,19 +1983,19 @@ int shpchp_disable_slot (struct slot *p_slot) if (ret || !getstatus) { info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return 1; + return -ENODEV; } ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (ret || getstatus) { info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return 1; + return -ENODEV; } ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (ret || !getstatus) { info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return 1; + return -ENODEV; } up(&p_slot->ctrl->crit_sect); @@ -2011,7 +2011,7 @@ int shpchp_disable_slot (struct slot *p_slot) /* Check the Class Code */ rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); if (rc) - return rc; + return -ENODEV; if (class_code == PCI_BASE_CLASS_DISPLAY) { /* Display/Video adapter (not supported) */ @@ -2020,13 +2020,13 @@ int shpchp_disable_slot (struct slot *p_slot) /* See if it's a bridge */ rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); if (rc) - return rc; + return -ENODEV; /* If it's a bridge, check the VGA Enable bit */ if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR); if (rc) - return rc; + return -ENODEV; /* If the VGA Enable bit is set, remove isn't supported */ if (BCR & PCI_BRIDGE_CTL_VGA) { @@ -2042,12 +2042,12 @@ int shpchp_disable_slot (struct slot *p_slot) if ((func != NULL) && !rc) { rc = remove_board(func, p_slot->ctrl); } else if (!rc) - rc = 1; + rc = -ENODEV; if (p_slot) update_slot_info(p_slot); - return(rc); + return rc; } -- cgit v1.2.3 From 8b245e45f34280ec61e3c8d643d4613b9e0eb7a4 Mon Sep 17 00:00:00 2001 From: Dely Sy Date: Fri, 6 May 2005 17:19:09 -0700 Subject: [PATCH] PCI Hotplug: get pciehp to work on the downstream port of a switch Here is the updated patch to get pciehp driver to work for downstream port of a switch and handle the difference in the offset value of PCI Express capability list item of different ports. Signed-off-by: Dely Sy Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp.h | 1 + drivers/pci/hotplug/pciehp_core.c | 2 +- drivers/pci/hotplug/pciehp_hpc.c | 156 +++++++++++++++++++------------------- drivers/pci/pcie/portdrv_bus.c | 3 +- 4 files changed, 83 insertions(+), 79 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index f313121d514..46b294a1241 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -130,6 +130,7 @@ struct controller { u8 slot_bus; /* Bus where the slots handled by this controller sit */ u8 ctrlcap; u16 vendor_id; + u8 cap_base; }; struct irq_mapping { diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index ed1fd8d6178..df4915dbc32 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -607,7 +607,7 @@ static int pciehp_resume (struct pcie_device *dev) static struct pcie_port_service_id port_pci_ids[] = { { .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, - .port_type = PCIE_RC_PORT, + .port_type = PCIE_ANY_PORT, .service_type = PCIE_PORT_SERVICE_HP, .driver_data = 0, }, { /* end: all zeroes */ } diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 9e70c4681f7..1cda30bd6e4 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -109,20 +109,20 @@ enum ctrl_offsets { }; static int pcie_cap_base = 0; /* Base of the PCI Express capability item structure */ -#define PCIE_CAP_ID ( pcie_cap_base + PCIECAPID ) -#define NXT_CAP_PTR ( pcie_cap_base + NXTCAPPTR ) -#define CAP_REG ( pcie_cap_base + CAPREG ) -#define DEV_CAP ( pcie_cap_base + DEVCAP ) -#define DEV_CTRL ( pcie_cap_base + DEVCTRL ) -#define DEV_STATUS ( pcie_cap_base + DEVSTATUS ) -#define LNK_CAP ( pcie_cap_base + LNKCAP ) -#define LNK_CTRL ( pcie_cap_base + LNKCTRL ) -#define LNK_STATUS ( pcie_cap_base + LNKSTATUS ) -#define SLOT_CAP ( pcie_cap_base + SLOTCAP ) -#define SLOT_CTRL ( pcie_cap_base + SLOTCTRL ) -#define SLOT_STATUS ( pcie_cap_base + SLOTSTATUS ) -#define ROOT_CTRL ( pcie_cap_base + ROOTCTRL ) -#define ROOT_STATUS ( pcie_cap_base + ROOTSTATUS ) +#define PCIE_CAP_ID(cb) ( cb + PCIECAPID ) +#define NXT_CAP_PTR(cb) ( cb + NXTCAPPTR ) +#define CAP_REG(cb) ( cb + CAPREG ) +#define DEV_CAP(cb) ( cb + DEVCAP ) +#define DEV_CTRL(cb) ( cb + DEVCTRL ) +#define DEV_STATUS(cb) ( cb + DEVSTATUS ) +#define LNK_CAP(cb) ( cb + LNKCAP ) +#define LNK_CTRL(cb) ( cb + LNKCTRL ) +#define LNK_STATUS(cb) ( cb + LNKSTATUS ) +#define SLOT_CAP(cb) ( cb + SLOTCAP ) +#define SLOT_CTRL(cb) ( cb + SLOTCTRL ) +#define SLOT_STATUS(cb) ( cb + SLOTSTATUS ) +#define ROOT_CTRL(cb) ( cb + ROOTCTRL ) +#define ROOT_STATUS(cb) ( cb + ROOTSTATUS ) #define hp_register_read_word(pdev, reg , value) \ pci_read_config_word(pdev, reg, &value) @@ -303,7 +303,7 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd) return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status); if (retval) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); return retval; @@ -317,7 +317,7 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd) } dbg("%s: Before hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, cmd); - retval = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, cmd | CMD_CMPL_INTR_ENABLE); + retval = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), cmd | CMD_CMPL_INTR_ENABLE); if (retval) { err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); return retval; @@ -342,7 +342,7 @@ static int hpc_check_lnk_status(struct controller *ctrl) return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status); + retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(ctrl->cap_base), lnk_status); if (retval) { err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__); @@ -376,14 +376,14 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); if (retval) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); return retval; } - dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__,SLOT_CTRL, slot_ctrl); + dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__,SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); atten_led_state = (slot_ctrl & ATTN_LED_CTRL) >> 6; @@ -423,13 +423,13 @@ static int hpc_get_power_status(struct slot * slot, u8 *status) return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); if (retval) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); return retval; } - dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, slot_ctrl); + dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); pwr_state = (slot_ctrl & PWR_CTRL) >> 10; @@ -463,7 +463,7 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status) return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status); if (retval) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); @@ -490,7 +490,7 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status) return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status); if (retval) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); @@ -518,7 +518,7 @@ static int hpc_query_power_fault(struct slot * slot) return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status); if (retval) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); @@ -549,7 +549,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) err("%s: Invalid HPC slot number!\n", __FUNCTION__); return -1; } - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); if (rc) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); @@ -574,7 +574,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) slot_cmd = slot_cmd | HP_INTR_ENABLE; pcie_write_cmd(slot, slot_cmd); - dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL, slot_cmd); + dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); return rc; } @@ -598,7 +598,7 @@ static void hpc_set_green_led_on(struct slot *slot) return ; } - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); if (rc) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); @@ -611,7 +611,7 @@ static void hpc_set_green_led_on(struct slot *slot) pcie_write_cmd(slot, slot_cmd); - dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd); + dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); return; } @@ -633,7 +633,7 @@ static void hpc_set_green_led_off(struct slot *slot) return ; } - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); if (rc) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); @@ -646,7 +646,7 @@ static void hpc_set_green_led_off(struct slot *slot) if (!pciehp_poll_mode) slot_cmd = slot_cmd | HP_INTR_ENABLE; pcie_write_cmd(slot, slot_cmd); - dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL, slot_cmd); + dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); return; } @@ -669,7 +669,7 @@ static void hpc_set_green_led_blink(struct slot *slot) return ; } - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); if (rc) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); @@ -683,7 +683,7 @@ static void hpc_set_green_led_blink(struct slot *slot) slot_cmd = slot_cmd | HP_INTR_ENABLE; pcie_write_cmd(slot, slot_cmd); - dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd); + dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); return; } @@ -707,7 +707,7 @@ int pcie_get_ctlr_slot_config(struct controller *ctrl, *first_device_num = 0; *num_ctlr_slots = 1; - rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP, slot_cap); + rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap); if (rc) { err("%s : hp_register_read_dword SLOT_CAP failed\n", __FUNCTION__); @@ -793,13 +793,13 @@ static int hpc_power_on_slot(struct slot * slot) return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); if (retval) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); return retval; } - dbg("%s: SLOT_CTRL %x, value read %xn", __FUNCTION__, SLOT_CTRL, + dbg("%s: SLOT_CTRL %x, value read %xn", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_ON; @@ -813,7 +813,7 @@ static int hpc_power_on_slot(struct slot * slot) err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd); return -1; } - dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd); + dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); DBG_LEAVE_ROUTINE @@ -842,13 +842,13 @@ static int hpc_power_off_slot(struct slot * slot) err("%s: Invalid HPC slot number!\n", __FUNCTION__); return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); if (retval) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); return retval; } - dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__, SLOT_CTRL, + dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_OFF; @@ -862,7 +862,7 @@ static int hpc_power_off_slot(struct slot * slot) err("%s: Write command failed!\n", __FUNCTION__); return -1; } - dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd); + dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); DBG_LEAVE_ROUTINE @@ -900,7 +900,7 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs) return IRQ_NONE; } - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); if (rc) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); return IRQ_NONE; @@ -918,7 +918,7 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs) dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc); /* Mask Hot-plug Interrupt Enable */ if (!pciehp_poll_mode) { - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); return IRQ_NONE; @@ -928,14 +928,14 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs) dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00; - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word); + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); return IRQ_NONE; } dbg("%s: hp_register_write_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); if (rc) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); return IRQ_NONE; @@ -944,7 +944,7 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs) /* Clear command complete interrupt caused by this write */ temp_word = 0x1f; - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word); + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); return IRQ_NONE; @@ -975,14 +975,14 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs) /* Clear all events after serving them */ temp_word = 0x1F; - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word); + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); return IRQ_NONE; } /* Unmask Hot-plug Interrupt Enable */ if (!pciehp_poll_mode) { - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); return IRQ_NONE; @@ -992,14 +992,14 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs) dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word); + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); return IRQ_NONE; } dbg("%s: hp_register_write_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); if (rc) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); return IRQ_NONE; @@ -1008,7 +1008,7 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs) /* Clear command complete interrupt caused by this write */ temp_word = 0x1F; - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word); + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); return IRQ_NONE; @@ -1038,7 +1038,7 @@ static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value) return -1; } - retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP, lnk_cap); + retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap); if (retval) { err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__); @@ -1079,7 +1079,7 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value return -1; } - retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP, lnk_cap); + retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap); if (retval) { err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__); @@ -1141,7 +1141,7 @@ static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value) return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status); + retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status); if (retval) { err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__); @@ -1182,7 +1182,7 @@ static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status); + retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status); if (retval) { err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__); @@ -1292,47 +1292,48 @@ int pcie_init(struct controller * ctrl, goto abort_free_ctlr; } - pcie_cap_base = cap_base; + ctrl->cap_base = cap_base; dbg("%s: pcie_cap_base %x\n", __FUNCTION__, pcie_cap_base); - rc = hp_register_read_word(pdev, CAP_REG, cap_reg); + rc = hp_register_read_word(pdev, CAP_REG(ctrl->cap_base), cap_reg); if (rc) { err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG, cap_reg); + dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG(ctrl->cap_base), cap_reg); - if (((cap_reg & SLOT_IMPL) == 0) || ((cap_reg & DEV_PORT_TYPE) != 0x0040)){ + if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040) + && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) { dbg("%s : This is not a root port or the port is not connected to a slot\n", __FUNCTION__); goto abort_free_ctlr; } - rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP, slot_cap); + rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap); if (rc) { err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP, slot_cap); + dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP(ctrl->cap_base), slot_cap); if (!(slot_cap & HP_CAP)) { dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__); goto abort_free_ctlr; } /* For debugging purpose */ - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); if (rc) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS, slot_status); + dbg("%s: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), slot_status); - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), slot_ctrl); if (rc) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL, slot_ctrl); + dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), slot_ctrl); if (first) { spin_lock_init(&hpc_event_lock); @@ -1372,36 +1373,37 @@ int pcie_init(struct controller * ctrl, php_ctlr->num_slots = 1; /* Mask Hot-plug Interrupt Enable */ - rc = hp_register_read_word(pdev, SLOT_CTRL, temp_word); + rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, temp_word); + dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), temp_word); temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00; - rc = hp_register_write_word(pdev, SLOT_CTRL, temp_word); + rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); goto abort_free_ctlr; } dbg("%s : Mask HPIE hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, temp_word); - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); if (rc) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: Mask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, SLOT_STATUS, slot_status); + dbg("%s: Mask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base) + , slot_status); temp_word = 0x1F; /* Clear all events */ - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word); + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS, temp_word); + dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), temp_word); if (pciehp_poll_mode) {/* Install interrupt polling code */ /* Install and start the interrupt polling timer */ @@ -1417,12 +1419,12 @@ int pcie_init(struct controller * ctrl, } } - rc = hp_register_read_word(pdev, SLOT_CTRL, temp_word); + rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, temp_word); + dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), temp_word); dbg("%s: slot_cap %x\n", __FUNCTION__, slot_cap); intr_enable = intr_enable | PRSN_DETECT_ENABLE; @@ -1446,27 +1448,27 @@ int pcie_init(struct controller * ctrl, dbg("%s: temp_word %x\n", __FUNCTION__, temp_word); /* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */ - rc = hp_register_write_word(pdev, SLOT_CTRL, temp_word); + rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); goto abort_free_ctlr; } dbg("%s : Unmask HPIE hp_register_write_word SLOT_CTRL with %x\n", __FUNCTION__, temp_word); - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); if (rc) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); goto abort_free_ctlr; } dbg("%s: Unmask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, - SLOT_STATUS, slot_status); + SLOT_STATUS(ctrl->cap_base), slot_status); temp_word = 0x1F; /* Clear all events */ - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word); + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS, temp_word); + dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), temp_word); /* Add this HPC instance into the HPC list */ spin_lock(&list_lock); diff --git a/drivers/pci/pcie/portdrv_bus.c b/drivers/pci/pcie/portdrv_bus.c index 4037a3e568d..3e84b501e6a 100644 --- a/drivers/pci/pcie/portdrv_bus.c +++ b/drivers/pci/pcie/portdrv_bus.c @@ -39,7 +39,8 @@ static int pcie_port_bus_match(struct device *dev, struct device_driver *drv) driver->id_table->vendor != pciedev->id.vendor) || (driver->id_table->device != PCI_ANY_ID && driver->id_table->device != pciedev->id.device) || - driver->id_table->port_type != pciedev->id.port_type || + (driver->id_table->port_type != PCIE_ANY_PORT && + driver->id_table->port_type != pciedev->id.port_type) || driver->id_table->service_type != pciedev->id.service_type ) return 0; -- cgit v1.2.3 From 43b7d7cfb157b5c8c5cc0933f4e96fd81adc81ca Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Mon, 9 May 2005 17:31:50 -0400 Subject: [PATCH] PCI Hotplug: CPCI update [PATCH] CPCI: update I have finally done some work to update the CompactPCI hotplug driver to fix some of the outstanding issues in 2.6: - Added adapter and latch status ops so that those files will get created by the current PCI hotplug core. This used to not be required, but seems to be now after some of the sysfs rework in the core. - Replaced slot list spinlock with a r/w semaphore to avoid any potential issues with sleeping. This quiets all of the runtime warnings. - Reworked interrupt driven hot extraction handling to remove need for a polling operator for ENUM# status. There are a lot of boards that only have an interrupt driven by ENUM#, so this lowers the bar to entry. - Replaced pci_visit_dev usage with better use of the PCI core functions. The new code is functionally equivalent to the previous code, but the use of pci_enable_device on insert needs to be investigated further, as I need to do some more testing to see if it is still necessary. Signed-off-by: Scott Murray Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/cpci_hotplug.h | 2 +- drivers/pci/hotplug/cpci_hotplug_core.c | 169 +++++++-------- drivers/pci/hotplug/cpci_hotplug_pci.c | 352 +++----------------------------- 3 files changed, 112 insertions(+), 411 deletions(-) diff --git a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h index 3ddd75937a4..d9769b30be9 100644 --- a/drivers/pci/hotplug/cpci_hotplug.h +++ b/drivers/pci/hotplug/cpci_hotplug.h @@ -31,7 +31,7 @@ #include #include -/* PICMG 2.12 R2.0 HS CSR bits: */ +/* PICMG 2.1 R2.0 HS CSR bits: */ #define HS_CSR_INS 0x0080 #define HS_CSR_EXT 0x0040 #define HS_CSR_PI 0x0030 diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index ed243605dc7..9e9dab7fe86 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -33,11 +33,11 @@ #include #include #include +#include #include #include "pci_hotplug.h" #include "cpci_hotplug.h" -#define DRIVER_VERSION "0.2" #define DRIVER_AUTHOR "Scott Murray " #define DRIVER_DESC "CompactPCI Hot Plug Core" @@ -54,9 +54,10 @@ #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) /* local variables */ -static spinlock_t list_lock; +static DECLARE_RWSEM(list_rwsem); static LIST_HEAD(slot_list); static int slots; +static atomic_t extracting; int cpci_debug; static struct cpci_hp_controller *controller; static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ @@ -68,6 +69,8 @@ static int disable_slot(struct hotplug_slot *slot); static int set_attention_status(struct hotplug_slot *slot, u8 value); static int get_power_status(struct hotplug_slot *slot, u8 * value); static int get_attention_status(struct hotplug_slot *slot, u8 * value); +static int get_adapter_status(struct hotplug_slot *slot, u8 * value); +static int get_latch_status(struct hotplug_slot *slot, u8 * value); static struct hotplug_slot_ops cpci_hotplug_slot_ops = { .owner = THIS_MODULE, @@ -76,6 +79,8 @@ static struct hotplug_slot_ops cpci_hotplug_slot_ops = { .set_attention_status = set_attention_status, .get_power_status = get_power_status, .get_attention_status = get_attention_status, + .get_adapter_status = get_adapter_status, + .get_latch_status = get_latch_status, }; static int @@ -148,8 +153,10 @@ disable_slot(struct hotplug_slot *hotplug_slot) warn("failure to update adapter file"); } - slot->extracting = 0; - + if(slot->extracting) { + slot->extracting = 0; + atomic_dec(&extracting); + } return retval; } @@ -188,6 +195,20 @@ set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) return cpci_set_attention_status(hotplug_slot->private, status); } +static int +get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value) +{ + *value = hotplug_slot->info->adapter_status; + return 0; +} + +static int +get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value) +{ + *value = hotplug_slot->info->latch_status; + return 0; +} + static void release_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; @@ -273,10 +294,10 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) } /* Add slot to our internal list */ - spin_lock(&list_lock); + down_write(&list_rwsem); list_add(&slot->slot_list, &slot_list); slots++; - spin_unlock(&list_lock); + up_write(&list_rwsem); } return 0; error_name: @@ -299,9 +320,9 @@ cpci_hp_unregister_bus(struct pci_bus *bus) struct list_head *next; int status; - spin_lock(&list_lock); + down_write(&list_rwsem); if(!slots) { - spin_unlock(&list_lock); + up_write(&list_rwsem); return -1; } list_for_each_safe(tmp, next, &slot_list) { @@ -319,7 +340,7 @@ cpci_hp_unregister_bus(struct pci_bus *bus) slots--; } } - spin_unlock(&list_lock); + up_write(&list_rwsem); return 0; } @@ -347,7 +368,7 @@ cpci_hp_intr(int irq, void *data, struct pt_regs *regs) } /* - * According to PICMG 2.12 R2.0, section 6.3.2, upon + * According to PICMG 2.1 R2.0, section 6.3.2, upon * initialization, the system driver shall clear the * INS bits of the cold-inserted devices. */ @@ -359,9 +380,9 @@ init_slots(void) struct pci_dev* dev; dbg("%s - enter", __FUNCTION__); - spin_lock(&list_lock); + down_read(&list_rwsem); if(!slots) { - spin_unlock(&list_lock); + up_read(&list_rwsem); return -1; } list_for_each(tmp, &slot_list) { @@ -386,7 +407,7 @@ init_slots(void) } } } - spin_unlock(&list_lock); + up_read(&list_rwsem); dbg("%s - exit", __FUNCTION__); return 0; } @@ -398,10 +419,11 @@ check_slots(void) struct list_head *tmp; int extracted; int inserted; + u16 hs_csr; - spin_lock(&list_lock); + down_read(&list_rwsem); if(!slots) { - spin_unlock(&list_lock); + up_read(&list_rwsem); err("no slots registered, shutting down"); return -1; } @@ -411,8 +433,6 @@ check_slots(void) dbg("%s - looking at slot %s", __FUNCTION__, slot->hotplug_slot->name); if(cpci_check_and_clear_ins(slot)) { - u16 hs_csr; - /* Some broken hardware (e.g. PLX 9054AB) asserts ENUM# twice... */ if(slot->dev) { warn("slot %s already inserted", slot->hotplug_slot->name); @@ -462,8 +482,6 @@ check_slots(void) inserted++; } else if(cpci_check_ext(slot)) { - u16 hs_csr; - /* Process extraction request */ dbg("%s - slot %s extracted", __FUNCTION__, slot->hotplug_slot->name); @@ -476,20 +494,40 @@ check_slots(void) if(!slot->extracting) { if(update_latch_status(slot->hotplug_slot, 0)) { warn("failure to update latch file"); + } + atomic_inc(&extracting); slot->extracting = 1; } extracted++; + } else if(slot->extracting) { + hs_csr = cpci_get_hs_csr(slot); + if(hs_csr == 0xffff) { + /* + * Hmmm, we're likely hosed at this point, should we + * bother trying to tell the driver or not? + */ + err("card in slot %s was improperly removed", + slot->hotplug_slot->name); + if(update_adapter_status(slot->hotplug_slot, 0)) { + warn("failure to update adapter file"); + } + slot->extracting = 0; + atomic_dec(&extracting); + } } } - spin_unlock(&list_lock); + up_read(&list_rwsem); + dbg("inserted=%d, extracted=%d, extracting=%d", + inserted, extracted, atomic_read(&extracting)); if(inserted || extracted) { return extracted; } - else { + else if(!atomic_read(&extracting)) { err("cannot find ENUM# source, shutting down"); return -1; } + return 0; } /* This is the interrupt mode worker thread body */ @@ -497,8 +535,6 @@ static int event_thread(void *data) { int rc; - struct slot *slot; - struct list_head *tmp; lock_kernel(); daemonize("cpci_hp_eventd"); @@ -512,39 +548,22 @@ event_thread(void *data) thread_finished); if(thread_finished || signal_pending(current)) break; - while(controller->ops->query_enum()) { + do { rc = check_slots(); - if (rc > 0) + if (rc > 0) { /* Give userspace a chance to handle extraction */ msleep(500); - else if (rc < 0) { + } else if (rc < 0) { dbg("%s - error checking slots", __FUNCTION__); thread_finished = 1; break; } - } - /* Check for someone yanking out a board */ - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - if(slot->extracting) { - /* - * Hmmm, we're likely hosed at this point, should we - * bother trying to tell the driver or not? - */ - err("card in slot %s was improperly removed", - slot->hotplug_slot->name); - if(update_adapter_status(slot->hotplug_slot, 0)) { - warn("failure to update adapter file"); - } - slot->extracting = 0; - } - } + } while(atomic_read(&extracting) != 0); /* Re-enable ENUM# interrupt */ dbg("%s - re-enabling irq", __FUNCTION__); controller->ops->enable_irq(); } - dbg("%s - event thread signals exit", __FUNCTION__); up(&thread_exit); return 0; @@ -555,8 +574,6 @@ static int poll_thread(void *data) { int rc; - struct slot *slot; - struct list_head *tmp; lock_kernel(); daemonize("cpci_hp_polld"); @@ -565,35 +582,19 @@ poll_thread(void *data) while(1) { if(thread_finished || signal_pending(current)) break; - - while(controller->ops->query_enum()) { - rc = check_slots(); - if(rc > 0) - /* Give userspace a chance to handle extraction */ - msleep(500); - else if (rc < 0) { - dbg("%s - error checking slots", __FUNCTION__); - thread_finished = 1; - break; - } - } - /* Check for someone yanking out a board */ - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - if(slot->extracting) { - /* - * Hmmm, we're likely hosed at this point, should we - * bother trying to tell the driver or not? - */ - err("card in slot %s was improperly removed", - slot->hotplug_slot->name); - if(update_adapter_status(slot->hotplug_slot, 0)) { - warn("failure to update adapter file"); + if(controller->ops->query_enum()) { + do { + rc = check_slots(); + if(rc > 0) { + /* Give userspace a chance to handle extraction */ + msleep(500); + } else if(rc < 0) { + dbg("%s - error checking slots", __FUNCTION__); + thread_finished = 1; + break; } - slot->extracting = 0; - } + } while(atomic_read(&extracting) != 0); } - msleep(100); } dbg("poll thread signals exit"); @@ -667,6 +668,9 @@ cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller) int status = 0; if(controller) { + if(atomic_read(&extracting) != 0) { + return -EBUSY; + } if(!thread_finished) { cpci_stop_thread(); } @@ -691,12 +695,12 @@ cpci_hp_start(void) return -ENODEV; } - spin_lock(&list_lock); - if(!slots) { - spin_unlock(&list_lock); + down_read(&list_rwsem); + if(list_empty(&slot_list)) { + up_read(&list_rwsem); return -ENODEV; } - spin_unlock(&list_lock); + up_read(&list_rwsem); if(first) { status = init_slots(); @@ -727,7 +731,9 @@ cpci_hp_stop(void) if(!controller) { return -ENODEV; } - + if(atomic_read(&extracting) != 0) { + return -EBUSY; + } if(controller->irq) { /* Stop enum interrupt processing */ dbg("%s - disabling irq", __FUNCTION__); @@ -747,7 +753,7 @@ cleanup_slots(void) * Unregister all of our slots with the pci_hotplug subsystem, * and free up all memory that we had allocated. */ - spin_lock(&list_lock); + down_write(&list_rwsem); if(!slots) { goto null_cleanup; } @@ -761,17 +767,14 @@ cleanup_slots(void) kfree(slot); } null_cleanup: - spin_unlock(&list_lock); + up_write(&list_rwsem); return; } int __init cpci_hotplug_init(int debug) { - spin_lock_init(&list_lock); cpci_debug = debug; - - info(DRIVER_DESC " version: " DRIVER_VERSION); return 0; } diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c index 2e969616f29..69eb4fc54f2 100644 --- a/drivers/pci/hotplug/cpci_hotplug_pci.c +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -32,11 +32,7 @@ #include "pci_hotplug.h" #include "cpci_hotplug.h" -#if !defined(MODULE) #define MY_NAME "cpci_hotplug" -#else -#define MY_NAME THIS_MODULE->name -#endif extern int cpci_debug; @@ -127,38 +123,6 @@ u16 cpci_get_hs_csr(struct slot* slot) return hs_csr; } -#if 0 -u16 cpci_set_hs_csr(struct slot* slot, u16 hs_csr) -{ - int hs_cap; - u16 new_hs_csr; - - hs_cap = pci_bus_find_capability(slot->bus, - slot->devfn, - PCI_CAP_ID_CHSWP); - if(!hs_cap) { - return 0xFFFF; - } - - /* Write out the new value */ - if(pci_bus_write_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - hs_csr)) { - return 0xFFFF; - } - - /* Read back what we just wrote out */ - if(pci_bus_read_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - &new_hs_csr)) { - return 0xFFFF; - } - return new_hs_csr; -} -#endif - int cpci_check_and_clear_ins(struct slot* slot) { int hs_cap; @@ -261,7 +225,6 @@ int cpci_led_on(struct slot* slot) return -ENODEV; } if((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) { - /* Set LOO */ hs_csr |= HS_CSR_LOO; if(pci_bus_write_config_word(slot->bus, slot->devfn, @@ -293,7 +256,6 @@ int cpci_led_off(struct slot* slot) return -ENODEV; } if(hs_csr & HS_CSR_LOO) { - /* Clear LOO */ hs_csr &= ~HS_CSR_LOO; if(pci_bus_write_config_word(slot->bus, slot->devfn, @@ -312,257 +274,23 @@ int cpci_led_off(struct slot* slot) * Device configuration functions */ -static int cpci_configure_dev(struct pci_bus *bus, struct pci_dev *dev) -{ - u8 irq_pin; - int r; - - dbg("%s - enter", __FUNCTION__); - - /* NOTE: device already setup from prior scan */ - - /* FIXME: How would we know if we need to enable the expansion ROM? */ - pci_write_config_word(dev, PCI_ROM_ADDRESS, 0x00L); - - /* Assign resources */ - dbg("assigning resources for %02x:%02x.%x", - dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - for (r = 0; r < 6; r++) { - struct resource *res = dev->resource + r; - if(res->flags) - pci_assign_resource(dev, r); - } - dbg("finished assigning resources for %02x:%02x.%x", - dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - - /* Does this function have an interrupt at all? */ - dbg("checking for function interrupt"); - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin); - if(irq_pin) { - dbg("function uses interrupt pin %d", irq_pin); - } - - /* - * Need to explicitly set irq field to 0 so that it'll get assigned - * by the pcibios platform dependent code called by pci_enable_device. - */ - dev->irq = 0; - - dbg("enabling device"); - pci_enable_device(dev); /* XXX check return */ - dbg("now dev->irq = %d", dev->irq); - if(irq_pin && dev->irq) { - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); - } - - /* Can't use pci_insert_device at the moment, do it manually for now */ - pci_proc_attach_device(dev); - dbg("notifying drivers"); - //pci_announce_device_to_drivers(dev); - dbg("%s - exit", __FUNCTION__); - return 0; -} - -static int cpci_configure_bridge(struct pci_bus* bus, struct pci_dev* dev) +static void cpci_enable_device(struct pci_dev *dev) { - int rc; - struct pci_bus* child; - struct resource* r; - u8 max, n; - u16 command; - - dbg("%s - enter", __FUNCTION__); + struct pci_bus *bus; - /* Do basic bridge initialization */ - rc = pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40); - if(rc) { - printk(KERN_ERR "%s - write of PCI_LATENCY_TIMER failed\n", __FUNCTION__); - } - rc = pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 0x40); - if(rc) { - printk(KERN_ERR "%s - write of PCI_SEC_LATENCY_TIMER failed\n", __FUNCTION__); - } - rc = pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4); - if(rc) { - printk(KERN_ERR "%s - write of PCI_CACHE_LINE_SIZE failed\n", __FUNCTION__); - } - - /* - * Set parent bridge's subordinate field so that configuration space - * access will work in pci_scan_bridge and friends. - */ - max = pci_max_busnr(); - bus->subordinate = max + 1; - pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, max + 1); - - /* Scan behind bridge */ - n = pci_scan_bridge(bus, dev, max, 2); - child = pci_find_bus(0, max + 1); - if (!child) - return -ENODEV; - pci_proc_attach_bus(child); - - /* - * Update parent bridge's subordinate field if there were more bridges - * behind the bridge that was scanned. - */ - if(n > max) { - bus->subordinate = n; - pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, n); - } - - /* - * Update the bridge resources of the bridge to accommodate devices - * behind it. - */ - pci_bus_size_bridges(child); - pci_bus_assign_resources(child); - - /* Enable resource mapping via command register */ - command = PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR; - r = child->resource[0]; - if(r && r->start) { - command |= PCI_COMMAND_IO; - } - r = child->resource[1]; - if(r && r->start) { - command |= PCI_COMMAND_MEMORY; - } - r = child->resource[2]; - if(r && r->start) { - command |= PCI_COMMAND_MEMORY; - } - rc = pci_write_config_word(dev, PCI_COMMAND, command); - if(rc) { - err("Error setting command register"); - return rc; - } - - /* Set bridge control register */ - command = PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_NO_ISA; - rc = pci_write_config_word(dev, PCI_BRIDGE_CONTROL, command); - if(rc) { - err("Error setting bridge control register"); - return rc; - } - dbg("%s - exit", __FUNCTION__); - return 0; -} - -static int configure_visit_pci_dev(struct pci_dev_wrapped *wrapped_dev, - struct pci_bus_wrapped *wrapped_bus) -{ - int rc; - struct pci_dev *dev = wrapped_dev->dev; - struct pci_bus *bus = wrapped_bus->bus; - struct slot* slot; - - dbg("%s - enter", __FUNCTION__); - - /* - * We need to fix up the hotplug representation with the Linux - * representation. - */ - if(wrapped_dev->data) { - slot = (struct slot*) wrapped_dev->data; - slot->dev = dev; - } - - /* If it's a bridge, scan behind it for devices */ + pci_enable_device(dev); if(dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - rc = cpci_configure_bridge(bus, dev); - if(rc) - return rc; - } - - /* Actually configure device */ - if(dev) { - rc = cpci_configure_dev(bus, dev); - if(rc) - return rc; - } - dbg("%s - exit", __FUNCTION__); - return 0; -} - -static int unconfigure_visit_pci_dev_phase2(struct pci_dev_wrapped *wrapped_dev, - struct pci_bus_wrapped *wrapped_bus) -{ - struct pci_dev *dev = wrapped_dev->dev; - struct slot* slot; - - dbg("%s - enter", __FUNCTION__); - if(!dev) - return -ENODEV; - - /* Remove the Linux representation */ - if(pci_remove_device_safe(dev)) { - err("Could not remove device\n"); - return -1; - } - - /* - * Now remove the hotplug representation. - */ - if(wrapped_dev->data) { - slot = (struct slot*) wrapped_dev->data; - slot->dev = NULL; - } else { - dbg("No hotplug representation for %02x:%02x.%x", - dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - } - dbg("%s - exit", __FUNCTION__); - return 0; -} - -static int unconfigure_visit_pci_bus_phase2(struct pci_bus_wrapped *wrapped_bus, - struct pci_dev_wrapped *wrapped_dev) -{ - struct pci_bus *bus = wrapped_bus->bus; - struct pci_bus *parent = bus->self->bus; - - dbg("%s - enter", __FUNCTION__); - - /* The cleanup code for proc entries regarding buses should be in the kernel... */ - if(bus->procdir) - dbg("detach_pci_bus %s", bus->procdir->name); - pci_proc_detach_bus(bus); - - /* The cleanup code should live in the kernel... */ - bus->self->subordinate = NULL; - - /* unlink from parent bus */ - list_del(&bus->node); - - /* Now, remove */ - if(bus) - kfree(bus); - - /* Update parent's subordinate field */ - if(parent) { - u8 n = pci_bus_max_busnr(parent); - if(n < parent->subordinate) { - parent->subordinate = n; - pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, n); + bus = dev->subordinate; + list_for_each_entry(dev, &bus->devices, bus_list) { + cpci_enable_device(dev); } } - dbg("%s - exit", __FUNCTION__); - return 0; } -static struct pci_visit configure_functions = { - .visit_pci_dev = configure_visit_pci_dev, -}; - -static struct pci_visit unconfigure_functions_phase2 = { - .post_visit_pci_bus = unconfigure_visit_pci_bus_phase2, - .post_visit_pci_dev = unconfigure_visit_pci_dev_phase2 -}; - - int cpci_configure_slot(struct slot* slot) { - int rc = 0; + unsigned char busnr; + struct pci_bus *child; dbg("%s - enter", __FUNCTION__); @@ -588,74 +316,44 @@ int cpci_configure_slot(struct slot* slot) slot->dev = pci_find_slot(slot->bus->number, slot->devfn); if(slot->dev == NULL) { err("Could not find PCI device for slot %02x", slot->number); - return 0; + return 1; } } - dbg("slot->dev = %p", slot->dev); - if(slot->dev) { - struct pci_dev *dev; - struct pci_dev_wrapped wrapped_dev; - struct pci_bus_wrapped wrapped_bus; - int i; - - memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped)); - memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped)); - - for (i = 0; i < 8; i++) { - dev = pci_find_slot(slot->bus->number, - PCI_DEVFN(PCI_SLOT(slot->dev->devfn), i)); - if(!dev) - continue; - wrapped_dev.dev = dev; - wrapped_bus.bus = slot->dev->bus; - if(i) - wrapped_dev.data = NULL; - else - wrapped_dev.data = (void*) slot; - rc = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus); - } + + if (slot->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_read_config_byte(slot->dev, PCI_SECONDARY_BUS, &busnr); + child = pci_add_new_bus(slot->dev->bus, slot->dev, busnr); + pci_do_scan_bus(child); + pci_bus_size_bridges(child); } - dbg("%s - exit, rc = %d", __FUNCTION__, rc); - return rc; + pci_bus_assign_resources(slot->dev->bus); + + cpci_enable_device(slot->dev); + + dbg("%s - exit", __FUNCTION__); + return 0; } int cpci_unconfigure_slot(struct slot* slot) { - int rc = 0; int i; - struct pci_dev_wrapped wrapped_dev; - struct pci_bus_wrapped wrapped_bus; struct pci_dev *dev; dbg("%s - enter", __FUNCTION__); - if(!slot->dev) { err("No device for slot %02x\n", slot->number); return -ENODEV; } - memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped)); - memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped)); - for (i = 0; i < 8; i++) { dev = pci_find_slot(slot->bus->number, PCI_DEVFN(PCI_SLOT(slot->devfn), i)); if(dev) { - wrapped_dev.dev = dev; - wrapped_bus.bus = dev->bus; - if(i) - wrapped_dev.data = NULL; - else - wrapped_dev.data = (void*) slot; - dbg("%s - unconfigure phase 2", __FUNCTION__); - rc = pci_visit_dev(&unconfigure_functions_phase2, - &wrapped_dev, - &wrapped_bus); - if(rc) - break; + pci_remove_bus_device(dev); + slot->dev = NULL; } } - dbg("%s - exit, rc = %d", __FUNCTION__, rc); - return rc; + dbg("%s - exit", __FUNCTION__); + return 0; } -- cgit v1.2.3 From c22610dadc0452b1273494f2b5157123c6cd60e1 Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Mon, 9 May 2005 17:36:27 -0400 Subject: [PATCH] PCI Hotplug: remove pci_visit_dev If my CPCI hotplug update patch is applied, then there are no longer any in tree users of the pci_visit_dev API, and it and its related code can be removed. Signed-off-by: Scott Murray Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug.c | 109 -------------------------------------------------- drivers/pci/pci.h | 27 ------------- 2 files changed, 136 deletions(-) diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c index 021d0f76bc4..6a1a976c4bf 100644 --- a/drivers/pci/hotplug.c +++ b/drivers/pci/hotplug.c @@ -56,112 +56,3 @@ int pci_hotplug (struct device *dev, char **envp, int num_envp, return 0; } - -static int pci_visit_bus (struct pci_visit * fn, struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_parent) -{ - struct list_head *ln; - struct pci_dev *dev; - struct pci_dev_wrapped wrapped_dev; - int result = 0; - - pr_debug("PCI: Scanning bus %04x:%02x\n", pci_domain_nr(wrapped_bus->bus), - wrapped_bus->bus->number); - - if (fn->pre_visit_pci_bus) { - result = fn->pre_visit_pci_bus(wrapped_bus, wrapped_parent); - if (result) - return result; - } - - ln = wrapped_bus->bus->devices.next; - while (ln != &wrapped_bus->bus->devices) { - dev = pci_dev_b(ln); - ln = ln->next; - - memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped)); - wrapped_dev.dev = dev; - - result = pci_visit_dev(fn, &wrapped_dev, wrapped_bus); - if (result) - return result; - } - - if (fn->post_visit_pci_bus) - result = fn->post_visit_pci_bus(wrapped_bus, wrapped_parent); - - return result; -} - -static int pci_visit_bridge (struct pci_visit * fn, - struct pci_dev_wrapped *wrapped_dev, - struct pci_bus_wrapped *wrapped_parent) -{ - struct pci_bus *bus; - struct pci_bus_wrapped wrapped_bus; - int result = 0; - - pr_debug("PCI: Scanning bridge %s\n", pci_name(wrapped_dev->dev)); - - if (fn->visit_pci_dev) { - result = fn->visit_pci_dev(wrapped_dev, wrapped_parent); - if (result) - return result; - } - - bus = wrapped_dev->dev->subordinate; - if (bus) { - memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped)); - wrapped_bus.bus = bus; - - result = pci_visit_bus(fn, &wrapped_bus, wrapped_dev); - } - return result; -} - -/** - * pci_visit_dev - scans the pci buses. - * @fn: callback functions that are called while visiting - * @wrapped_dev: the device to scan - * @wrapped_parent: the bus where @wrapped_dev is connected to - * - * Every bus and every function is presented to a custom - * function that can act upon it. - */ -int pci_visit_dev(struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev, - struct pci_bus_wrapped *wrapped_parent) -{ - struct pci_dev* dev = wrapped_dev ? wrapped_dev->dev : NULL; - int result = 0; - - if (!dev) - return 0; - - if (fn->pre_visit_pci_dev) { - result = fn->pre_visit_pci_dev(wrapped_dev, wrapped_parent); - if (result) - return result; - } - - switch (dev->class >> 8) { - case PCI_CLASS_BRIDGE_PCI: - result = pci_visit_bridge(fn, wrapped_dev, - wrapped_parent); - if (result) - return result; - break; - default: - pr_debug("PCI: Scanning device %s\n", pci_name(dev)); - if (fn->visit_pci_dev) { - result = fn->visit_pci_dev (wrapped_dev, - wrapped_parent); - if (result) - return result; - } - } - - if (fn->post_visit_pci_dev) - result = fn->post_visit_pci_dev(wrapped_dev, wrapped_parent); - - return result; -} -EXPORT_SYMBOL(pci_visit_dev); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 79cdc16c52c..744da0d4ae5 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -32,33 +32,6 @@ extern unsigned char pci_max_busnr(void); extern unsigned char pci_bus_max_busnr(struct pci_bus *bus); extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap); -struct pci_dev_wrapped { - struct pci_dev *dev; - void *data; -}; - -struct pci_bus_wrapped { - struct pci_bus *bus; - void *data; -}; - -struct pci_visit { - int (* pre_visit_pci_bus) (struct pci_bus_wrapped *, - struct pci_dev_wrapped *); - int (* post_visit_pci_bus) (struct pci_bus_wrapped *, - struct pci_dev_wrapped *); - - int (* pre_visit_pci_dev) (struct pci_dev_wrapped *, - struct pci_bus_wrapped *); - int (* visit_pci_dev) (struct pci_dev_wrapped *, - struct pci_bus_wrapped *); - int (* post_visit_pci_dev) (struct pci_dev_wrapped *, - struct pci_bus_wrapped *); -}; - -extern int pci_visit_dev(struct pci_visit *fn, - struct pci_dev_wrapped *wrapped_dev, - struct pci_bus_wrapped *wrapped_parent); extern void pci_remove_legacy_files(struct pci_bus *bus); /* Lock for read/write access to pci device and bus lists */ -- cgit v1.2.3 From 9888549e0507cc95d1d7ade1595c00ff8e902659 Mon Sep 17 00:00:00 2001 From: Greg KH Date: Thu, 5 May 2005 11:57:25 -0700 Subject: [PATCH] PCI: add modalias sysfs file for pci devices Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-sysfs.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 8568b207f18..6ca0061137a 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -73,6 +73,17 @@ resource_show(struct device * dev, char * buf) return (str - buf); } +static ssize_t modalias_show(struct device *dev, char *buf) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + + return sprintf(buf, "pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x\n", + pci_dev->vendor, pci_dev->device, + pci_dev->subsystem_vendor, pci_dev->subsystem_device, + (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8), + (u8)(pci_dev->class)); +} + struct device_attribute pci_dev_attrs[] = { __ATTR_RO(resource), __ATTR_RO(vendor), @@ -82,6 +93,7 @@ struct device_attribute pci_dev_attrs[] = { __ATTR_RO(class), __ATTR_RO(irq), __ATTR_RO(local_cpus), + __ATTR_RO(modalias), __ATTR_NULL, }; -- cgit v1.2.3 From d1ded203adf16b42ca90e9041120ae465ca5c4a6 Mon Sep 17 00:00:00 2001 From: Greg KH Date: Thu, 5 May 2005 11:57:25 -0700 Subject: [PATCH] PCI: add MODALIAS to hotplug event for pci devices Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c index 6a1a976c4bf..3903f8c559b 100644 --- a/drivers/pci/hotplug.c +++ b/drivers/pci/hotplug.c @@ -52,6 +52,16 @@ int pci_hotplug (struct device *dev, char **envp, int num_envp, if ((buffer_size - length <= 0) || (i >= num_envp)) return -ENOMEM; + envp[i++] = scratch; + length += scnprintf (scratch, buffer_size - length, + "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x\n", + pdev->vendor, pdev->device, + pdev->subsystem_vendor, pdev->subsystem_device, + (u8)(pdev->class >> 16), (u8)(pdev->class >> 8), + (u8)(pdev->class)); + if ((buffer_size - length <= 0) || (i >= num_envp)) + return -ENOMEM; + envp[i] = NULL; return 0; -- cgit v1.2.3 From 82428b62aa6294ea640c7e920a9224ecaf46db65 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 9 May 2005 08:07:00 -0700 Subject: [PATCH] Driver Core: pm diagnostics update, check for errors This patch includes various tweaks in the messaging that appears during system pm state transitions: * Warn about certain illegal calls in the device tree, like resuming child before parent or suspending parent before child. This could happen easily enough through sysfs, or in some cases when drivers use device_pm_set_parent(). * Be more consistent about dev_dbg() tracing ... do it for resume() and shutdown() too, and never if the driver doesn't have that method. * Say which type of system sleep state is being entered. Except for the warnings, these only affect debug messaging. Signed-off-by: David Brownell Acked-by: Pavel Machek Signed-off-by: Greg Kroah-Hartman --- drivers/base/power/resume.c | 11 ++++++++++- drivers/base/power/shutdown.c | 13 +++++++------ drivers/base/power/suspend.c | 17 +++++++++++++++-- kernel/power/main.c | 6 +++--- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c index f8f5055754d..26468971ef5 100644 --- a/drivers/base/power/resume.c +++ b/drivers/base/power/resume.c @@ -22,8 +22,17 @@ extern int sysdev_resume(void); int resume_device(struct device * dev) { - if (dev->bus && dev->bus->resume) + if (dev->power.pm_parent + && dev->power.pm_parent->power.power_state) { + dev_err(dev, "PM: resume from %d, parent %s still %d\n", + dev->power.power_state, + dev->power.pm_parent->bus_id, + dev->power.pm_parent->power.power_state); + } + if (dev->bus && dev->bus->resume) { + dev_dbg(dev,"resuming\n"); return dev->bus->resume(dev); + } return 0; } diff --git a/drivers/base/power/shutdown.c b/drivers/base/power/shutdown.c index d1e023fbe16..97979901c14 100644 --- a/drivers/base/power/shutdown.c +++ b/drivers/base/power/shutdown.c @@ -25,8 +25,10 @@ int device_detach_shutdown(struct device * dev) return 0; if (dev->detach_state == DEVICE_PM_OFF) { - if (dev->driver && dev->driver->shutdown) + if (dev->driver && dev->driver->shutdown) { + dev_dbg(dev, "shutdown\n"); dev->driver->shutdown(dev); + } return 0; } return dpm_runtime_suspend(dev, dev->detach_state); @@ -52,13 +54,12 @@ void device_shutdown(void) struct device * dev; down_write(&devices_subsys.rwsem); - list_for_each_entry_reverse(dev, &devices_subsys.kset.list, kobj.entry) { - pr_debug("shutting down %s: ", dev->bus_id); + list_for_each_entry_reverse(dev, &devices_subsys.kset.list, + kobj.entry) { if (dev->driver && dev->driver->shutdown) { - pr_debug("Ok\n"); + dev_dbg(dev, "shutdown\n"); dev->driver->shutdown(dev); - } else - pr_debug("Ignored.\n"); + } } up_write(&devices_subsys.rwsem); diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index a0b5cf689e6..0ec44ef840b 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c @@ -39,12 +39,25 @@ int suspend_device(struct device * dev, pm_message_t state) { int error = 0; - dev_dbg(dev, "suspending\n"); + if (dev->power.power_state) { + dev_dbg(dev, "PM: suspend %d-->%d\n", + dev->power.power_state, state); + } + if (dev->power.pm_parent + && dev->power.pm_parent->power.power_state) { + dev_err(dev, + "PM: suspend %d->%d, parent %s already %d\n", + dev->power.power_state, state, + dev->power.pm_parent->bus_id, + dev->power.pm_parent->power.power_state); + } dev->power.prev_state = dev->power.power_state; - if (dev->bus && dev->bus->suspend && !dev->power.power_state) + if (dev->bus && dev->bus->suspend && !dev->power.power_state) { + dev_dbg(dev, "suspending\n"); error = dev->bus->suspend(dev, state); + } return error; } diff --git a/kernel/power/main.c b/kernel/power/main.c index 7960ddf04a5..4cdebc972ff 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -156,14 +156,14 @@ static int enter_state(suspend_state_t state) goto Unlock; } - pr_debug("PM: Preparing system for suspend\n"); + pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); if ((error = suspend_prepare(state))) goto Unlock; - pr_debug("PM: Entering state.\n"); + pr_debug("PM: Entering %s sleep\n", pm_states[state]); error = suspend_enter(state); - pr_debug("PM: Finishing up.\n"); + pr_debug("PM: Finishing wakeup.\n"); suspend_finish(state); Unlock: up(&pm_sem); -- cgit v1.2.3 From 0b405a0f7e4d4d18fd1fe46ddf5ff465443036ab Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 12 May 2005 12:06:27 -0700 Subject: [PATCH] Driver Core: remove driver model detach_state The driver model has a "detach_state" mechanism that: - Has never been used by any in-kernel drive; - Is superfluous, since driver remove() methods can do the same thing; - Became buggy when the suspend() parameter changed semantics and type; - Could self-deadlock when called from certain suspend contexts; - Is effectively wasted documentation, object code, and headspace. This removes that "detach_state" mechanism; net code shrink, as well as a per-device saving in the driver model and sysfs. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- Documentation/filesystems/sysfs-pci.txt | 6 ++-- Documentation/power/devices.txt | 21 -------------- Documentation/powerpc/hvcs.txt | 4 +-- drivers/base/Makefile | 2 +- drivers/base/bus.c | 1 - drivers/base/core.c | 3 -- drivers/base/interface.c | 51 --------------------------------- drivers/base/power/power.h | 11 ------- drivers/base/power/shutdown.c | 16 ----------- include/linux/device.h | 3 -- 10 files changed, 5 insertions(+), 113 deletions(-) delete mode 100644 drivers/base/interface.c diff --git a/Documentation/filesystems/sysfs-pci.txt b/Documentation/filesystems/sysfs-pci.txt index e97d024eae7..988a62fae11 100644 --- a/Documentation/filesystems/sysfs-pci.txt +++ b/Documentation/filesystems/sysfs-pci.txt @@ -7,7 +7,6 @@ that support it. For example, a given bus might look like this: |-- 0000:17:00.0 | |-- class | |-- config - | |-- detach_state | |-- device | |-- irq | |-- local_cpus @@ -19,7 +18,7 @@ that support it. For example, a given bus might look like this: | |-- subsystem_device | |-- subsystem_vendor | `-- vendor - `-- detach_state + `-- ... The topmost element describes the PCI domain and bus number. In this case, the domain number is 0000 and the bus number is 17 (both values are in hex). @@ -31,7 +30,6 @@ files, each with their own function. ---- -------- class PCI class (ascii, ro) config PCI config space (binary, rw) - detach_state connection status (bool, rw) device PCI device (ascii, ro) irq IRQ number (ascii, ro) local_cpus nearby CPU mask (cpumask, ro) @@ -85,4 +83,4 @@ useful return codes should be provided. Legacy resources are protected by the HAVE_PCI_LEGACY define. Platforms wishing to support legacy functionality should define it and provide -pci_legacy_read, pci_legacy_write and pci_mmap_legacy_page_range functions. \ No newline at end of file +pci_legacy_read, pci_legacy_write and pci_mmap_legacy_page_range functions. diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt index 5d4ae9a39f1..f987afe43e2 100644 --- a/Documentation/power/devices.txt +++ b/Documentation/power/devices.txt @@ -207,27 +207,6 @@ SYSTEM_SHUTDOWN, I do not understand this one too much. probably event #READY_AFTER_RESUME # -Driver Detach Power Management - -The kernel now supports the ability to place a device in a low-power -state when it is detached from its driver, which happens when its -module is removed. - -Each device contains a 'detach_state' file in its sysfs directory -which can be used to control this state. Reading from this file -displays what the current detach state is set to. This is 0 (On) by -default. A user may write a positive integer value to this file in the -range of 1-4 inclusive. - -A value of 1-3 will indicate the device should be placed in that -low-power state, which will cause ->suspend() to be called for that -device. A value of 4 indicates that the device should be shutdown, so -->shutdown() will be called for that device. - -The driver is responsible for reinitializing the device when the -module is re-inserted during it's ->probe() (or equivalent) method. -The driver core will not call any extra functions when binding the -device to the driver. pm_message_t meaning diff --git a/Documentation/powerpc/hvcs.txt b/Documentation/powerpc/hvcs.txt index c0a62e116e6..dca75cbda6f 100644 --- a/Documentation/powerpc/hvcs.txt +++ b/Documentation/powerpc/hvcs.txt @@ -347,8 +347,8 @@ address that is created by firmware. An example vty-server sysfs entry looks like the following: Pow5:/sys/bus/vio/drivers/hvcs/30000004 # ls - . current_vty devspec name partner_vtys - .. detach_state index partner_clcs vterm_state + . current_vty devspec name partner_vtys + .. index partner_clcs vterm_state Each entry is provided, by default with a "name" attribute. Reading the "name" attribute will reveal the device type as shown in the following diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 6662b545e0a..a47928a2e57 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -1,6 +1,6 @@ # Makefile for the Linux device tree -obj-y := core.o sys.o interface.o bus.o \ +obj-y := core.o sys.o bus.o \ driver.o class.o class_simple.o platform.o \ cpu.o firmware.o init.o map.o dmapool.o \ attribute_container.o transport_class.o diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 2b3902c867d..3cb04bb04c2 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -390,7 +390,6 @@ void device_release_driver(struct device * dev) sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); sysfs_remove_link(&dev->kobj, "driver"); list_del_init(&dev->driver_list); - device_detach_shutdown(dev); if (drv->remove) drv->remove(dev); dev->driver = NULL; diff --git a/drivers/base/core.c b/drivers/base/core.c index 268a9c8d168..d21eb774449 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -31,8 +31,6 @@ int (*platform_notify_remove)(struct device * dev) = NULL; #define to_dev(obj) container_of(obj, struct device, kobj) #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) -extern struct attribute * dev_default_attrs[]; - static ssize_t dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) { @@ -89,7 +87,6 @@ static void device_release(struct kobject * kobj) static struct kobj_type ktype_device = { .release = device_release, .sysfs_ops = &dev_sysfs_ops, - .default_attrs = dev_default_attrs, }; diff --git a/drivers/base/interface.c b/drivers/base/interface.c deleted file mode 100644 index bd515843a0c..00000000000 --- a/drivers/base/interface.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * drivers/base/interface.c - common driverfs interface that's exported to - * the world for all devices. - * - * Copyright (c) 2002-3 Patrick Mochel - * Copyright (c) 2002-3 Open Source Development Labs - * - * This file is released under the GPLv2 - * - */ - -#include -#include -#include -#include - -/** - * detach_state - control the default power state for the device. - * - * This is the state the device enters when it's driver module is - * unloaded. The value is an unsigned integer, in the range of 0-4. - * '0' indicates 'On', so no action will be taken when the driver is - * unloaded. This is the default behavior. - * '4' indicates 'Off', meaning the driver core will call the driver's - * shutdown method to quiesce the device. - * 1-3 indicate a low-power state for the device to enter via the - * driver's suspend method. - */ - -static ssize_t detach_show(struct device * dev, char * buf) -{ - return sprintf(buf, "%u\n", dev->detach_state); -} - -static ssize_t detach_store(struct device * dev, const char * buf, size_t n) -{ - u32 state; - state = simple_strtoul(buf, NULL, 10); - if (state > 4) - return -EINVAL; - dev->detach_state = state; - return n; -} - -static DEVICE_ATTR(detach_state, 0644, detach_show, detach_store); - - -struct attribute * dev_default_attrs[] = { - &dev_attr_detach_state.attr, - NULL, -}; diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index e5eda746f2a..2e700d795cf 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -1,18 +1,7 @@ - - -enum { - DEVICE_PM_ON, - DEVICE_PM1, - DEVICE_PM2, - DEVICE_PM3, - DEVICE_PM_OFF, -}; - /* * shutdown.c */ -extern int device_detach_shutdown(struct device *); extern void device_shutdown(void); diff --git a/drivers/base/power/shutdown.c b/drivers/base/power/shutdown.c index 97979901c14..f50a08be424 100644 --- a/drivers/base/power/shutdown.c +++ b/drivers/base/power/shutdown.c @@ -19,22 +19,6 @@ extern struct subsystem devices_subsys; -int device_detach_shutdown(struct device * dev) -{ - if (!dev->detach_state) - return 0; - - if (dev->detach_state == DEVICE_PM_OFF) { - if (dev->driver && dev->driver->shutdown) { - dev_dbg(dev, "shutdown\n"); - dev->driver->shutdown(dev); - } - return 0; - } - return dpm_runtime_suspend(dev, dev->detach_state); -} - - /** * We handle system devices differently - we suspend and shut them * down last and resume them first. That way, we don't do anything stupid like diff --git a/include/linux/device.h b/include/linux/device.h index cf470459fa6..df94c0de53f 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -273,9 +273,6 @@ struct device { BIOS data relevant to device) */ struct dev_pm_info power; - u32 detach_state; /* State to enter when device is - detached from its driver. */ - u64 *dma_mask; /* dma mask (if dma'able device) */ u64 coherent_dma_mask;/* Like dma_mask, but for alloc_coherent mappings as -- cgit v1.2.3 From e72022e13d659bece2fc9cb2dd97afa67047dbca Mon Sep 17 00:00:00 2001 From: Stephen Tweedie Date: Wed, 18 May 2005 11:22:31 -0400 Subject: [PATCH] Fix filp being passed through raw ioctl handler Don't pass meaningless file handles to block device ioctls. The recent raw IO ioctl-passthrough fix started passing the raw file handle into the block device ioctl handler. That's unlikely to be useful, as the file handle is actually open on a character-mode raw device, not a block device, so dereferencing it is not going to yield useful results to a block device ioctl handler. Previously we just passed NULL; also not a value that can usefully be dereferenced, but at least if it does happen, we'll oops instead of silently pretending that the file is a block device, so NULL is the more defensive option here. This patch reverts to that behaviour. Noticed by Al Viro. Signed-off-by: Stephen Tweedie Acked-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/char/raw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 131465e8de5..ca5f42bcaad 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -122,7 +122,7 @@ raw_ioctl(struct inode *inode, struct file *filp, { struct block_device *bdev = filp->private_data; - return blkdev_ioctl(bdev->bd_inode, filp, command, arg); + return blkdev_ioctl(bdev->bd_inode, NULL, command, arg); } static void bind_device(struct raw_config_request *rq) -- cgit v1.2.3 From 301216244b1e39c4346e56d38b079ca53d528580 Mon Sep 17 00:00:00 2001 From: Stephen Tweedie Date: Wed, 18 May 2005 11:47:17 -0400 Subject: [PATCH] Avoid console spam with ext3 aborted journal. Avoid console spam with ext3 aborted journal. ext3 usually reports error conditions that it detects in its environment. But when its journal gets aborted due to such errors, it can sometimes continue to report that condition forever, spamming the console to such an extent that the initial first cause of the journal abort can be lost. When the journal aborts, we put the filesystem into readonly mode. Most subsequent filesystem operations will get rejected immediately by checks for MS_RDONLY either in the filesystem or in the VFS. But some paths do not have such checks --- for example, if we continue to write to a file handle that was opened before the fs went readonly. (We only check for the ROFS condition when the file is first opened.) In these cases, we can continue to generate log errors similar to EXT3-fs error (device $DEV) in start_transaction: Journal has aborted for each subsequent write. There is really no point in generating these errors after the initial error has been fully reported. Specifically, if we're starting a completely new filesystem operation, and the filesystem is *already* readonly (ie. the ext3 layer has already detected and handled the underlying jbd abort), and we see an EROFS error, then there is simply no point in reporting it again. Signed-off-by: Stephen Tweedie Signed-off-by: Linus Torvalds --- fs/ext3/super.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 545b440a2d2..981ccb233ef 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -225,8 +225,16 @@ void __ext3_std_error (struct super_block * sb, const char * function, int errno) { char nbuf[16]; - const char *errstr = ext3_decode_error(sb, errno, nbuf); + const char *errstr; + + /* Special case: if the error is EROFS, and we're not already + * inside a transaction, then there's really no point in logging + * an error. */ + if (errno == -EROFS && journal_current_handle() == NULL && + (sb->s_flags & MS_RDONLY)) + return; + errstr = ext3_decode_error(sb, errno, nbuf); printk (KERN_CRIT "EXT3-fs error (device %s) in %s: %s\n", sb->s_id, function, errstr); -- cgit v1.2.3 From fac9b83ea79aa3112ed245d9a4fc2a5c3ec2b7ec Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 18 May 2005 22:46:34 -0700 Subject: [TG3]: Add tagged status support. When supported, use the TAGGED interrupt processing support the chip provides. In this mode, instead of a "on/off" binary semaphore, an incrementing tag scheme is used to ACK interrupts. All MSI supporting chips support TAGGED mode, so the tg3_msi() interrupt handler uses it unconditionally. This invariant is verified when MSI support is tested. Since we can invoke tg3_poll() multiple times per interrupt under high packet load, we fetch a new copy of the tag value in the status block right before we actually do the work. Also, because the tagged status tells the chip exactly which work we have processed, we can make two optimizations: 1) tg3_restart_ints() need not check tg3_has_work() 2) the tg3_timer() need not poke the chip 10 times per second to keep from losing interrupt events Based upon valuable feedback from Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 195 +++++++++++++++++++++++++++++++++++++++--------------- drivers/net/tg3.h | 2 + 2 files changed, 142 insertions(+), 55 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f79b02e80e7..488b8c65252 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -420,7 +420,8 @@ static void tg3_enable_ints(struct tg3 *tp) { tw32(TG3PCI_MISC_HOST_CTRL, (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT)); - tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000000); + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, + (tp->last_tag << 24)); tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); tg3_cond_int(tp); @@ -455,10 +456,16 @@ static void tg3_restart_ints(struct tg3 *tp) { tw32(TG3PCI_MISC_HOST_CTRL, (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT)); - tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000000); + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, + tp->last_tag << 24); mmiowb(); - if (tg3_has_work(tp)) + /* When doing tagged status, this work check is unnecessary. + * The last_tag we write above tells the chip which piece of + * work we've completed. + */ + if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && + tg3_has_work(tp)) tw32(HOSTCC_MODE, tp->coalesce_mode | (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW)); } @@ -2862,6 +2869,9 @@ static int tg3_poll(struct net_device *netdev, int *budget) spin_lock_irqsave(&tp->lock, flags); + if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) + tp->last_tag = sblk->status_tag; + /* handle link change and other phy events */ if (!(tp->tg3_flags & (TG3_FLAG_USE_LINKCHG_REG | @@ -2928,22 +2938,21 @@ static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs) spin_lock_irqsave(&tp->lock, flags); /* - * writing any value to intr-mbox-0 clears PCI INTA# and + * Writing any value to intr-mbox-0 clears PCI INTA# and * chip-internal interrupt pending events. - * writing non-zero to intr-mbox-0 additional tells the + * Writing non-zero to intr-mbox-0 additional tells the * NIC to stop sending us irqs, engaging "in-intr-handler" * event coalescing. */ tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); + tp->last_tag = sblk->status_tag; sblk->status &= ~SD_STATUS_UPDATED; - if (likely(tg3_has_work(tp))) netif_rx_schedule(dev); /* schedule NAPI poll */ else { - /* no work, re-enable interrupts - */ + /* No work, re-enable interrupts. */ tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, - 0x00000000); + tp->last_tag << 24); } spin_unlock_irqrestore(&tp->lock, flags); @@ -2969,21 +2978,62 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs) if ((sblk->status & SD_STATUS_UPDATED) || !(tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) { /* - * writing any value to intr-mbox-0 clears PCI INTA# and + * Writing any value to intr-mbox-0 clears PCI INTA# and * chip-internal interrupt pending events. - * writing non-zero to intr-mbox-0 additional tells the + * Writing non-zero to intr-mbox-0 additional tells the * NIC to stop sending us irqs, engaging "in-intr-handler" * event coalescing. */ tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); + sblk->status &= ~SD_STATUS_UPDATED; + if (likely(tg3_has_work(tp))) + netif_rx_schedule(dev); /* schedule NAPI poll */ + else { + /* No work, shared interrupt perhaps? re-enable + * interrupts, and flush that PCI write + */ + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, + 0x00000000); + tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); + } + } else { /* shared interrupt */ + handled = 0; + } + + spin_unlock_irqrestore(&tp->lock, flags); + + return IRQ_RETVAL(handled); +} + +static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct tg3 *tp = netdev_priv(dev); + struct tg3_hw_status *sblk = tp->hw_status; + unsigned long flags; + unsigned int handled = 1; + + spin_lock_irqsave(&tp->lock, flags); + + /* In INTx mode, it is possible for the interrupt to arrive at + * the CPU before the status block posted prior to the interrupt. + * Reading the PCI State register will confirm whether the + * interrupt is ours and will flush the status block. + */ + if ((sblk->status & SD_STATUS_UPDATED) || + !(tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) { /* - * Flush PCI write. This also guarantees that our - * status block has been flushed to host memory. + * writing any value to intr-mbox-0 clears PCI INTA# and + * chip-internal interrupt pending events. + * writing non-zero to intr-mbox-0 additional tells the + * NIC to stop sending us irqs, engaging "in-intr-handler" + * event coalescing. */ - tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, + 0x00000001); + tp->last_tag = sblk->status_tag; sblk->status &= ~SD_STATUS_UPDATED; - if (likely(tg3_has_work(tp))) netif_rx_schedule(dev); /* schedule NAPI poll */ else { @@ -2991,7 +3041,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs) * interrupts, and flush that PCI write */ tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, - 0x00000000); + tp->last_tag << 24); tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); } } else { /* shared interrupt */ @@ -5445,7 +5495,8 @@ static int tg3_reset_hw(struct tg3 *tp) udelay(100); tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0); - tr32(MAILBOX_INTERRUPT_0); + tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); + tp->last_tag = 0; if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { tw32_f(DMAC_MODE, DMAC_MODE_ENABLE); @@ -5723,31 +5774,33 @@ static void tg3_timer(unsigned long __opaque) spin_lock_irqsave(&tp->lock, flags); spin_lock(&tp->tx_lock); - /* All of this garbage is because when using non-tagged - * IRQ status the mailbox/status_block protocol the chip - * uses with the cpu is race prone. - */ - if (tp->hw_status->status & SD_STATUS_UPDATED) { - tw32(GRC_LOCAL_CTRL, - tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); - } else { - tw32(HOSTCC_MODE, tp->coalesce_mode | - (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW)); - } + if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { + /* All of this garbage is because when using non-tagged + * IRQ status the mailbox/status_block protocol the chip + * uses with the cpu is race prone. + */ + if (tp->hw_status->status & SD_STATUS_UPDATED) { + tw32(GRC_LOCAL_CTRL, + tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); + } else { + tw32(HOSTCC_MODE, tp->coalesce_mode | + (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW)); + } - if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { - tp->tg3_flags2 |= TG3_FLG2_RESTART_TIMER; - spin_unlock(&tp->tx_lock); - spin_unlock_irqrestore(&tp->lock, flags); - schedule_work(&tp->reset_task); - return; + if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { + tp->tg3_flags2 |= TG3_FLG2_RESTART_TIMER; + spin_unlock(&tp->tx_lock); + spin_unlock_irqrestore(&tp->lock, flags); + schedule_work(&tp->reset_task); + return; + } } - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) - tg3_periodic_fetch_stats(tp); - /* This part only runs once per second. */ if (!--tp->timer_counter) { + if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) + tg3_periodic_fetch_stats(tp); + if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) { u32 mac_stat; int phy_event; @@ -5846,9 +5899,13 @@ static int tg3_test_interrupt(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) err = request_irq(tp->pdev->irq, tg3_msi, SA_SAMPLE_RANDOM, dev->name, dev); - else - err = request_irq(tp->pdev->irq, tg3_interrupt, + else { + irqreturn_t (*fn)(int, void *, struct pt_regs *)=tg3_interrupt; + if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) + fn = tg3_interrupt_tagged; + err = request_irq(tp->pdev->irq, fn, SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev); + } if (err) return err; @@ -5900,9 +5957,14 @@ static int tg3_test_msi(struct tg3 *tp) tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; - err = request_irq(tp->pdev->irq, tg3_interrupt, - SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev); + { + irqreturn_t (*fn)(int, void *, struct pt_regs *)=tg3_interrupt; + if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) + fn = tg3_interrupt_tagged; + err = request_irq(tp->pdev->irq, fn, + SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev); + } if (err) return err; @@ -5948,7 +6010,13 @@ static int tg3_open(struct net_device *dev) if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_AX) && (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_BX)) { - if (pci_enable_msi(tp->pdev) == 0) { + /* All MSI supporting chips should support tagged + * status. Assert that this is the case. + */ + if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { + printk(KERN_WARNING PFX "%s: MSI without TAGGED? " + "Not using MSI.\n", tp->dev->name); + } else if (pci_enable_msi(tp->pdev) == 0) { u32 msi_mode; msi_mode = tr32(MSGINT_MODE); @@ -5959,9 +6027,14 @@ static int tg3_open(struct net_device *dev) if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) err = request_irq(tp->pdev->irq, tg3_msi, SA_SAMPLE_RANDOM, dev->name, dev); - else - err = request_irq(tp->pdev->irq, tg3_interrupt, + else { + irqreturn_t (*fn)(int, void *, struct pt_regs *)=tg3_interrupt; + if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) + fn = tg3_interrupt_tagged; + + err = request_irq(tp->pdev->irq, fn, SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev); + } if (err) { if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { @@ -5980,9 +6053,16 @@ static int tg3_open(struct net_device *dev) tg3_halt(tp, 1); tg3_free_rings(tp); } else { - tp->timer_offset = HZ / 10; - tp->timer_counter = tp->timer_multiplier = 10; - tp->asf_counter = tp->asf_multiplier = (10 * 120); + if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) + tp->timer_offset = HZ; + else + tp->timer_offset = HZ / 10; + + BUG_ON(tp->timer_offset > HZ); + tp->timer_counter = tp->timer_multiplier = + (HZ / tp->timer_offset); + tp->asf_counter = tp->asf_multiplier = + ((HZ / tp->timer_offset) * 120); init_timer(&tp->timer); tp->timer.expires = jiffies + tp->timer_offset; @@ -6005,6 +6085,7 @@ static int tg3_open(struct net_device *dev) if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { err = tg3_test_msi(tp); + if (err) { spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); @@ -8422,15 +8503,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG; - /* Only 5701 and later support tagged irq status mode. - * Also, 5788 chips cannot use tagged irq status. - * - * However, since we are using NAPI avoid tagged irq status - * because the interrupt condition is more difficult to - * fully clear in that mode. - */ tp->coalesce_mode = 0; - if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_AX && GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX) tp->coalesce_mode |= HOSTCC_MODE_32BYTE; @@ -8494,6 +8567,18 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788M)) tp->tg3_flags2 |= TG3_FLG2_IS_5788; + if (!(tp->tg3_flags2 & TG3_FLG2_IS_5788) && + (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700)) + tp->tg3_flags |= TG3_FLAG_TAGGED_STATUS; + if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { + tp->coalesce_mode |= (HOSTCC_MODE_CLRTICK_RXBD | + HOSTCC_MODE_CLRTICK_TXBD); + + tp->misc_host_ctrl |= MISC_HOST_CTRL_TAGGED_STATUS; + pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, + tp->misc_host_ctrl); + } + /* these are limited to 10/100 only */ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 && (grc_misc_cfg == 0x8000 || grc_misc_cfg == 0x4000)) || diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 8de6f21037b..44c65160a20 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2023,6 +2023,7 @@ struct tg3 { struct tg3_hw_status *hw_status; dma_addr_t status_mapping; + u32 last_tag; u32 msg_enable; @@ -2068,6 +2069,7 @@ struct tg3 { u32 rx_offset; u32 tg3_flags; +#define TG3_FLAG_TAGGED_STATUS 0x00000001 #define TG3_FLAG_TXD_MBOX_HWBUG 0x00000002 #define TG3_FLAG_RX_CHECKSUMS 0x00000004 #define TG3_FLAG_USE_LINKCHG_REG 0x00000008 -- cgit v1.2.3 From 15f9850d3c2d46f5851a424d2990a18b5bb5ebfd Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 18 May 2005 22:49:26 -0700 Subject: [TG3]: Set minimal hw interrupt mitigation. Even though we do software interrupt mitigation via NAPI, it still helps to have some minimal hw assisted mitigation. This helps, particularly, on systems where register I/O overhead is much greater than the CPU horsepower. For example, it helps on NUMA systems. In such cases the PIO overhead to disable interrupts for NAPI accounts for the majority of the packet processing cost. The CPU is fast enough such that only a single packet is processed by each NAPI poll call. Thanks to Michael Chan for reviewing this patch. Signed-off-by: David S. Miller --- drivers/net/tg3.c | 72 +++++++++++++++++++++++++++++++++++++++++++++---------- drivers/net/tg3.h | 6 ++++- 2 files changed, 64 insertions(+), 14 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 488b8c65252..3df5b78d269 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -2507,7 +2507,7 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset) if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { if (netif_carrier_ok(tp->dev)) { tw32(HOSTCC_STAT_COAL_TICKS, - DEFAULT_STAT_COAL_TICKS); + tp->coal.stats_block_coalesce_usecs); } else { tw32(HOSTCC_STAT_COAL_TICKS, 0); } @@ -5094,6 +5094,27 @@ static void tg3_set_bdinfo(struct tg3 *tp, u32 bdinfo_addr, } static void __tg3_set_rx_mode(struct net_device *); +static void tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) +{ + tw32(HOSTCC_RXCOL_TICKS, ec->rx_coalesce_usecs); + tw32(HOSTCC_TXCOL_TICKS, ec->tx_coalesce_usecs); + tw32(HOSTCC_RXMAX_FRAMES, ec->rx_max_coalesced_frames); + tw32(HOSTCC_TXMAX_FRAMES, ec->tx_max_coalesced_frames); + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + tw32(HOSTCC_RXCOAL_TICK_INT, ec->rx_coalesce_usecs_irq); + tw32(HOSTCC_TXCOAL_TICK_INT, ec->tx_coalesce_usecs_irq); + } + tw32(HOSTCC_RXCOAL_MAXF_INT, ec->rx_max_coalesced_frames_irq); + tw32(HOSTCC_TXCOAL_MAXF_INT, ec->tx_max_coalesced_frames_irq); + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + u32 val = ec->stats_block_coalesce_usecs; + + if (!netif_carrier_ok(tp->dev)) + val = 0; + + tw32(HOSTCC_STAT_COAL_TICKS, val); + } +} /* tp->lock is held. */ static int tg3_reset_hw(struct tg3 *tp) @@ -5416,16 +5437,7 @@ static int tg3_reset_hw(struct tg3 *tp) udelay(10); } - tw32(HOSTCC_RXCOL_TICKS, 0); - tw32(HOSTCC_TXCOL_TICKS, LOW_TXCOL_TICKS); - tw32(HOSTCC_RXMAX_FRAMES, 1); - tw32(HOSTCC_TXMAX_FRAMES, LOW_RXMAX_FRAMES); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { - tw32(HOSTCC_RXCOAL_TICK_INT, 0); - tw32(HOSTCC_TXCOAL_TICK_INT, 0); - } - tw32(HOSTCC_RXCOAL_MAXF_INT, 1); - tw32(HOSTCC_TXCOAL_MAXF_INT, 0); + tg3_set_coalesce(tp, &tp->coal); /* set status block DMA address */ tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH, @@ -5438,8 +5450,6 @@ static int tg3_reset_hw(struct tg3 *tp) * the tg3_periodic_fetch_stats call there, and * tg3_get_stats to see how this works for 5705/5750 chips. */ - tw32(HOSTCC_STAT_COAL_TICKS, - DEFAULT_STAT_COAL_TICKS); tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH, ((u64) tp->stats_mapping >> 32)); tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW, @@ -7284,6 +7294,14 @@ static void tg3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) } #endif +static int tg3_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) +{ + struct tg3 *tp = netdev_priv(dev); + + memcpy(ec, &tp->coal, sizeof(*ec)); + return 0; +} + static struct ethtool_ops tg3_ethtool_ops = { .get_settings = tg3_get_settings, .set_settings = tg3_set_settings, @@ -7316,6 +7334,7 @@ static struct ethtool_ops tg3_ethtool_ops = { .get_strings = tg3_get_strings, .get_stats_count = tg3_get_stats_count, .get_ethtool_stats = tg3_get_ethtool_stats, + .get_coalesce = tg3_get_coalesce, }; static void __devinit tg3_get_eeprom_size(struct tg3 *tp) @@ -9096,6 +9115,31 @@ static struct pci_dev * __devinit tg3_find_5704_peer(struct tg3 *tp) return peer; } +static void __devinit tg3_init_coal(struct tg3 *tp) +{ + struct ethtool_coalesce *ec = &tp->coal; + + memset(ec, 0, sizeof(*ec)); + ec->cmd = ETHTOOL_GCOALESCE; + ec->rx_coalesce_usecs = LOW_RXCOL_TICKS; + ec->tx_coalesce_usecs = LOW_TXCOL_TICKS; + ec->rx_max_coalesced_frames = LOW_RXMAX_FRAMES; + ec->tx_max_coalesced_frames = LOW_TXMAX_FRAMES; + ec->rx_coalesce_usecs_irq = DEFAULT_RXCOAL_TICK_INT; + ec->tx_coalesce_usecs_irq = DEFAULT_TXCOAL_TICK_INT; + ec->rx_max_coalesced_frames_irq = DEFAULT_RXCOAL_MAXF_INT; + ec->tx_max_coalesced_frames_irq = DEFAULT_TXCOAL_MAXF_INT; + ec->stats_block_coalesce_usecs = DEFAULT_STAT_COAL_TICKS; + + if (tp->coalesce_mode & (HOSTCC_MODE_CLRTICK_RXBD | + HOSTCC_MODE_CLRTICK_TXBD)) { + ec->rx_coalesce_usecs = LOW_RXCOL_TICKS_CLRTCKS; + ec->rx_coalesce_usecs_irq = DEFAULT_RXCOAL_TICK_INT_CLRTCKS; + ec->tx_coalesce_usecs = LOW_TXCOL_TICKS_CLRTCKS; + ec->tx_coalesce_usecs_irq = DEFAULT_TXCOAL_TICK_INT_CLRTCKS; + } +} + static int __devinit tg3_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -9341,6 +9385,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, /* flow control autonegotiation is default behavior */ tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; + tg3_init_coal(tp); + err = register_netdev(dev); if (err) { printk(KERN_ERR PFX "Cannot register net device, " diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 44c65160a20..993f84c93dc 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -876,10 +876,12 @@ #define HOSTCC_STATUS_ERROR_ATTN 0x00000004 #define HOSTCC_RXCOL_TICKS 0x00003c08 #define LOW_RXCOL_TICKS 0x00000032 +#define LOW_RXCOL_TICKS_CLRTCKS 0x00000014 #define DEFAULT_RXCOL_TICKS 0x00000048 #define HIGH_RXCOL_TICKS 0x00000096 #define HOSTCC_TXCOL_TICKS 0x00003c0c #define LOW_TXCOL_TICKS 0x00000096 +#define LOW_TXCOL_TICKS_CLRTCKS 0x00000048 #define DEFAULT_TXCOL_TICKS 0x0000012c #define HIGH_TXCOL_TICKS 0x00000145 #define HOSTCC_RXMAX_FRAMES 0x00003c10 @@ -892,8 +894,10 @@ #define HIGH_TXMAX_FRAMES 0x00000052 #define HOSTCC_RXCOAL_TICK_INT 0x00003c18 #define DEFAULT_RXCOAL_TICK_INT 0x00000019 +#define DEFAULT_RXCOAL_TICK_INT_CLRTCKS 0x00000014 #define HOSTCC_TXCOAL_TICK_INT 0x00003c1c #define DEFAULT_TXCOAL_TICK_INT 0x00000019 +#define DEFAULT_TXCOAL_TICK_INT_CLRTCKS 0x00000014 #define HOSTCC_RXCOAL_MAXF_INT 0x00003c20 #define DEFAULT_RXCOAL_MAXF_INT 0x00000005 #define HOSTCC_TXCOAL_MAXF_INT 0x00003c24 @@ -2227,7 +2231,7 @@ struct tg3 { #define SST_25VF0X0_PAGE_SIZE 4098 - + struct ethtool_coalesce coal; }; #endif /* !(_T3_H) */ -- cgit v1.2.3 From 59e6b4343299373bc10dd131ab5142f53ddd838a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 18 May 2005 22:50:10 -0700 Subject: [TG3]: Refine DMA boundary setting. Extract DMA boundary bit selection into a seperate function, tg3_calc_dma_bndry(). Call this from tg3_test_dma(). Make DMA test more reliable by using no DMA boundry setting during the test. If the test passes, then use the setting we selected before the test. Signed-off-by: David S. Miller Signed-off-by: Michael Chan --- drivers/net/tg3.c | 207 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 163 insertions(+), 44 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 3df5b78d269..4ab9680ffbd 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8775,6 +8775,146 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) return 0; } +#define BOUNDARY_SINGLE_CACHELINE 1 +#define BOUNDARY_MULTI_CACHELINE 2 + +static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val) +{ + int cacheline_size; + u8 byte; + int goal; + + pci_read_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE, &byte); + if (byte == 0) + cacheline_size = 1024; + else + cacheline_size = (int) byte * 4; + + /* On 5703 and later chips, the boundary bits have no + * effect. + */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 && + !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) + goto out; + +#if defined(CONFIG_PPC64) || defined(CONFIG_IA64) || defined(CONFIG_PARISC) + goal = BOUNDARY_MULTI_CACHELINE; +#else +#if defined(CONFIG_SPARC64) || defined(CONFIG_ALPHA) + goal = BOUNDARY_SINGLE_CACHELINE; +#else + goal = 0; +#endif +#endif + + if (!goal) + goto out; + + /* PCI controllers on most RISC systems tend to disconnect + * when a device tries to burst across a cache-line boundary. + * Therefore, letting tg3 do so just wastes PCI bandwidth. + * + * Unfortunately, for PCI-E there are only limited + * write-side controls for this, and thus for reads + * we will still get the disconnects. We'll also waste + * these PCI cycles for both read and write for chips + * other than 5700 and 5701 which do not implement the + * boundary bits. + */ + if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) && + !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) { + switch (cacheline_size) { + case 16: + case 32: + case 64: + case 128: + if (goal == BOUNDARY_SINGLE_CACHELINE) { + val |= (DMA_RWCTRL_READ_BNDRY_128_PCIX | + DMA_RWCTRL_WRITE_BNDRY_128_PCIX); + } else { + val |= (DMA_RWCTRL_READ_BNDRY_384_PCIX | + DMA_RWCTRL_WRITE_BNDRY_384_PCIX); + } + break; + + case 256: + val |= (DMA_RWCTRL_READ_BNDRY_256_PCIX | + DMA_RWCTRL_WRITE_BNDRY_256_PCIX); + break; + + default: + val |= (DMA_RWCTRL_READ_BNDRY_384_PCIX | + DMA_RWCTRL_WRITE_BNDRY_384_PCIX); + break; + }; + } else if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { + switch (cacheline_size) { + case 16: + case 32: + case 64: + if (goal == BOUNDARY_SINGLE_CACHELINE) { + val &= ~DMA_RWCTRL_WRITE_BNDRY_DISAB_PCIE; + val |= DMA_RWCTRL_WRITE_BNDRY_64_PCIE; + break; + } + /* fallthrough */ + case 128: + default: + val &= ~DMA_RWCTRL_WRITE_BNDRY_DISAB_PCIE; + val |= DMA_RWCTRL_WRITE_BNDRY_128_PCIE; + break; + }; + } else { + switch (cacheline_size) { + case 16: + if (goal == BOUNDARY_SINGLE_CACHELINE) { + val |= (DMA_RWCTRL_READ_BNDRY_16 | + DMA_RWCTRL_WRITE_BNDRY_16); + break; + } + /* fallthrough */ + case 32: + if (goal == BOUNDARY_SINGLE_CACHELINE) { + val |= (DMA_RWCTRL_READ_BNDRY_32 | + DMA_RWCTRL_WRITE_BNDRY_32); + break; + } + /* fallthrough */ + case 64: + if (goal == BOUNDARY_SINGLE_CACHELINE) { + val |= (DMA_RWCTRL_READ_BNDRY_64 | + DMA_RWCTRL_WRITE_BNDRY_64); + break; + } + /* fallthrough */ + case 128: + if (goal == BOUNDARY_SINGLE_CACHELINE) { + val |= (DMA_RWCTRL_READ_BNDRY_128 | + DMA_RWCTRL_WRITE_BNDRY_128); + break; + } + /* fallthrough */ + case 256: + val |= (DMA_RWCTRL_READ_BNDRY_256 | + DMA_RWCTRL_WRITE_BNDRY_256); + break; + case 512: + val |= (DMA_RWCTRL_READ_BNDRY_512 | + DMA_RWCTRL_WRITE_BNDRY_512); + break; + case 1024: + default: + val |= (DMA_RWCTRL_READ_BNDRY_1024 | + DMA_RWCTRL_WRITE_BNDRY_1024); + break; + }; + } + +out: + return val; +} + static int __devinit tg3_do_test_dma(struct tg3 *tp, u32 *buf, dma_addr_t buf_dma, int size, int to_device) { struct tg3_internal_buffer_desc test_desc; @@ -8861,7 +9001,7 @@ static int __devinit tg3_do_test_dma(struct tg3 *tp, u32 *buf, dma_addr_t buf_dm static int __devinit tg3_test_dma(struct tg3 *tp) { dma_addr_t buf_dma; - u32 *buf; + u32 *buf, saved_dma_rwctrl; int ret; buf = pci_alloc_consistent(tp->pdev, TEST_BUFFER_SIZE, &buf_dma); @@ -8873,46 +9013,7 @@ static int __devinit tg3_test_dma(struct tg3 *tp) tp->dma_rwctrl = ((0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) | (0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT)); -#ifndef CONFIG_X86 - { - u8 byte; - int cacheline_size; - pci_read_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE, &byte); - - if (byte == 0) - cacheline_size = 1024; - else - cacheline_size = (int) byte * 4; - - switch (cacheline_size) { - case 16: - case 32: - case 64: - case 128: - if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) && - !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) { - tp->dma_rwctrl |= - DMA_RWCTRL_WRITE_BNDRY_384_PCIX; - break; - } else if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { - tp->dma_rwctrl &= - ~(DMA_RWCTRL_PCI_WRITE_CMD); - tp->dma_rwctrl |= - DMA_RWCTRL_WRITE_BNDRY_128_PCIE; - break; - } - /* fallthrough */ - case 256: - if (!(tp->tg3_flags & TG3_FLAG_PCIX_MODE) && - !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) - tp->dma_rwctrl |= - DMA_RWCTRL_WRITE_BNDRY_256; - else if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) - tp->dma_rwctrl |= - DMA_RWCTRL_WRITE_BNDRY_256_PCIX; - }; - } -#endif + tp->dma_rwctrl = tg3_calc_dma_bndry(tp, tp->dma_rwctrl); if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { /* DMA read watermark not used on PCIE */ @@ -8931,7 +9032,7 @@ static int __devinit tg3_test_dma(struct tg3 *tp) if (ccval == 0x6 || ccval == 0x7) tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA; - /* Set bit 23 to renable PCIX hw bug fix */ + /* Set bit 23 to enable PCIX hw bug fix */ tp->dma_rwctrl |= 0x009f0000; } else { tp->dma_rwctrl |= 0x001b000f; @@ -8972,6 +9073,13 @@ static int __devinit tg3_test_dma(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) goto out; + /* It is best to perform DMA test with maximum write burst size + * to expose the 5700/5701 write DMA bug. + */ + saved_dma_rwctrl = tp->dma_rwctrl; + tp->dma_rwctrl &= ~DMA_RWCTRL_WRITE_BNDRY_MASK; + tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl); + while (1) { u32 *p = buf, i; @@ -9010,8 +9118,9 @@ static int __devinit tg3_test_dma(struct tg3 *tp) if (p[i] == i) continue; - if ((tp->dma_rwctrl & DMA_RWCTRL_WRITE_BNDRY_MASK) == - DMA_RWCTRL_WRITE_BNDRY_DISAB) { + if ((tp->dma_rwctrl & DMA_RWCTRL_WRITE_BNDRY_MASK) != + DMA_RWCTRL_WRITE_BNDRY_16) { + tp->dma_rwctrl &= ~DMA_RWCTRL_WRITE_BNDRY_MASK; tp->dma_rwctrl |= DMA_RWCTRL_WRITE_BNDRY_16; tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl); break; @@ -9028,6 +9137,14 @@ static int __devinit tg3_test_dma(struct tg3 *tp) break; } } + if ((tp->dma_rwctrl & DMA_RWCTRL_WRITE_BNDRY_MASK) != + DMA_RWCTRL_WRITE_BNDRY_16) { + /* DMA test passed without adjusting DMA boundary, + * just restore the calculated DMA boundary + */ + tp->dma_rwctrl = saved_dma_rwctrl; + tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl); + } out: pci_free_consistent(tp->pdev, TEST_BUFFER_SIZE, buf, buf_dma); @@ -9429,6 +9546,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, (tp->tg3_flags & TG3_FLAG_SPLIT_MODE) != 0, (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED) == 0, (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) != 0); + printk(KERN_INFO "%s: dma_rwctrl[%08x]\n", + dev->name, tp->dma_rwctrl); return 0; -- cgit v1.2.3 From f7383c22246cfccbe912541dd83103009ed2b537 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 18 May 2005 22:50:53 -0700 Subject: [TG3]: In tg3_poll(), resample status_tag after doing work. Signed-off-by: David S. Miller --- drivers/net/tg3.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 4ab9680ffbd..4d2bdbdd34e 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -2869,9 +2869,6 @@ static int tg3_poll(struct net_device *netdev, int *budget) spin_lock_irqsave(&tp->lock, flags); - if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) - tp->last_tag = sblk->status_tag; - /* handle link change and other phy events */ if (!(tp->tg3_flags & (TG3_FLAG_USE_LINKCHG_REG | @@ -2896,7 +2893,6 @@ static int tg3_poll(struct net_device *netdev, int *budget) * All RX "locking" is done by ensuring outside * code synchronizes with dev->poll() */ - done = 1; if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) { int orig_budget = *budget; int work_done; @@ -2908,12 +2904,14 @@ static int tg3_poll(struct net_device *netdev, int *budget) *budget -= work_done; netdev->quota -= work_done; - - if (work_done >= orig_budget) - done = 0; } + if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) + tp->last_tag = sblk->status_tag; + rmb(); + /* if no more work, tell net stack and NIC we're done */ + done = !tg3_has_work(tp); if (done) { spin_lock_irqsave(&tp->lock, flags); __netif_rx_complete(netdev); -- cgit v1.2.3 From d48102007d068df7ba3055cdc1723e12db1ba30f Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Wed, 18 May 2005 22:51:45 -0700 Subject: [XFRM]: skb_cow_data() does not set proper owner for new skbs. It looks like skb_cow_data() does not set proper owner for newly created skb. If we have several fragments for skb and some of them are shared(?) or cloned (like in async IPsec) there might be a situation when we require recreating skb and thus using skb_copy() for it. Newly created skb has neither a destructor nor a socket assotiated with it, which must be copied from the old skb. As far as I can see, current code sets destructor and socket for the first one skb only and uses truesize of the first skb only to increment sk_wmem_alloc value. If above "analysis" is correct then attached patch fixes that. Signed-off-by: Evgeniy Polyakov Acked-by: Herbert Xu Signed-off-by: David S. Miller --- net/xfrm/xfrm_algo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c index 080aae243ce..2f4531fcaca 100644 --- a/net/xfrm/xfrm_algo.c +++ b/net/xfrm/xfrm_algo.c @@ -698,7 +698,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer) return -ENOMEM; if (skb1->sk) - skb_set_owner_w(skb, skb1->sk); + skb_set_owner_w(skb2, skb1->sk); /* Looking around. Are we still alive? * OK, link new skb, drop old one */ -- cgit v1.2.3 From 2fdba6b085eb7068e9594cfa55ffe40466184b4d Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 18 May 2005 22:52:33 -0700 Subject: [IPV4/IPV6] Ensure all frag_list members have NULL sk Having frag_list members which holds wmem of an sk leads to nightmares with partially cloned frag skb's. The reason is that once you unleash a skb with a frag_list that has individual sk ownerships into the stack you can never undo those ownerships safely as they may have been cloned by things like netfilter. Since we have to undo them in order to make skb_linearize happy this approach leads to a dead-end. So let's go the other way and make this an invariant: For any skb on a frag_list, skb->sk must be NULL. That is, the socket ownership always belongs to the head skb. It turns out that the implementation is actually pretty simple. The above invariant is actually violated in the following patch for a short duration inside ip_fragment. This is OK because the offending frag_list member is either destroyed at the end of the slow path without being sent anywhere, or it is detached from the frag_list before being sent. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/ip_output.c | 8 ++++++++ net/ipv6/ip6_output.c | 14 ++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index daebd93fd8a..760dc8238d6 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -490,6 +490,14 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) /* Partially cloned skb? */ if (skb_shared(frag)) goto slow_path; + + BUG_ON(frag->sk); + if (skb->sk) { + sock_hold(skb->sk); + frag->sk = skb->sk; + frag->destructor = sock_wfree; + skb->truesize -= frag->truesize; + } } /* Everything is OK. Generate! */ diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 0f0711417c9..b78a5358680 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -552,13 +552,17 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) skb_headroom(frag) < hlen) goto slow_path; - /* Correct socket ownership. */ - if (frag->sk == NULL) - goto slow_path; - /* Partially cloned skb? */ if (skb_shared(frag)) goto slow_path; + + BUG_ON(frag->sk); + if (skb->sk) { + sock_hold(skb->sk); + frag->sk = skb->sk; + frag->destructor = sock_wfree; + skb->truesize -= frag->truesize; + } } err = 0; @@ -1116,12 +1120,10 @@ int ip6_push_pending_frames(struct sock *sk) tail_skb = &(tmp_skb->next); skb->len += tmp_skb->len; skb->data_len += tmp_skb->len; -#if 0 /* Logically correct, but useless work, ip_fragment() will have to undo */ skb->truesize += tmp_skb->truesize; __sock_put(tmp_skb->sk); tmp_skb->destructor = NULL; tmp_skb->sk = NULL; -#endif } ipv6_addr_copy(final_dst, &fl->fl6_dst); -- cgit v1.2.3 From 49a43876b935c811cfd29d8fe998a6912a1cc5c4 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 18 May 2005 15:39:33 -0700 Subject: [PATCH] prevent NULL mmap in topdown model Prevent the topdown allocator from allocating mmap areas all the way down to address zero. We still allow a MAP_FIXED mapping of page 0 (needed for various things, ranging from Wine and DOSEMU to people who want to allow speculative loads off a NULL pointer). Tested by Chris Wright. Signed-off-by: Linus Torvalds --- mm/mmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/mmap.c b/mm/mmap.c index 01f9793591f..63df2d69841 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1244,7 +1244,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, addr = mm->free_area_cache; /* make sure it can fit in the remaining address space */ - if (addr >= len) { + if (addr > len) { vma = find_vma(mm, addr-len); if (!vma || addr <= vma->vm_start) /* remember the address as a hint for next time */ @@ -1266,7 +1266,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, /* try just below the current vma->vm_start */ addr = vma->vm_start-len; - } while (len <= vma->vm_start); + } while (len < vma->vm_start); /* * A failed mmap() very likely causes application failure, -- cgit v1.2.3 From f81a0bffa116ea22149aa7cfb0b4ee09096d9d92 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 19 May 2005 12:26:43 -0700 Subject: [AF_UNIX]: Use lookup_create(). currently it opencodes it, but that's in the way of chaning the lookup_hash interface. I'd prefer to disallow modular af_unix over exporting lookup_create, but I'll leave that to you. Signed-off-by: Christoph Hellwig Signed-off-by: David S. Miller --- fs/namei.c | 1 + net/unix/af_unix.c | 28 +++------------------------- 2 files changed, 4 insertions(+), 25 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index defe6781e00..dd78f01b6de 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1580,6 +1580,7 @@ enoent: fail: return dentry; } +EXPORT_SYMBOL_GPL(lookup_create); int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) { diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index c478fc8db77..c420eba4876 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -770,33 +770,12 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) err = path_lookup(sunaddr->sun_path, LOOKUP_PARENT, &nd); if (err) goto out_mknod_parent; - /* - * Yucky last component or no last component at all? - * (foo/., foo/.., /////) - */ - err = -EEXIST; - if (nd.last_type != LAST_NORM) - goto out_mknod; - /* - * Lock the directory. - */ - down(&nd.dentry->d_inode->i_sem); - /* - * Do the final lookup. - */ - dentry = lookup_hash(&nd.last, nd.dentry); + + dentry = lookup_create(&nd, 0); err = PTR_ERR(dentry); if (IS_ERR(dentry)) goto out_mknod_unlock; - err = -ENOENT; - /* - * Special case - lookup gave negative, but... we had foo/bar/ - * From the vfs_mknod() POV we just have a negative dentry - - * all is fine. Let's be bastards - you had / on the end, you've - * been asking for (non-existent) directory. -ENOENT for you. - */ - if (nd.last.name[nd.last.len] && !dentry->d_inode) - goto out_mknod_dput; + /* * All right, let's create it. */ @@ -845,7 +824,6 @@ out_mknod_dput: dput(dentry); out_mknod_unlock: up(&nd.dentry->d_inode->i_sem); -out_mknod: path_release(&nd); out_mknod_parent: if (err==-EEXIST) -- cgit v1.2.3 From d9fa0f392b20b2b8e3df379c44194492a2446c6e Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Thu, 19 May 2005 12:29:59 -0700 Subject: [IP_VS]: Remove extra __ip_vs_conn_put() for incoming ICMP. Remove extra __ip_vs_conn_put for incoming ICMP in direct routing mode. Mark de Vries reports that IPVS connections are not leaked anymore. Signed-off-by: Julian Anastasov Signed-off-by: David S. Miller --- net/ipv4/ipvs/ip_vs_xmit.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c index faa6176bbeb..de21da00057 100644 --- a/net/ipv4/ipvs/ip_vs_xmit.c +++ b/net/ipv4/ipvs/ip_vs_xmit.c @@ -508,7 +508,6 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, rc = NF_ACCEPT; /* do not touch skb anymore */ atomic_inc(&cp->in_pkts); - __ip_vs_conn_put(cp); goto out; } -- cgit v1.2.3 From 8be58932ca596972e4953ae980d8bc286857cae8 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 19 May 2005 12:36:33 -0700 Subject: [NETFILTER]: Do not be clever about SKB ownership in ip_ct_gather_frags(). Just do an skb_orphan() and be done with it. Based upon discussions with Herbert Xu on netdev. Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_conntrack_core.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 28d9425d5c3..09e82462297 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -940,37 +940,25 @@ void ip_ct_refresh_acct(struct ip_conntrack *ct, struct sk_buff * ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user) { - struct sock *sk = skb->sk; #ifdef CONFIG_NETFILTER_DEBUG unsigned int olddebug = skb->nf_debug; #endif - if (sk) { - sock_hold(sk); - skb_orphan(skb); - } + skb_orphan(skb); local_bh_disable(); skb = ip_defrag(skb, user); local_bh_enable(); - if (!skb) { - if (sk) - sock_put(sk); - return skb; - } - - if (sk) { - skb_set_owner_w(skb, sk); - sock_put(sk); - } - - ip_send_check(skb->nh.iph); - skb->nfcache |= NFC_ALTERED; + if (skb) { + ip_send_check(skb->nh.iph); + skb->nfcache |= NFC_ALTERED; #ifdef CONFIG_NETFILTER_DEBUG - /* Packet path as if nothing had happened. */ - skb->nf_debug = olddebug; + /* Packet path as if nothing had happened. */ + skb->nf_debug = olddebug; #endif + } + return skb; } -- cgit v1.2.3 From b9e9dead05b19e7f52c9aa00cd3a5b7ac4fcacf4 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 19 May 2005 12:39:04 -0700 Subject: [IPSEC]: Fixed alg_key_len usage in attach_one_algo The variable alg_key_len is in bits and not bytes. The function attach_one_algo is currently using it as if it were in bytes. This causes it to read memory which may not be there. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 5ddda2c98af..15ba08602aa 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -162,6 +162,7 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props, struct rtattr *rta = u_arg; struct xfrm_algo *p, *ualg; struct xfrm_algo_desc *algo; + int len; if (!rta) return 0; @@ -173,11 +174,12 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props, return -ENOSYS; *props = algo->desc.sadb_alg_id; - p = kmalloc(sizeof(*ualg) + ualg->alg_key_len, GFP_KERNEL); + len = sizeof(*ualg) + (ualg->alg_key_len + 7U) / 8; + p = kmalloc(len, GFP_KERNEL); if (!p) return -ENOMEM; - memcpy(p, ualg, sizeof(*ualg) + ualg->alg_key_len); + memcpy(p, ualg, len); *algpp = p; return 0; } -- cgit v1.2.3 From 31c26852cb2ac77f1d4acb37bcf31f165fd5eb68 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 19 May 2005 12:39:49 -0700 Subject: [IPSEC]: Verify key payload in verify_one_algo We need to verify that the payload contains enough data so that attach_one_algo can copy alg_key_len bits from the payload. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 15ba08602aa..97509011c27 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -34,14 +34,21 @@ static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) { struct rtattr *rt = xfrma[type - 1]; struct xfrm_algo *algp; + int len; if (!rt) return 0; - if ((rt->rta_len - sizeof(*rt)) < sizeof(*algp)) + len = (rt->rta_len - sizeof(*rt)) - sizeof(*algp); + if (len < 0) return -EINVAL; algp = RTA_DATA(rt); + + len -= (algp->alg_key_len + 7U) / 8; + if (len < 0) + return -EINVAL; + switch (type) { case XFRMA_ALG_AUTH: if (!algp->alg_key_len && -- cgit v1.2.3 From 1eda339e76a9aac05883c548028bf91aed734783 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Thu, 19 May 2005 12:42:39 -0700 Subject: [PKT_SCHED]: Fixup simple action define. Make it consistent with other net/sched files Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- include/net/act_generic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/net/act_generic.h b/include/net/act_generic.h index 95b120781c1..c9daa7e5230 100644 --- a/include/net/act_generic.h +++ b/include/net/act_generic.h @@ -2,8 +2,8 @@ * include/net/act_generic.h * */ -#ifndef ACT_GENERIC_H -#define ACT_GENERIC_H +#ifndef _NET_ACT_GENERIC_H +#define _NET_ACT_GENERIC_H static inline int tcf_defact_release(struct tcf_defact *p, int bind) { int ret = 0; -- cgit v1.2.3 From db61ecc3352d72513c1b07805bd6f760e30c001b Mon Sep 17 00:00:00 2001 From: "Tommy S. Christensen" Date: Thu, 19 May 2005 12:46:59 -0700 Subject: [NETLINK]: Fix race with recvmsg(). This bug causes: assertion (!atomic_read(&sk->sk_rmem_alloc)) failed at net/netlink/af_netlink.c (122) What's happening is that: 1) The skb is sent to socket 1. 2) Someone does a recvmsg on socket 1 and drops the ref on the skb. Note that the rmalloc is not returned at this point since the skb is still referenced. 3) The same skb is now sent to socket 2. This version of the fix resurrects the skb_orphan call that was moved out, last time we had 'shared-skb troubles'. It is practically a no-op in the common case, but still prevents the possible race with recvmsg. Signed-off-by: Tommy S. Christensen Acked-by: Herbert Xu Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 733bf52cef3..b40c9a97696 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -697,6 +697,7 @@ static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf && !test_bit(0, &nlk->state)) { + skb_orphan(skb); skb_set_owner_r(skb, sk); skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_data_ready(sk, skb->len); -- cgit v1.2.3 From 68acc024ea7391e03c2c695ba0b9fb31baa974bf Mon Sep 17 00:00:00 2001 From: "Tommy S. Christensen" Date: Thu, 19 May 2005 13:06:35 -0700 Subject: [NETLINK]: Move broadcast skb_orphan to the skb_get path. Cloned packets don't need the orphan call. Signed-off-by: Tommy S. Christensen Acked-by: Herbert Xu Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index b40c9a97696..4b91f4b84cb 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -697,7 +697,6 @@ static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf && !test_bit(0, &nlk->state)) { - skb_orphan(skb); skb_set_owner_r(skb, sk); skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_data_ready(sk, skb->len); @@ -736,11 +735,15 @@ static inline int do_one_broadcast(struct sock *sk, sock_hold(sk); if (p->skb2 == NULL) { - if (atomic_read(&p->skb->users) != 1) { + if (skb_shared(p->skb)) { p->skb2 = skb_clone(p->skb, p->allocation); } else { - p->skb2 = p->skb; - atomic_inc(&p->skb->users); + p->skb2 = skb_get(p->skb); + /* + * skb ownership may have been set when + * delivered to a previous socket. + */ + skb_orphan(p->skb2); } } if (p->skb2 == NULL) { -- cgit v1.2.3 From aa1c6a6f7f0518b42994d02756a41cbfdcac1916 Mon Sep 17 00:00:00 2001 From: "Tommy S. Christensen" Date: Thu, 19 May 2005 13:07:32 -0700 Subject: [NETLINK]: Defer socket destruction a bit In netlink_broadcast() we're sending shared skb's to netlink listeners when possible (saves some copying). This is OK, since we hold the only other reference to the skb. However, this implies that we must drop our reference on the skb, before allowing a receiving socket to disappear. Otherwise, the socket buffer accounting is disrupted. Signed-off-by: Tommy S. Christensen Acked-by: Herbert Xu Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 4b91f4b84cb..e41ce458c2a 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -789,11 +789,12 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list) do_one_broadcast(sk, &info); + kfree_skb(skb); + netlink_unlock_table(); if (info.skb2) kfree_skb(info.skb2); - kfree_skb(skb); if (info.delivered) { if (info.congested && (allocation & __GFP_WAIT)) -- cgit v1.2.3 From 07ab67c8d0d7c1021343b7d5c045033d6bf7be69 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 19 May 2005 22:43:37 -0700 Subject: Fix get_unmapped_area sanity tests As noted by Chris Wright, we need to do the full range of tests regardless of whether MAP_FIXED is set or not, so re-organize get_unmapped_area() slightly to do the sanity checks unconditionally. --- include/linux/err.h | 4 +++- mm/mmap.c | 59 ++++++++++++++++++++++++++++------------------------- 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/include/linux/err.h b/include/linux/err.h index 17c55df1361..ff71d2af5da 100644 --- a/include/linux/err.h +++ b/include/linux/err.h @@ -13,6 +13,8 @@ * This should be a per-architecture thing, to allow different * error and pointer decisions. */ +#define IS_ERR_VALUE(x) unlikely((x) > (unsigned long)-1000L) + static inline void *ERR_PTR(long error) { return (void *) error; @@ -25,7 +27,7 @@ static inline long PTR_ERR(const void *ptr) static inline long IS_ERR(const void *ptr) { - return unlikely((unsigned long)ptr > (unsigned long)-1000L); + return IS_ERR_VALUE((unsigned long)ptr); } #endif /* _LINUX_ERR_H */ diff --git a/mm/mmap.c b/mm/mmap.c index 63df2d69841..de54acd9942 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1302,37 +1302,40 @@ unsigned long get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { - if (flags & MAP_FIXED) { - unsigned long ret; + unsigned long ret; - if (addr > TASK_SIZE - len) - return -ENOMEM; - if (addr & ~PAGE_MASK) - return -EINVAL; - if (file && is_file_hugepages(file)) { - /* - * Check if the given range is hugepage aligned, and - * can be made suitable for hugepages. - */ - ret = prepare_hugepage_range(addr, len); - } else { - /* - * Ensure that a normal request is not falling in a - * reserved hugepage range. For some archs like IA-64, - * there is a separate region for hugepages. - */ - ret = is_hugepage_only_range(current->mm, addr, len); - } - if (ret) - return -EINVAL; - return addr; - } + if (!(flags & MAP_FIXED)) { + unsigned long (*get_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); - if (file && file->f_op && file->f_op->get_unmapped_area) - return file->f_op->get_unmapped_area(file, addr, len, - pgoff, flags); + get_area = current->mm->get_unmapped_area; + if (file && file->f_op && file->f_op->get_unmapped_area) + get_area = file->f_op->get_unmapped_area; + addr = get_area(file, addr, len, pgoff, flags); + if (IS_ERR_VALUE(addr)) + return addr; + } - return current->mm->get_unmapped_area(file, addr, len, pgoff, flags); + if (addr > TASK_SIZE - len) + return -ENOMEM; + if (addr & ~PAGE_MASK) + return -EINVAL; + if (file && is_file_hugepages(file)) { + /* + * Check if the given range is hugepage aligned, and + * can be made suitable for hugepages. + */ + ret = prepare_hugepage_range(addr, len); + } else { + /* + * Ensure that a normal request is not falling in a + * reserved hugepage range. For some archs like IA-64, + * there is a separate region for hugepages. + */ + ret = is_hugepage_only_range(current->mm, addr, len); + } + if (ret) + return -EINVAL; + return addr; } EXPORT_SYMBOL(get_unmapped_area); -- cgit v1.2.3 From 6c37a88c5b1195d4ac74d44a6413839b93df5af4 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 20 May 2005 16:57:22 +1000 Subject: [PATCH] ppc32: don't call progress functions after boot On ppc32, the platform code can supply a "progress" function that is used to show progress through the boot. These functions are usually in an init section and so can't be called after the init pages are freed. Now that the cpu bringup code can be called after the system is booted (for hotplug cpu) we can get the situation where the progress function can be called after boot. The simple fix is to set the progress function pointer to NULL when the init pages are freed, and that is what this patch does (note that all callers already check whether the function pointer is NULL before trying to call it). Signed-off-by: Paul Mackerras Signed-off-by: Linus Torvalds --- arch/ppc/mm/init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index be02a7fec2b..363c157e361 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -179,6 +179,7 @@ void free_initmem(void) if (!have_of) FREESEC(openfirmware); printk("\n"); + ppc_md.progress = NULL; #undef FREESEC } -- cgit v1.2.3 From 3207a80a6e11c7ceff7e46d5ec6bfcc03c14e729 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 20 May 2005 17:15:00 +1000 Subject: [PATCH] ppc32: remove unused computation We are computing phys in the code below and never using. This patch takes out the redundant computation. Signed-off-by: Paul Mackerras Signed-off-by: Linus Torvalds --- arch/ppc/syslib/open_pic.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c index 7619e16fcca..9d4ed68b580 100644 --- a/arch/ppc/syslib/open_pic.c +++ b/arch/ppc/syslib/open_pic.c @@ -557,12 +557,10 @@ static void __init openpic_initipi(u_int ipi, u_int pri, u_int vec) */ void openpic_cause_IPI(u_int ipi, cpumask_t cpumask) { - cpumask_t phys; DECL_THIS_CPU; CHECK_THIS_CPU; check_arg_ipi(ipi); - phys = physmask(cpumask); openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi), cpus_addr(physmask(cpumask))[0]); } -- cgit v1.2.3 From 72480ef863740c3dc301b0803c9ed6d10716aa11 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 20 May 2005 16:50:55 +1000 Subject: [PATCH] ppc32: Fix __copy_tofrom_user return value Recently the __copy_tofrom_user routine was modified to avoid doing prefetches past the end of the source array. However, in doing so we introduced a bug in that it now returns the wrong value for the number of bytes not copied when a fault is encountered. This fixes it to return the correct number. Signed-off-by: Paul Mackerras Signed-off-by: Linus Torvalds --- arch/ppc/lib/string.S | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/ppc/lib/string.S b/arch/ppc/lib/string.S index 8d08a2eb225..36c9b97fd92 100644 --- a/arch/ppc/lib/string.S +++ b/arch/ppc/lib/string.S @@ -446,6 +446,7 @@ _GLOBAL(__copy_tofrom_user) #ifdef CONFIG_8xx /* Don't use prefetch on 8xx */ mtctr r0 + li r0,0 53: COPY_16_BYTES_WITHEX(0) bdnz 53b @@ -564,7 +565,9 @@ _GLOBAL(__copy_tofrom_user) /* or write fault in cacheline loop */ 105: li r9,1 92: li r3,LG_CACHELINE_BYTES - b 99f + mfctr r8 + add r0,r0,r8 + b 106f /* read fault in final word loop */ 108: li r9,0 b 93f @@ -585,7 +588,7 @@ _GLOBAL(__copy_tofrom_user) * r5 + (ctr << r3), and r9 is 0 for read or 1 for write. */ 99: mfctr r0 - slw r3,r0,r3 +106: slw r3,r0,r3 add. r3,r3,r5 beq 120f /* shouldn't happen */ cmpwi 0,r9,0 -- cgit v1.2.3 From 45fed46f5b98aaf439e9ef125992ec853cd98499 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 20 May 2005 16:45:58 +1000 Subject: [PATCH] ppx32: Fix uninitialized variable in set_preferred_console This fixes an uninitialized variable warning in arch/ppc/kernel/setup.c, and this time gcc is actually right, there is a path that could result in offset being uninitialized. Zero is a sane default in this instance. Signed-off-by: Paul Mackerras Signed-off-by: Linus Torvalds --- arch/ppc/kernel/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 309797d7f96..5c20266e3b1 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -499,7 +499,7 @@ static int __init set_preferred_console(void) { struct device_node *prom_stdout; char *name; - int offset; + int offset = 0; if (of_stdout_device == NULL) return -ENODEV; -- cgit v1.2.3 From 37e0915b701281182cea9fc90e894d10addf134a Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Fri, 20 May 2005 08:56:23 +0200 Subject: [PATCH] Add sysfs support for the IPMI device interface Add support for sysfs to the IPMI device interface. Clean-ups based on Dimitry Torokovs comment by Philipp Hahn. Signed-off-by: Corey Minyard Signed-off-by: Philipp Hahn Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_devintf.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 49d67f5384a..4bb9af736fb 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -44,6 +44,7 @@ #include #include #include +#include #define IPMI_DEVINTF_VERSION "v33" @@ -519,15 +520,21 @@ MODULE_PARM_DESC(ipmi_major, "Sets the major number of the IPMI device. By" " interface. Other values will set the major device number" " to that value."); +static struct class *ipmi_class; + static void ipmi_new_smi(int if_num) { - devfs_mk_cdev(MKDEV(ipmi_major, if_num), - S_IFCHR | S_IRUSR | S_IWUSR, + dev_t dev = MKDEV(ipmi_major, if_num); + + devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, "ipmidev/%d", if_num); + + class_simple_device_add(ipmi_class, dev, NULL, "ipmi%d", if_num); } static void ipmi_smi_gone(int if_num) { + class_simple_device_remove(ipmi_class, MKDEV(ipmi_major, if_num)); devfs_remove("ipmidev/%d", if_num); } @@ -548,8 +555,15 @@ static __init int init_ipmi_devintf(void) printk(KERN_INFO "ipmi device interface version " IPMI_DEVINTF_VERSION "\n"); + ipmi_class = class_simple_create(THIS_MODULE, "ipmi"); + if (IS_ERR(ipmi_class)) { + printk(KERN_ERR "ipmi: can't register device class\n"); + return PTR_ERR(ipmi_class); + } + rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops); if (rv < 0) { + class_simple_destroy(ipmi_class); printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major); return rv; } @@ -563,6 +577,7 @@ static __init int init_ipmi_devintf(void) rv = ipmi_smi_watcher_register(&smi_watcher); if (rv) { unregister_chrdev(ipmi_major, DEVICE_NAME); + class_simple_destroy(ipmi_class); printk(KERN_WARNING "ipmi: can't register smi watcher\n"); return rv; } @@ -573,6 +588,7 @@ module_init(init_ipmi_devintf); static __exit void cleanup_ipmi(void) { + class_simple_destroy(ipmi_class); ipmi_smi_watcher_unregister(&smi_watcher); devfs_remove(DEVICE_NAME); unregister_chrdev(ipmi_major, DEVICE_NAME); -- cgit v1.2.3 From a228dfd5dc4b92288ea22d427b2bfc48ba5bb8b0 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 20 May 2005 11:40:32 -0700 Subject: [SPARC64]: Fix bad performance side effect of strbuf timeout changes. The recent change to add a timeout to strbuf flushing had a negative performance impact. The udelay()'s are too long, and they were done in the wrong order wrt. the register read checks. Fix both, and things are happy again. There are more possible improvements in this area. In fact, PCI streaming buffer flushing seems to be part of the bottleneck in network receive performance on my SunBlade1000 box. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_iommu.c | 16 +++++++++------- arch/sparc64/kernel/sbus.c | 4 ++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c index f009b1b4550..33ca56c90da 100644 --- a/arch/sparc64/kernel/pci_iommu.c +++ b/arch/sparc64/kernel/pci_iommu.c @@ -392,14 +392,16 @@ static void pci_strbuf_flush(struct pci_strbuf *strbuf, struct pci_iommu *iommu, flushreg = strbuf->strbuf_ctxflush; matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); - limit = 10000; - do { - pci_iommu_write(flushreg, ctx); - udelay(10); + limit = 100000; + pci_iommu_write(flushreg, ctx); + for(;;) { + if (((long)pci_iommu_read(matchreg)) >= 0L) + break; limit--; if (!limit) break; - } while(((long)pci_iommu_read(matchreg)) < 0L); + udelay(1); + } if (!limit) printk(KERN_WARNING "pci_strbuf_flush: ctx flush " "timeout vaddr[%08x] ctx[%lx]\n", @@ -414,12 +416,12 @@ static void pci_strbuf_flush(struct pci_strbuf *strbuf, struct pci_iommu *iommu, pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); (void) pci_iommu_read(iommu->write_complete_reg); - limit = 10000; + limit = 100000; while (!PCI_STC_FLUSHFLAG_SET(strbuf)) { limit--; if (!limit) break; - udelay(10); + udelay(1); membar("#LoadLoad"); } if (!limit) diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index d3eca98e1fe..76ea6455433 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -133,12 +133,12 @@ static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long iommu->strbuf_regs + STRBUF_FSYNC); upa_readq(iommu->sbus_control_reg); - limit = 10000; + limit = 100000; while (iommu->strbuf_flushflag == 0UL) { limit--; if (!limit) break; - udelay(10); + udelay(1); membar("#LoadLoad"); } if (!limit) -- cgit v1.2.3 From 1c7878f024705594ac455e501ad51e475a400d5d Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 20 May 2005 13:36:19 -0700 Subject: Remove some left-over empty files Hopefully the addition of -E to my applypatch script will mean that I won't have these kinds of leftovers in the future. --- arch/um/kernel/checksum.c | 0 include/asm-ia64/ioctl32.h | 0 include/asm-um/arch-signal-i386.h | 0 include/asm-x86_64/ioctl32.h | 0 4 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 arch/um/kernel/checksum.c delete mode 100644 include/asm-ia64/ioctl32.h delete mode 100644 include/asm-um/arch-signal-i386.h delete mode 100644 include/asm-x86_64/ioctl32.h diff --git a/arch/um/kernel/checksum.c b/arch/um/kernel/checksum.c deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/include/asm-ia64/ioctl32.h b/include/asm-ia64/ioctl32.h deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/include/asm-um/arch-signal-i386.h b/include/asm-um/arch-signal-i386.h deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/include/asm-x86_64/ioctl32.h b/include/asm-x86_64/ioctl32.h deleted file mode 100644 index e69de29bb2d..00000000000 -- cgit v1.2.3 From 62a8612972eaea804e1e42c63ee403cd4e14cc35 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 6 May 2005 18:05:20 -0500 Subject: [SCSI] implement parameter limits in the SPI transport class There's a basic need not to have parameters go under or over certain values when doing domain validation. The basic ones are max_offset, max_width and min_period This patch makes the transport class take and enforce these three limits. Currently they can be set by the user, although they could obviously be read from the HBA's on-board NVRAM area during slave_configure (if it has one). Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_spi.c | 188 ++++++++++++++++++++++++++++++++------ include/scsi/scsi_transport_spi.h | 6 ++ 2 files changed, 167 insertions(+), 27 deletions(-) diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 28966d05435..67c6cc40ce1 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -35,7 +35,7 @@ #define SPI_PRINTK(x, l, f, a...) dev_printk(l, &(x)->dev, f , ##a) -#define SPI_NUM_ATTRS 10 /* increase this if you add attributes */ +#define SPI_NUM_ATTRS 13 /* increase this if you add attributes */ #define SPI_OTHER_ATTRS 1 /* Increase this if you add "always * on" attributes */ #define SPI_HOST_ATTRS 1 @@ -219,8 +219,11 @@ static int spi_setup_transport_attrs(struct device *dev) struct scsi_target *starget = to_scsi_target(dev); spi_period(starget) = -1; /* illegal value */ + spi_min_period(starget) = 0; spi_offset(starget) = 0; /* async */ + spi_max_offset(starget) = 255; spi_width(starget) = 0; /* narrow */ + spi_max_width(starget) = 1; spi_iu(starget) = 0; /* no IU */ spi_dt(starget) = 0; /* ST */ spi_qas(starget) = 0; @@ -235,6 +238,34 @@ static int spi_setup_transport_attrs(struct device *dev) return 0; } +#define spi_transport_show_simple(field, format_string) \ + \ +static ssize_t \ +show_spi_transport_##field(struct class_device *cdev, char *buf) \ +{ \ + struct scsi_target *starget = transport_class_to_starget(cdev); \ + struct spi_transport_attrs *tp; \ + \ + tp = (struct spi_transport_attrs *)&starget->starget_data; \ + return snprintf(buf, 20, format_string, tp->field); \ +} + +#define spi_transport_store_simple(field, format_string) \ + \ +static ssize_t \ +store_spi_transport_##field(struct class_device *cdev, const char *buf, \ + size_t count) \ +{ \ + int val; \ + struct scsi_target *starget = transport_class_to_starget(cdev); \ + struct spi_transport_attrs *tp; \ + \ + tp = (struct spi_transport_attrs *)&starget->starget_data; \ + val = simple_strtoul(buf, NULL, 0); \ + tp->field = val; \ + return count; \ +} + #define spi_transport_show_function(field, format_string) \ \ static ssize_t \ @@ -261,6 +292,25 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \ struct spi_internal *i = to_spi_internal(shost->transportt); \ \ val = simple_strtoul(buf, NULL, 0); \ + i->f->set_##field(starget, val); \ + return count; \ +} + +#define spi_transport_store_max(field, format_string) \ +static ssize_t \ +store_spi_transport_##field(struct class_device *cdev, const char *buf, \ + size_t count) \ +{ \ + int val; \ + struct scsi_target *starget = transport_class_to_starget(cdev); \ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \ + struct spi_internal *i = to_spi_internal(shost->transportt); \ + struct spi_transport_attrs *tp \ + = (struct spi_transport_attrs *)&starget->starget_data; \ + \ + val = simple_strtoul(buf, NULL, 0); \ + if (val > tp->max_##field) \ + val = tp->max_##field; \ i->f->set_##field(starget, val); \ return count; \ } @@ -272,9 +322,24 @@ static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \ show_spi_transport_##field, \ store_spi_transport_##field); +#define spi_transport_simple_attr(field, format_string) \ + spi_transport_show_simple(field, format_string) \ + spi_transport_store_simple(field, format_string) \ +static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \ + show_spi_transport_##field, \ + store_spi_transport_##field); + +#define spi_transport_max_attr(field, format_string) \ + spi_transport_show_function(field, format_string) \ + spi_transport_store_max(field, format_string) \ + spi_transport_simple_attr(max_##field, format_string) \ +static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \ + show_spi_transport_##field, \ + store_spi_transport_##field); + /* The Parallel SCSI Tranport Attributes: */ -spi_transport_rd_attr(offset, "%d\n"); -spi_transport_rd_attr(width, "%d\n"); +spi_transport_max_attr(offset, "%d\n"); +spi_transport_max_attr(width, "%d\n"); spi_transport_rd_attr(iu, "%d\n"); spi_transport_rd_attr(dt, "%d\n"); spi_transport_rd_attr(qas, "%d\n"); @@ -300,26 +365,18 @@ static CLASS_DEVICE_ATTR(revalidate, S_IWUSR, NULL, store_spi_revalidate); /* Translate the period into ns according to the current spec * for SDTR/PPR messages */ -static ssize_t show_spi_transport_period(struct class_device *cdev, char *buf) - +static ssize_t +show_spi_transport_period_helper(struct class_device *cdev, char *buf, + int period) { - struct scsi_target *starget = transport_class_to_starget(cdev); - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct spi_transport_attrs *tp; int len, picosec; - struct spi_internal *i = to_spi_internal(shost->transportt); - - tp = (struct spi_transport_attrs *)&starget->starget_data; - - if (i->f->get_period) - i->f->get_period(starget); - if (tp->period < 0 || tp->period > 0xff) { + if (period < 0 || period > 0xff) { picosec = -1; - } else if (tp->period <= SPI_STATIC_PPR) { - picosec = ppr_to_ps[tp->period]; + } else if (period <= SPI_STATIC_PPR) { + picosec = ppr_to_ps[period]; } else { - picosec = tp->period * 4000; + picosec = period * 4000; } if (picosec == -1) { @@ -334,12 +391,9 @@ static ssize_t show_spi_transport_period(struct class_device *cdev, char *buf) } static ssize_t -store_spi_transport_period(struct class_device *cdev, const char *buf, - size_t count) +store_spi_transport_period_helper(struct class_device *cdev, const char *buf, + size_t count, int *periodp) { - struct scsi_target *starget = transport_class_to_starget(cdev); - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct spi_internal *i = to_spi_internal(shost->transportt); int j, picosec, period = -1; char *endp; @@ -368,15 +422,79 @@ store_spi_transport_period(struct class_device *cdev, const char *buf, if (period > 0xff) period = 0xff; - i->f->set_period(starget, period); + *periodp = period; return count; } +static ssize_t +show_spi_transport_period(struct class_device *cdev, char *buf) +{ + struct scsi_target *starget = transport_class_to_starget(cdev); + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct spi_internal *i = to_spi_internal(shost->transportt); + struct spi_transport_attrs *tp = + (struct spi_transport_attrs *)&starget->starget_data; + + if (i->f->get_period) + i->f->get_period(starget); + + return show_spi_transport_period_helper(cdev, buf, tp->period); +} + +static ssize_t +store_spi_transport_period(struct class_device *cdev, const char *buf, + size_t count) +{ + struct scsi_target *starget = transport_class_to_starget(cdev); + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct spi_internal *i = to_spi_internal(shost->transportt); + struct spi_transport_attrs *tp = + (struct spi_transport_attrs *)&starget->starget_data; + int period, retval; + + retval = store_spi_transport_period_helper(cdev, buf, count, &period); + + if (period < tp->min_period) + period = tp->min_period; + + i->f->set_period(starget, period); + + return retval; +} + static CLASS_DEVICE_ATTR(period, S_IRUGO | S_IWUSR, show_spi_transport_period, store_spi_transport_period); +static ssize_t +show_spi_transport_min_period(struct class_device *cdev, char *buf) +{ + struct scsi_target *starget = transport_class_to_starget(cdev); + struct spi_transport_attrs *tp = + (struct spi_transport_attrs *)&starget->starget_data; + + return show_spi_transport_period_helper(cdev, buf, tp->min_period); +} + +static ssize_t +store_spi_transport_min_period(struct class_device *cdev, const char *buf, + size_t count) +{ + struct scsi_target *starget = transport_class_to_starget(cdev); + struct spi_transport_attrs *tp = + (struct spi_transport_attrs *)&starget->starget_data; + + return store_spi_transport_period_helper(cdev, buf, count, + &tp->min_period); +} + + +static CLASS_DEVICE_ATTR(min_period, S_IRUGO | S_IWUSR, + show_spi_transport_min_period, + store_spi_transport_min_period); + + static ssize_t show_spi_host_signalling(struct class_device *cdev, char *buf) { struct Scsi_Host *shost = transport_class_to_shost(cdev); @@ -642,6 +760,7 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) { struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt); struct scsi_device *sdev = sreq->sr_device; + struct scsi_target *starget = sdev->sdev_target; int len = sdev->inquiry_len; /* first set us up for narrow async */ DV_SET(offset, 0); @@ -655,9 +774,11 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) } /* test width */ - if (i->f->set_width && sdev->wdtr) { + if (i->f->set_width && spi_max_width(starget) && sdev->wdtr) { i->f->set_width(sdev->sdev_target, 1); + printk("WIDTH IS %d\n", spi_max_width(starget)); + if (spi_dv_device_compare_inquiry(sreq, buffer, buffer + len, DV_LOOPS) @@ -684,8 +805,8 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) retry: /* now set up to the maximum */ - DV_SET(offset, 255); - DV_SET(period, 1); + DV_SET(offset, spi_max_offset(starget)); + DV_SET(period, spi_min_period(starget)); if (len == 0) { SPI_PRINTK(sdev->sdev_target, KERN_INFO, "Domain Validation skipping write tests\n"); @@ -892,6 +1013,16 @@ EXPORT_SYMBOL(spi_display_xfer_agreement); if (i->f->show_##field) \ count++ +#define SETUP_RELATED_ATTRIBUTE(field, rel_field) \ + i->private_attrs[count] = class_device_attr_##field; \ + if (!i->f->set_##rel_field) { \ + i->private_attrs[count].attr.mode = S_IRUGO; \ + i->private_attrs[count].store = NULL; \ + } \ + i->attrs[count] = &i->private_attrs[count]; \ + if (i->f->show_##rel_field) \ + count++ + #define SETUP_HOST_ATTRIBUTE(field) \ i->private_host_attrs[count] = class_device_attr_##field; \ if (!i->f->set_##field) { \ @@ -975,8 +1106,11 @@ spi_attach_transport(struct spi_function_template *ft) i->f = ft; SETUP_ATTRIBUTE(period); + SETUP_RELATED_ATTRIBUTE(min_period, period); SETUP_ATTRIBUTE(offset); + SETUP_RELATED_ATTRIBUTE(max_offset, offset); SETUP_ATTRIBUTE(width); + SETUP_RELATED_ATTRIBUTE(max_width, width); SETUP_ATTRIBUTE(iu); SETUP_ATTRIBUTE(dt); SETUP_ATTRIBUTE(qas); diff --git a/include/scsi/scsi_transport_spi.h b/include/scsi/scsi_transport_spi.h index 6dcf497bf46..a30d6cd4c0e 100644 --- a/include/scsi/scsi_transport_spi.h +++ b/include/scsi/scsi_transport_spi.h @@ -27,8 +27,11 @@ struct scsi_transport_template; struct spi_transport_attrs { int period; /* value in the PPR/SDTR command */ + int min_period; int offset; + int max_offset; unsigned int width:1; /* 0 - narrow, 1 - wide */ + unsigned int max_width:1; unsigned int iu:1; /* Information Units enabled */ unsigned int dt:1; /* DT clocking enabled */ unsigned int qas:1; /* Quick Arbitration and Selection enabled */ @@ -63,8 +66,11 @@ struct spi_host_attrs { /* accessor functions */ #define spi_period(x) (((struct spi_transport_attrs *)&(x)->starget_data)->period) +#define spi_min_period(x) (((struct spi_transport_attrs *)&(x)->starget_data)->min_period) #define spi_offset(x) (((struct spi_transport_attrs *)&(x)->starget_data)->offset) +#define spi_max_offset(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_offset) #define spi_width(x) (((struct spi_transport_attrs *)&(x)->starget_data)->width) +#define spi_max_width(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_width) #define spi_iu(x) (((struct spi_transport_attrs *)&(x)->starget_data)->iu) #define spi_dt(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dt) #define spi_qas(x) (((struct spi_transport_attrs *)&(x)->starget_data)->qas) -- cgit v1.2.3 From fad01ef88d2a27303757924c1fc013b31fe9a76b Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 8 May 2005 16:00:15 -0500 Subject: [SCSI] correct aic7xxx period setting routines This is similar to the previous sym2 problem. For Domain Validation to work we can't allow any period setting to turn wide on if it was previously off. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7xxx_osm.c | 71 ++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index d978e4a3e97..0ed9ccc3091 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -3346,6 +3346,32 @@ ahc_platform_dump_card_state(struct ahc_softc *ahc) static void ahc_linux_exit(void); +static void ahc_linux_get_width(struct scsi_target *starget) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata); + struct ahc_tmode_tstate *tstate; + struct ahc_initiator_tinfo *tinfo + = ahc_fetch_transinfo(ahc, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + spi_width(starget) = tinfo->curr.width; +} + +static void ahc_linux_set_width(struct scsi_target *starget, int width) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata); + struct ahc_devinfo devinfo; + unsigned long flags; + + ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + ahc_lock(ahc, &flags); + ahc_set_width(ahc, &devinfo, width, AHC_TRANS_GOAL, FALSE); + ahc_unlock(ahc, &flags); +} + static void ahc_linux_get_period(struct scsi_target *starget) { struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); @@ -3378,6 +3404,14 @@ static void ahc_linux_set_period(struct scsi_target *starget, int period) ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, starget->channel + 'A', ROLE_INITIATOR); + + /* all PPR requests apart from QAS require wide transfers */ + if (ppr_options & ~MSG_EXT_PPR_QAS_REQ) { + ahc_linux_get_width(starget); + if (spi_width(starget) == 0) + ppr_options &= MSG_EXT_PPR_QAS_REQ; + } + syncrate = ahc_find_syncrate(ahc, &period, &ppr_options, AHC_SYNCRATE_DT); ahc_lock(ahc, &flags); ahc_set_syncrate(ahc, &devinfo, syncrate, period, offset, @@ -3425,32 +3459,6 @@ static void ahc_linux_set_offset(struct scsi_target *starget, int offset) ahc_unlock(ahc, &flags); } -static void ahc_linux_get_width(struct scsi_target *starget) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata); - struct ahc_tmode_tstate *tstate; - struct ahc_initiator_tinfo *tinfo - = ahc_fetch_transinfo(ahc, - starget->channel + 'A', - shost->this_id, starget->id, &tstate); - spi_width(starget) = tinfo->curr.width; -} - -static void ahc_linux_set_width(struct scsi_target *starget, int width) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata); - struct ahc_devinfo devinfo; - unsigned long flags; - - ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, - starget->channel + 'A', ROLE_INITIATOR); - ahc_lock(ahc, &flags); - ahc_set_width(ahc, &devinfo, width, AHC_TRANS_GOAL, FALSE); - ahc_unlock(ahc, &flags); -} - static void ahc_linux_get_dt(struct scsi_target *starget) { struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); @@ -3481,8 +3489,7 @@ static void ahc_linux_set_dt(struct scsi_target *starget, int dt) ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, starget->channel + 'A', ROLE_INITIATOR); - syncrate = ahc_find_syncrate(ahc, &period, &ppr_options, - dt ? AHC_SYNCRATE_DT : AHC_SYNCRATE_ULTRA2); + syncrate = ahc_find_syncrate(ahc, &period, &ppr_options,AHC_SYNCRATE_DT); ahc_lock(ahc, &flags); ahc_set_syncrate(ahc, &devinfo, syncrate, period, tinfo->curr.offset, ppr_options, AHC_TRANS_GOAL, FALSE); @@ -3514,7 +3521,6 @@ static void ahc_linux_set_qas(struct scsi_target *starget, int qas) unsigned int ppr_options = tinfo->curr.ppr_options & ~MSG_EXT_PPR_QAS_REQ; unsigned int period = tinfo->curr.period; - unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; unsigned long flags; struct ahc_syncrate *syncrate; @@ -3523,8 +3529,7 @@ static void ahc_linux_set_qas(struct scsi_target *starget, int qas) ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, starget->channel + 'A', ROLE_INITIATOR); - syncrate = ahc_find_syncrate(ahc, &period, &ppr_options, - dt ? AHC_SYNCRATE_DT : AHC_SYNCRATE_ULTRA2); + syncrate = ahc_find_syncrate(ahc, &period, &ppr_options, AHC_SYNCRATE_DT); ahc_lock(ahc, &flags); ahc_set_syncrate(ahc, &devinfo, syncrate, period, tinfo->curr.offset, ppr_options, AHC_TRANS_GOAL, FALSE); @@ -3556,7 +3561,6 @@ static void ahc_linux_set_iu(struct scsi_target *starget, int iu) unsigned int ppr_options = tinfo->curr.ppr_options & ~MSG_EXT_PPR_IU_REQ; unsigned int period = tinfo->curr.period; - unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; unsigned long flags; struct ahc_syncrate *syncrate; @@ -3565,8 +3569,7 @@ static void ahc_linux_set_iu(struct scsi_target *starget, int iu) ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, starget->channel + 'A', ROLE_INITIATOR); - syncrate = ahc_find_syncrate(ahc, &period, &ppr_options, - dt ? AHC_SYNCRATE_DT : AHC_SYNCRATE_ULTRA2); + syncrate = ahc_find_syncrate(ahc, &period, &ppr_options, AHC_SYNCRATE_DT); ahc_lock(ahc, &flags); ahc_set_syncrate(ahc, &devinfo, syncrate, period, tinfo->curr.offset, ppr_options, AHC_TRANS_GOAL, FALSE); -- cgit v1.2.3 From e4e360c325c90f7830baaa2a27cd7a1f2bdeb6b0 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Mon, 16 May 2005 16:39:38 -0500 Subject: [SCSI] remove aic7xxx busyq The aic7xxx driver has two spurious queues in it's linux glue code: the busyq which queues incoming commands to the driver and the completeq which queues finished commands before sending them back to the mid-layer This patch just removes the busyq and makes the aic finally return the correct status to get the mid-layer to manage its queueing, so a command is either committed to the sequencer or returned to the midlayer for requeue. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7xxx_osm.c | 625 +++++++++++-------------------------- drivers/scsi/aic7xxx/aic7xxx_osm.h | 4 +- 2 files changed, 191 insertions(+), 438 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 0ed9ccc3091..9017942407d 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -458,26 +458,20 @@ static struct ahc_linux_device* ahc_linux_alloc_device(struct ahc_softc*, u_int); static void ahc_linux_free_device(struct ahc_softc*, struct ahc_linux_device*); -static void ahc_linux_run_device_queue(struct ahc_softc*, - struct ahc_linux_device*); +static int ahc_linux_run_command(struct ahc_softc*, + struct ahc_linux_device *, + struct scsi_cmnd *); static void ahc_linux_setup_tag_info_global(char *p); static aic_option_callback_t ahc_linux_setup_tag_info; static int aic7xxx_setup(char *s); static int ahc_linux_next_unit(void); -static void ahc_runq_tasklet(unsigned long data); static struct ahc_cmd *ahc_linux_run_complete_queue(struct ahc_softc *ahc); /********************************* Inlines ************************************/ -static __inline void ahc_schedule_runq(struct ahc_softc *ahc); static __inline struct ahc_linux_device* ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target, u_int lun, int alloc); static __inline void ahc_schedule_completeq(struct ahc_softc *ahc); -static __inline void ahc_linux_check_device_queue(struct ahc_softc *ahc, - struct ahc_linux_device *dev); -static __inline struct ahc_linux_device * - ahc_linux_next_device_to_run(struct ahc_softc *ahc); -static __inline void ahc_linux_run_device_queues(struct ahc_softc *ahc); static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*); static __inline int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb, @@ -494,15 +488,6 @@ ahc_schedule_completeq(struct ahc_softc *ahc) } } -/* - * Must be called with our lock held. - */ -static __inline void -ahc_schedule_runq(struct ahc_softc *ahc) -{ - tasklet_schedule(&ahc->platform_data->runq_tasklet); -} - static __inline struct ahc_linux_device* ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target, u_int lun, int alloc) @@ -568,45 +553,6 @@ ahc_linux_run_complete_queue(struct ahc_softc *ahc) return (acmd); } -static __inline void -ahc_linux_check_device_queue(struct ahc_softc *ahc, - struct ahc_linux_device *dev) -{ - if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) != 0 - && dev->active == 0) { - dev->flags &= ~AHC_DEV_FREEZE_TIL_EMPTY; - dev->qfrozen--; - } - - if (TAILQ_FIRST(&dev->busyq) == NULL - || dev->openings == 0 || dev->qfrozen != 0) - return; - - ahc_linux_run_device_queue(ahc, dev); -} - -static __inline struct ahc_linux_device * -ahc_linux_next_device_to_run(struct ahc_softc *ahc) -{ - - if ((ahc->flags & AHC_RESOURCE_SHORTAGE) != 0 - || (ahc->platform_data->qfrozen != 0)) - return (NULL); - return (TAILQ_FIRST(&ahc->platform_data->device_runq)); -} - -static __inline void -ahc_linux_run_device_queues(struct ahc_softc *ahc) -{ - struct ahc_linux_device *dev; - - while ((dev = ahc_linux_next_device_to_run(ahc)) != NULL) { - TAILQ_REMOVE(&ahc->platform_data->device_runq, dev, links); - dev->flags &= ~AHC_DEV_ON_RUN_LIST; - ahc_linux_check_device_queue(ahc, dev); - } -} - static __inline void ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb) { @@ -871,7 +817,6 @@ ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) { struct ahc_softc *ahc; struct ahc_linux_device *dev; - u_long flags; ahc = *(struct ahc_softc **)cmd->device->host->hostdata; @@ -880,42 +825,22 @@ ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) */ cmd->scsi_done = scsi_done; - ahc_midlayer_entrypoint_lock(ahc, &flags); - /* * Close the race of a command that was in the process of * being queued to us just as our simq was frozen. Let * DV commands through so long as we are only frozen to * perform DV. */ - if (ahc->platform_data->qfrozen != 0) { + if (ahc->platform_data->qfrozen != 0) + return SCSI_MLQUEUE_HOST_BUSY; - ahc_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ); - ahc_linux_queue_cmd_complete(ahc, cmd); - ahc_schedule_completeq(ahc); - ahc_midlayer_entrypoint_unlock(ahc, &flags); - return (0); - } dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id, cmd->device->lun, /*alloc*/TRUE); - if (dev == NULL) { - ahc_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL); - ahc_linux_queue_cmd_complete(ahc, cmd); - ahc_schedule_completeq(ahc); - ahc_midlayer_entrypoint_unlock(ahc, &flags); - printf("%s: aic7xxx_linux_queue - Unable to allocate device!\n", - ahc_name(ahc)); - return (0); - } + BUG_ON(dev == NULL); + cmd->result = CAM_REQ_INPROG << 16; - TAILQ_INSERT_TAIL(&dev->busyq, (struct ahc_cmd *)cmd, acmd_links.tqe); - if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { - TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links); - dev->flags |= AHC_DEV_ON_RUN_LIST; - ahc_linux_run_device_queues(ahc); - } - ahc_midlayer_entrypoint_unlock(ahc, &flags); - return (0); + + return ahc_linux_run_command(ahc, dev, cmd); } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) @@ -987,8 +912,7 @@ ahc_linux_slave_destroy(Scsi_Device *device) if (dev != NULL && (dev->flags & AHC_DEV_SLAVE_CONFIGURED) != 0) { dev->flags |= AHC_DEV_UNCONFIGURED; - if (TAILQ_EMPTY(&dev->busyq) - && dev->active == 0 + if (dev->active == 0 && (dev->flags & AHC_DEV_TIMER_ACTIVE) == 0) ahc_linux_free_device(ahc, dev); } @@ -1206,33 +1130,6 @@ Scsi_Host_Template aic7xxx_driver_template = { /**************************** Tasklet Handler *********************************/ -/* - * In 2.4.X and above, this routine is called from a tasklet, - * so we must re-acquire our lock prior to executing this code. - * In all prior kernels, ahc_schedule_runq() calls this routine - * directly and ahc_schedule_runq() is called with our lock held. - */ -static void -ahc_runq_tasklet(unsigned long data) -{ - struct ahc_softc* ahc; - struct ahc_linux_device *dev; - u_long flags; - - ahc = (struct ahc_softc *)data; - ahc_lock(ahc, &flags); - while ((dev = ahc_linux_next_device_to_run(ahc)) != NULL) { - - TAILQ_REMOVE(&ahc->platform_data->device_runq, dev, links); - dev->flags &= ~AHC_DEV_ON_RUN_LIST; - ahc_linux_check_device_queue(ahc, dev); - /* Yeild to our interrupt handler */ - ahc_unlock(ahc, &flags); - ahc_lock(ahc, &flags); - } - ahc_unlock(ahc, &flags); -} - /******************************** Macros **************************************/ #define BUILD_SCSIID(ahc, cmd) \ ((((cmd)->device->id << TID_SHIFT) & TID) \ @@ -1728,8 +1625,6 @@ ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg) ahc->platform_data->completeq_timer.function = (ahc_linux_callback_t *)ahc_linux_thread_run_complete_queue; init_MUTEX_LOCKED(&ahc->platform_data->eh_sem); - tasklet_init(&ahc->platform_data->runq_tasklet, ahc_runq_tasklet, - (unsigned long)ahc); ahc->seltime = (aic7xxx_seltime & 0x3) << 4; ahc->seltime_b = (aic7xxx_seltime & 0x3) << 4; if (aic7xxx_pci_parity == 0) @@ -1747,7 +1642,6 @@ ahc_platform_free(struct ahc_softc *ahc) if (ahc->platform_data != NULL) { del_timer_sync(&ahc->platform_data->completeq_timer); - tasklet_kill(&ahc->platform_data->runq_tasklet); if (ahc->platform_data->host != NULL) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_remove_host(ahc->platform_data->host); @@ -1906,71 +1800,7 @@ int ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, char channel, int lun, u_int tag, role_t role, uint32_t status) { - int chan; - int maxchan; - int targ; - int maxtarg; - int clun; - int maxlun; - int count; - - if (tag != SCB_LIST_NULL) - return (0); - - chan = 0; - if (channel != ALL_CHANNELS) { - chan = channel - 'A'; - maxchan = chan + 1; - } else { - maxchan = (ahc->features & AHC_TWIN) ? 2 : 1; - } - targ = 0; - if (target != CAM_TARGET_WILDCARD) { - targ = target; - maxtarg = targ + 1; - } else { - maxtarg = (ahc->features & AHC_WIDE) ? 16 : 8; - } - clun = 0; - if (lun != CAM_LUN_WILDCARD) { - clun = lun; - maxlun = clun + 1; - } else { - maxlun = AHC_NUM_LUNS; - } - - count = 0; - for (; chan < maxchan; chan++) { - - for (; targ < maxtarg; targ++) { - - for (; clun < maxlun; clun++) { - struct ahc_linux_device *dev; - struct ahc_busyq *busyq; - struct ahc_cmd *acmd; - - dev = ahc_linux_get_device(ahc, chan, - targ, clun, - /*alloc*/FALSE); - if (dev == NULL) - continue; - - busyq = &dev->busyq; - while ((acmd = TAILQ_FIRST(busyq)) != NULL) { - Scsi_Cmnd *cmd; - - cmd = &acmd_scsi_cmd(acmd); - TAILQ_REMOVE(busyq, acmd, - acmd_links.tqe); - count++; - cmd->result = status << 16; - ahc_linux_queue_cmd_complete(ahc, cmd); - } - } - } - } - - return (count); + return 0; } static void @@ -2045,213 +1875,203 @@ ahc_linux_device_queue_depth(struct ahc_softc *ahc, } } -static void -ahc_linux_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev) +static int +ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev, + struct scsi_cmnd *cmd) { - struct ahc_cmd *acmd; - struct scsi_cmnd *cmd; struct scb *scb; struct hardware_scb *hscb; struct ahc_initiator_tinfo *tinfo; struct ahc_tmode_tstate *tstate; uint16_t mask; + struct scb_tailq *untagged_q = NULL; - if ((dev->flags & AHC_DEV_ON_RUN_LIST) != 0) - panic("running device on run list"); + /* + * Schedule us to run later. The only reason we are not + * running is because the whole controller Q is frozen. + */ + if (ahc->platform_data->qfrozen != 0) + return SCSI_MLQUEUE_HOST_BUSY; - while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL - && dev->openings > 0 && dev->qfrozen == 0) { + /* + * We only allow one untagged transaction + * per target in the initiator role unless + * we are storing a full busy target *lun* + * table in SCB space. + */ + if (!blk_rq_tagged(cmd->request) + && (ahc->features & AHC_SCB_BTT) == 0) { + int target_offset; - /* - * Schedule us to run later. The only reason we are not - * running is because the whole controller Q is frozen. - */ - if (ahc->platform_data->qfrozen != 0) { - TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, - dev, links); - dev->flags |= AHC_DEV_ON_RUN_LIST; - return; - } - /* - * Get an scb to use. - */ - if ((scb = ahc_get_scb(ahc)) == NULL) { - TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, - dev, links); - dev->flags |= AHC_DEV_ON_RUN_LIST; + target_offset = cmd->device->id + cmd->device->channel * 8; + untagged_q = &(ahc->untagged_queues[target_offset]); + if (!TAILQ_EMPTY(untagged_q)) + /* if we're already executing an untagged command + * we're busy to another */ + return SCSI_MLQUEUE_DEVICE_BUSY; + } + + /* + * Get an scb to use. + */ + if ((scb = ahc_get_scb(ahc)) == NULL) { ahc->flags |= AHC_RESOURCE_SHORTAGE; - return; - } - TAILQ_REMOVE(&dev->busyq, acmd, acmd_links.tqe); - cmd = &acmd_scsi_cmd(acmd); - scb->io_ctx = cmd; - scb->platform_data->dev = dev; - hscb = scb->hscb; - cmd->host_scribble = (char *)scb; + return SCSI_MLQUEUE_HOST_BUSY; + } - /* - * Fill out basics of the HSCB. - */ - hscb->control = 0; - hscb->scsiid = BUILD_SCSIID(ahc, cmd); - hscb->lun = cmd->device->lun; - mask = SCB_GET_TARGET_MASK(ahc, scb); - tinfo = ahc_fetch_transinfo(ahc, SCB_GET_CHANNEL(ahc, scb), - SCB_GET_OUR_ID(scb), - SCB_GET_TARGET(ahc, scb), &tstate); - hscb->scsirate = tinfo->scsirate; - hscb->scsioffset = tinfo->curr.offset; - if ((tstate->ultraenb & mask) != 0) - hscb->control |= ULTRAENB; - - if ((ahc->user_discenable & mask) != 0) - hscb->control |= DISCENB; - - if ((tstate->auto_negotiate & mask) != 0) { - scb->flags |= SCB_AUTO_NEGOTIATE; - scb->hscb->control |= MK_MESSAGE; - } + scb->io_ctx = cmd; + scb->platform_data->dev = dev; + hscb = scb->hscb; + cmd->host_scribble = (char *)scb; - if ((dev->flags & (AHC_DEV_Q_TAGGED|AHC_DEV_Q_BASIC)) != 0) { + /* + * Fill out basics of the HSCB. + */ + hscb->control = 0; + hscb->scsiid = BUILD_SCSIID(ahc, cmd); + hscb->lun = cmd->device->lun; + mask = SCB_GET_TARGET_MASK(ahc, scb); + tinfo = ahc_fetch_transinfo(ahc, SCB_GET_CHANNEL(ahc, scb), + SCB_GET_OUR_ID(scb), + SCB_GET_TARGET(ahc, scb), &tstate); + hscb->scsirate = tinfo->scsirate; + hscb->scsioffset = tinfo->curr.offset; + if ((tstate->ultraenb & mask) != 0) + hscb->control |= ULTRAENB; + + if ((ahc->user_discenable & mask) != 0) + hscb->control |= DISCENB; + + if ((tstate->auto_negotiate & mask) != 0) { + scb->flags |= SCB_AUTO_NEGOTIATE; + scb->hscb->control |= MK_MESSAGE; + } + + if ((dev->flags & (AHC_DEV_Q_TAGGED|AHC_DEV_Q_BASIC)) != 0) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - int msg_bytes; - uint8_t tag_msgs[2]; - - msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs); - if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) { - hscb->control |= tag_msgs[0]; - if (tag_msgs[0] == MSG_ORDERED_TASK) - dev->commands_since_idle_or_otag = 0; - } else -#endif - if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH - && (dev->flags & AHC_DEV_Q_TAGGED) != 0) { - hscb->control |= MSG_ORDERED_TASK; + int msg_bytes; + uint8_t tag_msgs[2]; + + msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs); + if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) { + hscb->control |= tag_msgs[0]; + if (tag_msgs[0] == MSG_ORDERED_TASK) dev->commands_since_idle_or_otag = 0; - } else { - hscb->control |= MSG_SIMPLE_TASK; - } - } - - hscb->cdb_len = cmd->cmd_len; - if (hscb->cdb_len <= 12) { - memcpy(hscb->shared_data.cdb, cmd->cmnd, hscb->cdb_len); + } else +#endif + if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH + && (dev->flags & AHC_DEV_Q_TAGGED) != 0) { + hscb->control |= MSG_ORDERED_TASK; + dev->commands_since_idle_or_otag = 0; } else { - memcpy(hscb->cdb32, cmd->cmnd, hscb->cdb_len); - scb->flags |= SCB_CDB32_PTR; + hscb->control |= MSG_SIMPLE_TASK; } + } - scb->platform_data->xfer_len = 0; - ahc_set_residual(scb, 0); - ahc_set_sense_residual(scb, 0); - scb->sg_count = 0; - if (cmd->use_sg != 0) { - struct ahc_dma_seg *sg; - struct scatterlist *cur_seg; - struct scatterlist *end_seg; - int nseg; - - cur_seg = (struct scatterlist *)cmd->request_buffer; - nseg = pci_map_sg(ahc->dev_softc, cur_seg, cmd->use_sg, - cmd->sc_data_direction); - end_seg = cur_seg + nseg; - /* Copy the segments into the SG list. */ - sg = scb->sg_list; - /* - * The sg_count may be larger than nseg if - * a transfer crosses a 32bit page. - */ - while (cur_seg < end_seg) { - dma_addr_t addr; - bus_size_t len; - int consumed; - - addr = sg_dma_address(cur_seg); - len = sg_dma_len(cur_seg); - consumed = ahc_linux_map_seg(ahc, scb, - sg, addr, len); - sg += consumed; - scb->sg_count += consumed; - cur_seg++; - } - sg--; - sg->len |= ahc_htole32(AHC_DMA_LAST_SEG); - - /* - * Reset the sg list pointer. - */ - scb->hscb->sgptr = - ahc_htole32(scb->sg_list_phys | SG_FULL_RESID); + hscb->cdb_len = cmd->cmd_len; + if (hscb->cdb_len <= 12) { + memcpy(hscb->shared_data.cdb, cmd->cmnd, hscb->cdb_len); + } else { + memcpy(hscb->cdb32, cmd->cmnd, hscb->cdb_len); + scb->flags |= SCB_CDB32_PTR; + } - /* - * Copy the first SG into the "current" - * data pointer area. - */ - scb->hscb->dataptr = scb->sg_list->addr; - scb->hscb->datacnt = scb->sg_list->len; - } else if (cmd->request_bufflen != 0) { - struct ahc_dma_seg *sg; + scb->platform_data->xfer_len = 0; + ahc_set_residual(scb, 0); + ahc_set_sense_residual(scb, 0); + scb->sg_count = 0; + if (cmd->use_sg != 0) { + struct ahc_dma_seg *sg; + struct scatterlist *cur_seg; + struct scatterlist *end_seg; + int nseg; + + cur_seg = (struct scatterlist *)cmd->request_buffer; + nseg = pci_map_sg(ahc->dev_softc, cur_seg, cmd->use_sg, + cmd->sc_data_direction); + end_seg = cur_seg + nseg; + /* Copy the segments into the SG list. */ + sg = scb->sg_list; + /* + * The sg_count may be larger than nseg if + * a transfer crosses a 32bit page. + */ + while (cur_seg < end_seg) { dma_addr_t addr; - - sg = scb->sg_list; - addr = pci_map_single(ahc->dev_softc, - cmd->request_buffer, - cmd->request_bufflen, - cmd->sc_data_direction); - scb->platform_data->buf_busaddr = addr; - scb->sg_count = ahc_linux_map_seg(ahc, scb, - sg, addr, - cmd->request_bufflen); - sg->len |= ahc_htole32(AHC_DMA_LAST_SEG); - - /* - * Reset the sg list pointer. - */ - scb->hscb->sgptr = - ahc_htole32(scb->sg_list_phys | SG_FULL_RESID); - - /* - * Copy the first SG into the "current" - * data pointer area. - */ - scb->hscb->dataptr = sg->addr; - scb->hscb->datacnt = sg->len; - } else { - scb->hscb->sgptr = ahc_htole32(SG_LIST_NULL); - scb->hscb->dataptr = 0; - scb->hscb->datacnt = 0; - scb->sg_count = 0; + bus_size_t len; + int consumed; + + addr = sg_dma_address(cur_seg); + len = sg_dma_len(cur_seg); + consumed = ahc_linux_map_seg(ahc, scb, + sg, addr, len); + sg += consumed; + scb->sg_count += consumed; + cur_seg++; } + sg--; + sg->len |= ahc_htole32(AHC_DMA_LAST_SEG); - ahc_sync_sglist(ahc, scb, BUS_DMASYNC_PREWRITE); - LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links); - dev->openings--; - dev->active++; - dev->commands_issued++; - if ((dev->flags & AHC_DEV_PERIODIC_OTAG) != 0) - dev->commands_since_idle_or_otag++; + /* + * Reset the sg list pointer. + */ + scb->hscb->sgptr = + ahc_htole32(scb->sg_list_phys | SG_FULL_RESID); + + /* + * Copy the first SG into the "current" + * data pointer area. + */ + scb->hscb->dataptr = scb->sg_list->addr; + scb->hscb->datacnt = scb->sg_list->len; + } else if (cmd->request_bufflen != 0) { + struct ahc_dma_seg *sg; + dma_addr_t addr; + + sg = scb->sg_list; + addr = pci_map_single(ahc->dev_softc, + cmd->request_buffer, + cmd->request_bufflen, + cmd->sc_data_direction); + scb->platform_data->buf_busaddr = addr; + scb->sg_count = ahc_linux_map_seg(ahc, scb, + sg, addr, + cmd->request_bufflen); + sg->len |= ahc_htole32(AHC_DMA_LAST_SEG); /* - * We only allow one untagged transaction - * per target in the initiator role unless - * we are storing a full busy target *lun* - * table in SCB space. + * Reset the sg list pointer. */ - if ((scb->hscb->control & (TARGET_SCB|TAG_ENB)) == 0 - && (ahc->features & AHC_SCB_BTT) == 0) { - struct scb_tailq *untagged_q; - int target_offset; - - target_offset = SCB_GET_TARGET_OFFSET(ahc, scb); - untagged_q = &(ahc->untagged_queues[target_offset]); - TAILQ_INSERT_TAIL(untagged_q, scb, links.tqe); - scb->flags |= SCB_UNTAGGEDQ; - if (TAILQ_FIRST(untagged_q) != scb) - continue; - } - scb->flags |= SCB_ACTIVE; - ahc_queue_scb(ahc, scb); + scb->hscb->sgptr = + ahc_htole32(scb->sg_list_phys | SG_FULL_RESID); + + /* + * Copy the first SG into the "current" + * data pointer area. + */ + scb->hscb->dataptr = sg->addr; + scb->hscb->datacnt = sg->len; + } else { + scb->hscb->sgptr = ahc_htole32(SG_LIST_NULL); + scb->hscb->dataptr = 0; + scb->hscb->datacnt = 0; + scb->sg_count = 0; + } + + LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links); + dev->openings--; + dev->active++; + dev->commands_issued++; + if ((dev->flags & AHC_DEV_PERIODIC_OTAG) != 0) + dev->commands_since_idle_or_otag++; + + scb->flags |= SCB_ACTIVE; + if (untagged_q) { + TAILQ_INSERT_TAIL(untagged_q, scb, links.tqe); + scb->flags |= SCB_UNTAGGEDQ; } + ahc_queue_scb(ahc, scb); + return 0; } /* @@ -2267,8 +2087,6 @@ ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs) ahc = (struct ahc_softc *) dev_id; ahc_lock(ahc, &flags); ours = ahc_intr(ahc); - if (ahc_linux_next_device_to_run(ahc) != NULL) - ahc_schedule_runq(ahc); ahc_linux_run_complete_queue(ahc); ahc_unlock(ahc, &flags); return IRQ_RETVAL(ours); @@ -2349,7 +2167,6 @@ ahc_linux_alloc_device(struct ahc_softc *ahc, return (NULL); memset(dev, 0, sizeof(*dev)); init_timer(&dev->timer); - TAILQ_INIT(&dev->busyq); dev->flags = AHC_DEV_UNCONFIGURED; dev->lun = lun; dev->target = targ; @@ -2515,7 +2332,7 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) target_offset = SCB_GET_TARGET_OFFSET(ahc, scb); untagged_q = &(ahc->untagged_queues[target_offset]); TAILQ_REMOVE(untagged_q, scb, links.tqe); - ahc_run_untagged_queue(ahc, untagged_q); + BUG_ON(!TAILQ_EMPTY(untagged_q)); } if ((scb->flags & SCB_ACTIVE) == 0) { @@ -2606,12 +2423,11 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) if (dev->active == 0) dev->commands_since_idle_or_otag = 0; - if (TAILQ_EMPTY(&dev->busyq)) { - if ((dev->flags & AHC_DEV_UNCONFIGURED) != 0 - && dev->active == 0 - && (dev->flags & AHC_DEV_TIMER_ACTIVE) == 0) - ahc_linux_free_device(ahc, dev); - } else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { + if ((dev->flags & AHC_DEV_UNCONFIGURED) != 0 + && dev->active == 0 + && (dev->flags & AHC_DEV_TIMER_ACTIVE) == 0) + ahc_linux_free_device(ahc, dev); + else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links); dev->flags |= AHC_DEV_ON_RUN_LIST; } @@ -2940,7 +2756,6 @@ ahc_linux_release_simq(u_long arg) ahc->platform_data->qfrozen--; if (ahc->platform_data->qfrozen == 0) unblock_reqs = 1; - ahc_schedule_runq(ahc); ahc_unlock(ahc, &s); /* * There is still a race here. The mid-layer @@ -2965,11 +2780,7 @@ ahc_linux_dev_timed_unfreeze(u_long arg) dev->flags &= ~AHC_DEV_TIMER_ACTIVE; if (dev->qfrozen > 0) dev->qfrozen--; - if (dev->qfrozen == 0 - && (dev->flags & AHC_DEV_ON_RUN_LIST) == 0) - ahc_linux_run_device_queue(ahc, dev); - if (TAILQ_EMPTY(&dev->busyq) - && dev->active == 0) + if (dev->active == 0) __ahc_linux_free_device(ahc, dev); ahc_unlock(ahc, &s); } @@ -2978,8 +2789,6 @@ static int ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) { struct ahc_softc *ahc; - struct ahc_cmd *acmd; - struct ahc_cmd *list_acmd; struct ahc_linux_device *dev; struct scb *pending_scb; u_long s; @@ -2998,7 +2807,6 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) paused = FALSE; wait = FALSE; ahc = *(struct ahc_softc **)cmd->device->host->hostdata; - acmd = (struct ahc_cmd *)cmd; printf("%s:%d:%d:%d: Attempting to queue a%s message\n", ahc_name(ahc), cmd->device->channel, @@ -3048,24 +2856,6 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) goto no_cmd; } - TAILQ_FOREACH(list_acmd, &dev->busyq, acmd_links.tqe) { - if (list_acmd == acmd) - break; - } - - if (list_acmd != NULL) { - printf("%s:%d:%d:%d: Command found on device queue\n", - ahc_name(ahc), cmd->device->channel, cmd->device->id, - cmd->device->lun); - if (flag == SCB_ABORT) { - TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe); - cmd->result = DID_ABORT << 16; - ahc_linux_queue_cmd_complete(ahc, cmd); - retval = SUCCESS; - goto done; - } - } - if ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED)) == 0 && ahc_search_untagged_queues(ahc, cmd, cmd->device->id, cmd->device->channel + 'A', @@ -3299,7 +3089,6 @@ done: } spin_lock_irq(&ahc->platform_data->spin_lock); } - ahc_schedule_runq(ahc); ahc_linux_run_complete_queue(ahc); ahc_midlayer_entrypoint_unlock(ahc, &s); return (retval); @@ -3308,40 +3097,6 @@ done: void ahc_platform_dump_card_state(struct ahc_softc *ahc) { - struct ahc_linux_device *dev; - int channel; - int maxchannel; - int target; - int maxtarget; - int lun; - int i; - - maxchannel = (ahc->features & AHC_TWIN) ? 1 : 0; - maxtarget = (ahc->features & AHC_WIDE) ? 15 : 7; - for (channel = 0; channel <= maxchannel; channel++) { - - for (target = 0; target <=maxtarget; target++) { - - for (lun = 0; lun < AHC_NUM_LUNS; lun++) { - struct ahc_cmd *acmd; - - dev = ahc_linux_get_device(ahc, channel, target, - lun, /*alloc*/FALSE); - if (dev == NULL) - continue; - - printf("DevQ(%d:%d:%d): ", - channel, target, lun); - i = 0; - TAILQ_FOREACH(acmd, &dev->busyq, - acmd_links.tqe) { - if (i++ > AHC_SCB_MAX) - break; - } - printf("%d waiting\n", i); - } - } - } } static void ahc_linux_exit(void); diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index ed9027bd8a4..95609703521 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -66,11 +66,11 @@ #include #include #include +#include #include #include #include -#include /* For tasklet support. */ #include #include @@ -341,7 +341,6 @@ typedef enum { struct ahc_linux_target; struct ahc_linux_device { TAILQ_ENTRY(ahc_linux_device) links; - struct ahc_busyq busyq; /* * The number of transactions currently @@ -488,7 +487,6 @@ struct ahc_platform_data { struct ahc_completeq completeq; spinlock_t spin_lock; - struct tasklet_struct runq_tasklet; u_int qfrozen; pid_t dv_pid; struct timer_list completeq_timer; -- cgit v1.2.3 From c06716fe1cea97749668c83e8374b453fbd00823 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 16 May 2005 18:51:13 +0200 Subject: [SCSI] aic7xxx: remove some DV leftovers Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7xxx_osm.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index 95609703521..6ea2bfb8820 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -488,15 +488,9 @@ struct ahc_platform_data { spinlock_t spin_lock; u_int qfrozen; - pid_t dv_pid; struct timer_list completeq_timer; struct timer_list reset_timer; struct semaphore eh_sem; - struct semaphore dv_sem; - struct semaphore dv_cmd_sem; /* XXX This needs to be in - * the target struct - */ - struct scsi_device *dv_scsi_dev; struct Scsi_Host *host; /* pointer to scsi host */ #define AHC_LINUX_NOIRQ ((uint32_t)~0) uint32_t irq; /* IRQ for this adapter */ -- cgit v1.2.3 From dedd831081052028f35aaf924ea3d6c55109074f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 16 May 2005 18:52:06 +0200 Subject: [SCSI] aic7xxx: remove Linux 2.4 ifdefs There's not much sense in sharing code anymore now that aic7xxx uses various transport class facilities. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7770_osm.c | 52 +----- drivers/scsi/aic7xxx/aic7xxx_osm.c | 314 +-------------------------------- drivers/scsi/aic7xxx/aic7xxx_osm.h | 89 ---------- drivers/scsi/aic7xxx/aic7xxx_osm_pci.c | 9 +- drivers/scsi/aic7xxx/aic7xxx_proc.c | 13 -- 5 files changed, 5 insertions(+), 472 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c index c2b47f2bdff..682ca0b32b4 100644 --- a/drivers/scsi/aic7xxx/aic7770_osm.c +++ b/drivers/scsi/aic7xxx/aic7770_osm.c @@ -41,7 +41,6 @@ #include "aic7xxx_osm.h" -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) #include #include @@ -62,13 +61,6 @@ static struct eisa_driver aic7770_driver = { }; typedef struct device *aic7770_dev_t; -#else -#define MINSLOT 1 -#define NUMSLOTS 16 -#define IDOFFSET 0x80 - -typedef void *aic7770_dev_t; -#endif static int aic7770_linux_config(struct aic7770_identity *entry, aic7770_dev_t dev, u_int eisaBase); @@ -76,7 +68,6 @@ static int aic7770_linux_config(struct aic7770_identity *entry, int ahc_linux_eisa_init(void) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) struct eisa_device_id *eid; struct aic7770_identity *id; int i; @@ -110,44 +101,6 @@ ahc_linux_eisa_init(void) eid->sig[0] = 0; return eisa_driver_register(&aic7770_driver); -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) */ - struct aic7770_identity *entry; - u_int slot; - u_int eisaBase; - u_int i; - int ret = -ENODEV; - - if (aic7xxx_probe_eisa_vl == 0) - return ret; - - eisaBase = 0x1000 + AHC_EISA_SLOT_OFFSET; - for (slot = 1; slot < NUMSLOTS; eisaBase+=0x1000, slot++) { - uint32_t eisa_id; - size_t id_size; - - if (request_region(eisaBase, AHC_EISA_IOSIZE, "aic7xxx") == 0) - continue; - - eisa_id = 0; - id_size = sizeof(eisa_id); - for (i = 0; i < 4; i++) { - /* VLcards require priming*/ - outb(0x80 + i, eisaBase + IDOFFSET); - eisa_id |= inb(eisaBase + IDOFFSET + i) - << ((id_size-i-1) * 8); - } - release_region(eisaBase, AHC_EISA_IOSIZE); - if (eisa_id & 0x80000000) - continue; /* no EISA card in slot */ - - entry = aic7770_find_device(eisa_id); - if (entry != NULL) { - aic7770_linux_config(entry, NULL, eisaBase); - ret = 0; - } - } - return ret; -#endif } void @@ -187,11 +140,10 @@ aic7770_linux_config(struct aic7770_identity *entry, aic7770_dev_t dev, ahc_free(ahc); return (error); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + dev->driver_data = (void *)ahc; if (aic7xxx_detect_complete) error = ahc_linux_register_host(ahc, &aic7xxx_driver_template); -#endif return (error); } @@ -225,7 +177,6 @@ aic7770_map_int(struct ahc_softc *ahc, u_int irq) return (-error); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) static int aic7770_eisa_dev_probe(struct device *dev) { @@ -261,4 +212,3 @@ aic7770_eisa_dev_remove(struct device *dev) return (0); } -#endif diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 9017942407d..37fda70b543 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -134,11 +134,6 @@ static struct scsi_transport_template *ahc_linux_transport_template = NULL; #include "aiclib.c" #include /* __setup */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -#include "sd.h" /* For geometry detection */ -#endif - #include /* For fetching system memory size */ #include /* For block_size() */ #include /* For ssleep/msleep */ @@ -148,11 +143,6 @@ static struct scsi_transport_template *ahc_linux_transport_template = NULL; */ spinlock_t ahc_list_spinlock; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -/* For dynamic sglist size calculation. */ -u_int ahc_linux_nseg; -#endif - /* * Set this to the delay in seconds after SCSI bus reset. * Note, we honor this only for the initial bus reset. @@ -443,7 +433,6 @@ static void ahc_linux_release_simq(u_long arg); static void ahc_linux_dev_timed_unfreeze(u_long arg); static int ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag); static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc); -static void ahc_linux_size_nseg(void); static void ahc_linux_thread_run_complete_queue(struct ahc_softc *ahc); static u_int ahc_linux_user_tagdepth(struct ahc_softc *ahc, struct ahc_devinfo *devinfo); @@ -519,11 +508,9 @@ static struct ahc_cmd * ahc_linux_run_complete_queue(struct ahc_softc *ahc) { struct ahc_cmd *acmd; - u_long done_flags; int with_errors; with_errors = 0; - ahc_done_lock(ahc, &done_flags); while ((acmd = TAILQ_FIRST(&ahc->platform_data->completeq)) != NULL) { Scsi_Cmnd *cmd; @@ -549,7 +536,6 @@ ahc_linux_run_complete_queue(struct ahc_softc *ahc) cmd->scsi_done(cmd); } - ahc_done_unlock(ahc, &done_flags); return (acmd); } @@ -600,7 +586,6 @@ ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb, static int ahc_linux_detect(Scsi_Host_Template *); static int ahc_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); static const char *ahc_linux_info(struct Scsi_Host *); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) static int ahc_linux_slave_alloc(Scsi_Device *); static int ahc_linux_slave_configure(Scsi_Device *); static void ahc_linux_slave_destroy(Scsi_Device *); @@ -609,79 +594,10 @@ static int ahc_linux_biosparam(struct scsi_device*, struct block_device*, sector_t, int[]); #endif -#else -static int ahc_linux_release(struct Scsi_Host *); -static void ahc_linux_select_queue_depth(struct Scsi_Host *host, - Scsi_Device *scsi_devs); -#if defined(__i386__) -static int ahc_linux_biosparam(Disk *, kdev_t, int[]); -#endif -#endif static int ahc_linux_bus_reset(Scsi_Cmnd *); static int ahc_linux_dev_reset(Scsi_Cmnd *); static int ahc_linux_abort(Scsi_Cmnd *); -/* - * Calculate a safe value for AHC_NSEG (as expressed through ahc_linux_nseg). - * - * In pre-2.5.X... - * The midlayer allocates an S/G array dynamically when a command is issued - * using SCSI malloc. This array, which is in an OS dependent format that - * must later be copied to our private S/G list, is sized to house just the - * number of segments needed for the current transfer. Since the code that - * sizes the SCSI malloc pool does not take into consideration fragmentation - * of the pool, executing transactions numbering just a fraction of our - * concurrent transaction limit with list lengths aproaching AHC_NSEG will - * quickly depleat the SCSI malloc pool of usable space. Unfortunately, the - * mid-layer does not properly handle this scsi malloc failures for the S/G - * array and the result can be a lockup of the I/O subsystem. We try to size - * our S/G list so that it satisfies our drivers allocation requirements in - * addition to avoiding fragmentation of the SCSI malloc pool. - */ -static void -ahc_linux_size_nseg(void) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - u_int cur_size; - u_int best_size; - - /* - * The SCSI allocator rounds to the nearest 512 bytes - * an cannot allocate across a page boundary. Our algorithm - * is to start at 1K of scsi malloc space per-command and - * loop through all factors of the PAGE_SIZE and pick the best. - */ - best_size = 0; - for (cur_size = 1024; cur_size <= PAGE_SIZE; cur_size *= 2) { - u_int nseg; - - nseg = cur_size / sizeof(struct scatterlist); - if (nseg < AHC_LINUX_MIN_NSEG) - continue; - - if (best_size == 0) { - best_size = cur_size; - ahc_linux_nseg = nseg; - } else { - u_int best_rem; - u_int cur_rem; - - /* - * Compare the traits of the current "best_size" - * with the current size to determine if the - * current size is a better size. - */ - best_rem = best_size % sizeof(struct scatterlist); - cur_rem = cur_size % sizeof(struct scatterlist); - if (cur_rem < best_rem) { - best_size = cur_size; - ahc_linux_nseg = nseg; - } - } - } -#endif -} - /* * Try to detect an Adaptec 7XXX controller. */ @@ -691,14 +607,6 @@ ahc_linux_detect(Scsi_Host_Template *template) struct ahc_softc *ahc; int found = 0; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - /* - * It is a bug that the upper layer takes - * this lock just prior to calling us. - */ - spin_unlock_irq(&io_request_lock); -#endif - /* * Sanity checking of Linux SCSI data structures so * that some of our hacks^H^H^H^H^Hassumptions aren't @@ -710,7 +618,6 @@ ahc_linux_detect(Scsi_Host_Template *template) printf("ahc_linux_detect: Unable to attach\n"); return (0); } - ahc_linux_size_nseg(); /* * If we've been passed any parameters, process them now. */ @@ -739,48 +646,11 @@ ahc_linux_detect(Scsi_Host_Template *template) found++; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - spin_lock_irq(&io_request_lock); -#endif aic7xxx_detect_complete++; return (found); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -/* - * Free the passed in Scsi_Host memory structures prior to unloading the - * module. - */ -int -ahc_linux_release(struct Scsi_Host * host) -{ - struct ahc_softc *ahc; - u_long l; - - ahc_list_lock(&l); - if (host != NULL) { - - /* - * We should be able to just perform - * the free directly, but check our - * list for extra sanity. - */ - ahc = ahc_find_softc(*(struct ahc_softc **)host->hostdata); - if (ahc != NULL) { - u_long s; - - ahc_lock(ahc, &s); - ahc_intr_enable(ahc, FALSE); - ahc_unlock(ahc, &s); - ahc_free(ahc); - } - } - ahc_list_unlock(&l); - return (0); -} -#endif - /* * Return a string describing the driver. */ @@ -843,7 +713,6 @@ ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) return ahc_linux_run_command(ahc, dev, cmd); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) static int ahc_linux_slave_alloc(Scsi_Device *device) { @@ -860,12 +729,10 @@ ahc_linux_slave_configure(Scsi_Device *device) { struct ahc_softc *ahc; struct ahc_linux_device *dev; - u_long flags; ahc = *((struct ahc_softc **)device->host->hostdata); if (bootverbose) printf("%s: Slave Configure %d\n", ahc_name(ahc), device->id); - ahc_midlayer_entrypoint_lock(ahc, &flags); /* * Since Linux has attached to the device, configure * it so we don't free and allocate the device @@ -879,7 +746,6 @@ ahc_linux_slave_configure(Scsi_Device *device) dev->scsi_device = device; ahc_linux_device_queue_depth(ahc, dev); } - ahc_midlayer_entrypoint_unlock(ahc, &flags); /* Initial Domain Validation */ if (!spi_initial_dv(device->sdev_target)) @@ -893,12 +759,10 @@ ahc_linux_slave_destroy(Scsi_Device *device) { struct ahc_softc *ahc; struct ahc_linux_device *dev; - u_long flags; ahc = *((struct ahc_softc **)device->host->hostdata); if (bootverbose) printf("%s: Slave Destroy %d\n", ahc_name(ahc), device->id); - ahc_midlayer_entrypoint_lock(ahc, &flags); dev = ahc_linux_get_device(ahc, device->channel, device->id, device->lun, /*alloc*/FALSE); @@ -916,93 +780,17 @@ ahc_linux_slave_destroy(Scsi_Device *device) && (dev->flags & AHC_DEV_TIMER_ACTIVE) == 0) ahc_linux_free_device(ahc, dev); } - ahc_midlayer_entrypoint_unlock(ahc, &flags); } -#else -/* - * Sets the queue depth for each SCSI device hanging - * off the input host adapter. - */ -static void -ahc_linux_select_queue_depth(struct Scsi_Host *host, Scsi_Device *scsi_devs) -{ - Scsi_Device *device; - Scsi_Device *ldev; - struct ahc_softc *ahc; - u_long flags; - - ahc = *((struct ahc_softc **)host->hostdata); - ahc_lock(ahc, &flags); - for (device = scsi_devs; device != NULL; device = device->next) { - - /* - * Watch out for duplicate devices. This works around - * some quirks in how the SCSI scanning code does its - * device management. - */ - for (ldev = scsi_devs; ldev != device; ldev = ldev->next) { - if (ldev->host == device->host - && ldev->channel == device->channel - && ldev->id == device->id - && ldev->lun == device->lun) - break; - } - /* Skip duplicate. */ - if (ldev != device) - continue; - - if (device->host == host) { - struct ahc_linux_device *dev; - - /* - * Since Linux has attached to the device, configure - * it so we don't free and allocate the device - * structure on every command. - */ - dev = ahc_linux_get_device(ahc, device->channel, - device->id, device->lun, - /*alloc*/TRUE); - if (dev != NULL) { - dev->flags &= ~AHC_DEV_UNCONFIGURED; - dev->scsi_device = device; - ahc_linux_device_queue_depth(ahc, dev); - device->queue_depth = dev->openings - + dev->active; - if ((dev->flags & (AHC_DEV_Q_BASIC - | AHC_DEV_Q_TAGGED)) == 0) { - /* - * We allow the OS to queue 2 untagged - * transactions to us at any time even - * though we can only execute them - * serially on the controller/device. - * This should remove some latency. - */ - device->queue_depth = 2; - } - } - } - } - ahc_unlock(ahc, &flags); -} -#endif #if defined(__i386__) /* * Return the disk geometry for the given SCSI device. */ static int -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ahc_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) { uint8_t *bh; -#else -ahc_linux_biosparam(Disk *disk, kdev_t dev, int geom[]) -{ - struct scsi_device *sdev = disk->device; - u_long capacity = disk->capacity; - struct buffer_head *bh; -#endif int heads; int sectors; int cylinders; @@ -1014,22 +802,11 @@ ahc_linux_biosparam(Disk *disk, kdev_t dev, int geom[]) ahc = *((struct ahc_softc **)sdev->host->hostdata); channel = sdev->channel; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) bh = scsi_bios_ptable(bdev); -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17) - bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, block_size(dev)); -#else - bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024); -#endif - if (bh) { ret = scsi_partsize(bh, capacity, &geom[2], &geom[0], &geom[1]); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) kfree(bh); -#else - brelse(bh); -#endif if (ret != -1) return (ret); } @@ -1090,15 +867,12 @@ static int ahc_linux_bus_reset(Scsi_Cmnd *cmd) { struct ahc_softc *ahc; - u_long s; int found; ahc = *(struct ahc_softc **)cmd->device->host->hostdata; - ahc_midlayer_entrypoint_lock(ahc, &s); found = ahc_reset_channel(ahc, cmd->device->channel + 'A', /*initiate reset*/TRUE); ahc_linux_run_complete_queue(ahc); - ahc_midlayer_entrypoint_unlock(ahc, &s); if (bootverbose) printf("%s: SCSI bus reset delivered. " @@ -1461,11 +1235,7 @@ ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) *((struct ahc_softc **)host->hostdata) = ahc; ahc_lock(ahc, &s); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_assign_lock(host, &ahc->platform_data->spin_lock); -#elif AHC_SCSI_HAS_HOST_LOCK != 0 - host->lock = &ahc->platform_data->spin_lock; -#endif ahc->platform_data->host = host; host->can_queue = AHC_MAX_QUEUE; host->cmd_per_lun = 2; @@ -1484,19 +1254,14 @@ ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) ahc_set_name(ahc, new_name); } host->unique_id = ahc->unit; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - scsi_set_pci_device(host, ahc->dev_softc); -#endif ahc_linux_initialize_scsi_bus(ahc); ahc_intr_enable(ahc, TRUE); ahc_unlock(ahc, &s); host->transportt = ahc_linux_transport_template; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_add_host(host, (ahc->dev_softc ? &ahc->dev_softc->dev : NULL)); /* XXX handle failure */ scsi_scan_host(host); -#endif return (0); } @@ -1619,7 +1384,6 @@ ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg) ahc->platform_data->irq = AHC_LINUX_NOIRQ; ahc->platform_data->hw_dma_mask = 0xFFFFFFFF; ahc_lockinit(ahc); - ahc_done_lockinit(ahc); init_timer(&ahc->platform_data->completeq_timer); ahc->platform_data->completeq_timer.data = (u_long)ahc; ahc->platform_data->completeq_timer.function = @@ -1643,9 +1407,7 @@ ahc_platform_free(struct ahc_softc *ahc) if (ahc->platform_data != NULL) { del_timer_sync(&ahc->platform_data->completeq_timer); if (ahc->platform_data->host != NULL) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_remove_host(ahc->platform_data->host); -#endif scsi_host_put(ahc->platform_data->host); } @@ -1681,16 +1443,7 @@ ahc_platform_free(struct ahc_softc *ahc) release_mem_region(ahc->platform_data->mem_busaddr, 0x1000); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - /* - * In 2.4 we detach from the scsi midlayer before the PCI - * layer invokes our remove callback. No per-instance - * detach is provided, so we must reach inside the PCI - * subsystem's internals and detach our driver manually. - */ - if (ahc->dev_softc != NULL) - ahc->dev_softc->driver = NULL; -#endif + free(ahc->platform_data, M_DEVBUF); } } @@ -1767,7 +1520,6 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, dev->maxtags = 0; dev->openings = 1 - dev->active; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) if (dev->scsi_device != NULL) { switch ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED))) { case AHC_DEV_Q_BASIC: @@ -1793,7 +1545,6 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, break; } } -#endif } int @@ -1948,7 +1699,6 @@ ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev, } if ((dev->flags & (AHC_DEV_Q_TAGGED|AHC_DEV_Q_BASIC)) != 0) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) int msg_bytes; uint8_t tag_msgs[2]; @@ -1957,10 +1707,8 @@ ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev, hscb->control |= tag_msgs[0]; if (tag_msgs[0] == MSG_ORDERED_TASK) dev->commands_since_idle_or_otag = 0; - } else -#endif - if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH - && (dev->flags & AHC_DEV_Q_TAGGED) != 0) { + } else if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH + && (dev->flags & AHC_DEV_Q_TAGGED) != 0) { hscb->control |= MSG_ORDERED_TASK; dev->commands_since_idle_or_otag = 0; } else { @@ -2280,28 +2028,9 @@ ahc_send_async(struct ahc_softc *ahc, char channel, } case AC_SENT_BDR: { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) WARN_ON(lun != CAM_LUN_WILDCARD); scsi_report_device_reset(ahc->platform_data->host, channel - 'A', target); -#else - Scsi_Device *scsi_dev; - - /* - * Find the SCSI device associated with this - * request and indicate that a UA is expected. - */ - for (scsi_dev = ahc->platform_data->host->host_queue; - scsi_dev != NULL; scsi_dev = scsi_dev->next) { - if (channel - 'A' == scsi_dev->channel - && target == scsi_dev->id - && (lun == CAM_LUN_WILDCARD - || lun == scsi_dev->lun)) { - scsi_dev->was_reset = 1; - scsi_dev->expecting_cc_ua = 1; - } - } -#endif break; } case AC_BUS_RESET: @@ -2791,7 +2520,6 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) struct ahc_softc *ahc; struct ahc_linux_device *dev; struct scb *pending_scb; - u_long s; u_int saved_scbptr; u_int active_scb_index; u_int last_phase; @@ -2818,22 +2546,6 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) printf(" 0x%x", cmd->cmnd[cdb_byte]); printf("\n"); - /* - * In all versions of Linux, we have to work around - * a major flaw in how the mid-layer is locked down - * if we are to sleep successfully in our error handler - * while allowing our interrupt handler to run. Since - * the midlayer acquires either the io_request_lock or - * our lock prior to calling us, we must use the - * spin_unlock_irq() method for unlocking our lock. - * This will force interrupts to be enabled on the - * current CPU. Since the EH thread should not have - * been running with CPU interrupts disabled other than - * by acquiring either the io_request_lock or our own - * lock, this *should* be safe. - */ - ahc_midlayer_entrypoint_lock(ahc, &s); - /* * First determine if we currently own this command. * Start by searching the device queue. If not found @@ -3090,7 +2802,6 @@ done: spin_lock_irq(&ahc->platform_data->spin_lock); } ahc_linux_run_complete_queue(ahc); - ahc_midlayer_entrypoint_unlock(ahc, &s); return (retval); } @@ -3357,7 +3068,6 @@ static struct spi_function_template ahc_linux_transport_functions = { static int __init ahc_linux_init(void) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ahc_linux_transport_template = spi_attach_transport(&ahc_linux_transport_functions); if (!ahc_linux_transport_template) return -ENODEV; @@ -3366,29 +3076,11 @@ ahc_linux_init(void) spi_release_transport(ahc_linux_transport_template); ahc_linux_exit(); return -ENODEV; -#else - scsi_register_module(MODULE_SCSI_HA, &aic7xxx_driver_template); - if (aic7xxx_driver_template.present == 0) { - scsi_unregister_module(MODULE_SCSI_HA, - &aic7xxx_driver_template); - return (-ENODEV); - } - - return (0); -#endif } static void ahc_linux_exit(void) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - /* - * In 2.4 we have to unregister from the PCI core _after_ - * unregistering from the scsi midlayer to avoid dangling - * references. - */ - scsi_unregister_module(MODULE_SCSI_HA, &aic7xxx_driver_template); -#endif ahc_linux_pci_exit(); ahc_linux_eisa_exit(); spi_release_transport(ahc_linux_transport_template); diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index 6ea2bfb8820..752022e4d4d 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -281,12 +281,6 @@ ahc_scb_timer_reset(struct scb *scb, u_int usec) /***************************** SMP support ************************************/ #include -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) || defined(SCSI_HAS_HOST_LOCK)) -#define AHC_SCSI_HAS_HOST_LOCK 1 -#else -#define AHC_SCSI_HAS_HOST_LOCK 0 -#endif - #define AIC7XXX_DRIVER_VERSION "6.2.36" /**************************** Front End Queues ********************************/ @@ -438,18 +432,7 @@ struct ahc_linux_target { * manner and are allocated below 4GB, the number of S/G segments is * unrestricted. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -/* - * We dynamically adjust the number of segments in pre-2.5 kernels to - * avoid fragmentation issues in the SCSI mid-layer's private memory - * allocator. See aic7xxx_osm.c ahc_linux_size_nseg() for details. - */ -extern u_int ahc_linux_nseg; -#define AHC_NSEG ahc_linux_nseg -#define AHC_LINUX_MIN_NSEG 64 -#else #define AHC_NSEG 128 -#endif /* * Per-SCB OSM storage. @@ -607,17 +590,6 @@ static __inline void ahc_lockinit(struct ahc_softc *); static __inline void ahc_lock(struct ahc_softc *, unsigned long *flags); static __inline void ahc_unlock(struct ahc_softc *, unsigned long *flags); -/* Lock acquisition and release of the above lock in midlayer entry points. */ -static __inline void ahc_midlayer_entrypoint_lock(struct ahc_softc *, - unsigned long *flags); -static __inline void ahc_midlayer_entrypoint_unlock(struct ahc_softc *, - unsigned long *flags); - -/* Lock held during command compeletion to the upper layer */ -static __inline void ahc_done_lockinit(struct ahc_softc *); -static __inline void ahc_done_lock(struct ahc_softc *, unsigned long *flags); -static __inline void ahc_done_unlock(struct ahc_softc *, unsigned long *flags); - /* Lock held during ahc_list manipulation and ahc softc frees */ extern spinlock_t ahc_list_spinlock; static __inline void ahc_list_lockinit(void); @@ -642,57 +614,6 @@ ahc_unlock(struct ahc_softc *ahc, unsigned long *flags) spin_unlock_irqrestore(&ahc->platform_data->spin_lock, *flags); } -static __inline void -ahc_midlayer_entrypoint_lock(struct ahc_softc *ahc, unsigned long *flags) -{ - /* - * In 2.5.X and some 2.4.X versions, the midlayer takes our - * lock just before calling us, so we avoid locking again. - * For other kernel versions, the io_request_lock is taken - * just before our entry point is called. In this case, we - * trade the io_request_lock for our per-softc lock. - */ -#if AHC_SCSI_HAS_HOST_LOCK == 0 - spin_unlock(&io_request_lock); - spin_lock(&ahc->platform_data->spin_lock); -#endif -} - -static __inline void -ahc_midlayer_entrypoint_unlock(struct ahc_softc *ahc, unsigned long *flags) -{ -#if AHC_SCSI_HAS_HOST_LOCK == 0 - spin_unlock(&ahc->platform_data->spin_lock); - spin_lock(&io_request_lock); -#endif -} - -static __inline void -ahc_done_lockinit(struct ahc_softc *ahc) -{ - /* - * In 2.5.X, our own lock is held during completions. - * In previous versions, the io_request_lock is used. - * In either case, we can't initialize this lock again. - */ -} - -static __inline void -ahc_done_lock(struct ahc_softc *ahc, unsigned long *flags) -{ -#if AHC_SCSI_HAS_HOST_LOCK == 0 - spin_lock_irqsave(&io_request_lock, *flags); -#endif -} - -static __inline void -ahc_done_unlock(struct ahc_softc *ahc, unsigned long *flags) -{ -#if AHC_SCSI_HAS_HOST_LOCK == 0 - spin_unlock_irqrestore(&io_request_lock, *flags); -#endif -} - static __inline void ahc_list_lockinit(void) { @@ -759,12 +680,6 @@ typedef enum } ahc_power_state; /**************************** VL/EISA Routines ********************************/ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) \ - && (defined(__i386__) || defined(__alpha__)) \ - && (!defined(CONFIG_EISA))) -#define CONFIG_EISA -#endif - #ifdef CONFIG_EISA extern uint32_t aic7xxx_probe_eisa_vl; int ahc_linux_eisa_init(void); @@ -880,12 +795,8 @@ ahc_flush_device_writes(struct ahc_softc *ahc) } /**************************** Proc FS Support *********************************/ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -int ahc_linux_proc_info(char *, char **, off_t, int, int, int); -#else int ahc_linux_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); -#endif /*************************** Domain Validation ********************************/ /*********************** Transaction Access Wrappers *************************/ diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c index 6f6674aa31e..886f92f9184 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c @@ -236,15 +236,8 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return (-error); } pci_set_drvdata(pdev, ahc); - if (aic7xxx_detect_complete) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + if (aic7xxx_detect_complete) ahc_linux_register_host(ahc, &aic7xxx_driver_template); -#else - printf("aic7xxx: ignoring PCI device found after " - "initialization\n"); - return (-ENODEV); -#endif - } return (0); } diff --git a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c index 85e80eecc9d..5fece859fbd 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_proc.c +++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c @@ -289,13 +289,8 @@ done: * Return information to handle /proc support for the driver. */ int -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -ahc_linux_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int inout) -#else ahc_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length, int inout) -#endif { struct ahc_softc *ahc; struct info_str info; @@ -307,15 +302,7 @@ ahc_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, retval = -EINVAL; ahc_list_lock(&s); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - TAILQ_FOREACH(ahc, &ahc_tailq, links) { - if (ahc->platform_data->host->host_no == hostno) - break; - } -#else ahc = ahc_find_softc(*(struct ahc_softc **)shost->hostdata); -#endif - if (ahc == NULL) goto done; -- cgit v1.2.3 From 7dfa0f2673c17334c5de75a449f7bc161c9bd2c0 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 16 May 2005 18:54:12 +0200 Subject: [SCSI] remove dma_mask hacks pci_alloc_consistent is under 4G by default. Also simplify the definition of bus_dmamap_t. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7xxx_osm.c | 43 ++++------------------------------ drivers/scsi/aic7xxx/aic7xxx_osm.h | 7 +----- drivers/scsi/aic7xxx/aic7xxx_osm_pci.c | 2 -- 3 files changed, 6 insertions(+), 46 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 37fda70b543..717401b26b6 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -949,37 +949,11 @@ int ahc_dmamem_alloc(struct ahc_softc *ahc, bus_dma_tag_t dmat, void** vaddr, int flags, bus_dmamap_t *mapp) { - bus_dmamap_t map; - - map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT); - if (map == NULL) - return (ENOMEM); - /* - * Although we can dma data above 4GB, our - * "consistent" memory is below 4GB for - * space efficiency reasons (only need a 4byte - * address). For this reason, we have to reset - * our dma mask when doing allocations. - */ - if (ahc->dev_softc != NULL) - if (pci_set_dma_mask(ahc->dev_softc, 0xFFFFFFFF)) { - printk(KERN_WARNING "aic7xxx: No suitable DMA available.\n"); - kfree(map); - return (ENODEV); - } *vaddr = pci_alloc_consistent(ahc->dev_softc, - dmat->maxsize, &map->bus_addr); - if (ahc->dev_softc != NULL) - if (pci_set_dma_mask(ahc->dev_softc, - ahc->platform_data->hw_dma_mask)) { - printk(KERN_WARNING "aic7xxx: No suitable DMA available.\n"); - kfree(map); - return (ENODEV); - } + dmat->maxsize, mapp); if (*vaddr == NULL) - return (ENOMEM); - *mapp = map; - return(0); + return ENOMEM; + return 0; } void @@ -987,7 +961,7 @@ ahc_dmamem_free(struct ahc_softc *ahc, bus_dma_tag_t dmat, void* vaddr, bus_dmamap_t map) { pci_free_consistent(ahc->dev_softc, dmat->maxsize, - vaddr, map->bus_addr); + vaddr, map); } int @@ -1001,7 +975,7 @@ ahc_dmamap_load(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map, */ bus_dma_segment_t stack_sg; - stack_sg.ds_addr = map->bus_addr; + stack_sg.ds_addr = map; stack_sg.ds_len = dmat->maxsize; cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0); return (0); @@ -1010,12 +984,6 @@ ahc_dmamap_load(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map, void ahc_dmamap_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map) { - /* - * The map may is NULL in our < 2.3.X implementation. - * Now it's 2.6.5, but just in case... - */ - BUG_ON(map == NULL); - free(map, M_DEVBUF); } int @@ -1382,7 +1350,6 @@ ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg) TAILQ_INIT(&ahc->platform_data->completeq); TAILQ_INIT(&ahc->platform_data->device_runq); ahc->platform_data->irq = AHC_LINUX_NOIRQ; - ahc->platform_data->hw_dma_mask = 0xFFFFFFFF; ahc_lockinit(ahc); init_timer(&ahc->platform_data->completeq_timer); ahc->platform_data->completeq_timer.data = (u_long)ahc; diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index 752022e4d4d..9cfb46b4b15 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -174,11 +174,7 @@ struct ahc_linux_dma_tag }; typedef struct ahc_linux_dma_tag* bus_dma_tag_t; -struct ahc_linux_dmamap -{ - dma_addr_t bus_addr; -}; -typedef struct ahc_linux_dmamap* bus_dmamap_t; +typedef dma_addr_t bus_dmamap_t; typedef int bus_dma_filter_t(void*, dma_addr_t); typedef void bus_dmamap_callback_t(void *, bus_dma_segment_t *, int, int); @@ -479,7 +475,6 @@ struct ahc_platform_data { uint32_t irq; /* IRQ for this adapter */ uint32_t bios_address; uint32_t mem_busaddr; /* Mem Base Addr */ - uint64_t hw_dma_mask; ahc_linux_softc_flags flags; }; diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c index 886f92f9184..2a0ebce83e7 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c @@ -221,13 +221,11 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) && ahc_linux_get_memsize() > 0x80000000 && pci_set_dma_mask(pdev, mask_39bit) == 0) { ahc->flags |= AHC_39BIT_ADDRESSING; - ahc->platform_data->hw_dma_mask = mask_39bit; } else { if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { printk(KERN_WARNING "aic7xxx: No suitable DMA available.\n"); return (-ENODEV); } - ahc->platform_data->hw_dma_mask = DMA_32BIT_MASK; } ahc->dev_softc = pci; error = ahc_pci_config(ahc, entry); -- cgit v1.2.3 From 013791ee01754f83dbb4ccfd266381db74e120b5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 16 May 2005 18:52:39 +0200 Subject: [SCSI] aic7xxx: remove usage of obsolete typedefs Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7xxx_osm.c | 52 +++++++++++++------------------------- drivers/scsi/aic7xxx/aic7xxx_osm.h | 36 ++++++++++++++------------ drivers/scsi/aic7xxx/aiclib.c | 1 - 3 files changed, 38 insertions(+), 51 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 717401b26b6..ff2a212c6e9 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -426,12 +426,12 @@ static void ahc_linux_handle_scsi_status(struct ahc_softc *, struct ahc_linux_device *, struct scb *); static void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, - Scsi_Cmnd *cmd); + struct scsi_cmnd *cmd); static void ahc_linux_sem_timeout(u_long arg); static void ahc_linux_freeze_simq(struct ahc_softc *ahc); static void ahc_linux_release_simq(u_long arg); static void ahc_linux_dev_timed_unfreeze(u_long arg); -static int ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag); +static int ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag); static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc); static void ahc_linux_thread_run_complete_queue(struct ahc_softc *ahc); static u_int ahc_linux_user_tagdepth(struct ahc_softc *ahc, @@ -512,7 +512,7 @@ ahc_linux_run_complete_queue(struct ahc_softc *ahc) with_errors = 0; while ((acmd = TAILQ_FIRST(&ahc->platform_data->completeq)) != NULL) { - Scsi_Cmnd *cmd; + struct scsi_cmnd *cmd; if (with_errors > AHC_LINUX_MAX_RETURNED_ERRORS) { /* @@ -542,7 +542,7 @@ ahc_linux_run_complete_queue(struct ahc_softc *ahc) static __inline void ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb) { - Scsi_Cmnd *cmd; + struct scsi_cmnd *cmd; cmd = scb->io_ctx; ahc_sync_sglist(ahc, scb, BUS_DMASYNC_POSTWRITE); @@ -582,27 +582,11 @@ ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb, return (consumed); } -/************************ Host template entry points *************************/ -static int ahc_linux_detect(Scsi_Host_Template *); -static int ahc_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); -static const char *ahc_linux_info(struct Scsi_Host *); -static int ahc_linux_slave_alloc(Scsi_Device *); -static int ahc_linux_slave_configure(Scsi_Device *); -static void ahc_linux_slave_destroy(Scsi_Device *); -#if defined(__i386__) -static int ahc_linux_biosparam(struct scsi_device*, - struct block_device*, - sector_t, int[]); -#endif -static int ahc_linux_bus_reset(Scsi_Cmnd *); -static int ahc_linux_dev_reset(Scsi_Cmnd *); -static int ahc_linux_abort(Scsi_Cmnd *); - /* * Try to detect an Adaptec 7XXX controller. */ static int -ahc_linux_detect(Scsi_Host_Template *template) +ahc_linux_detect(struct scsi_host_template *template) { struct ahc_softc *ahc; int found = 0; @@ -683,7 +667,7 @@ ahc_linux_info(struct Scsi_Host *host) * Queue an SCB to the controller. */ static int -ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) +ahc_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *)) { struct ahc_softc *ahc; struct ahc_linux_device *dev; @@ -714,7 +698,7 @@ ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) } static int -ahc_linux_slave_alloc(Scsi_Device *device) +ahc_linux_slave_alloc(struct scsi_device *device) { struct ahc_softc *ahc; @@ -725,7 +709,7 @@ ahc_linux_slave_alloc(Scsi_Device *device) } static int -ahc_linux_slave_configure(Scsi_Device *device) +ahc_linux_slave_configure(struct scsi_device *device) { struct ahc_softc *ahc; struct ahc_linux_device *dev; @@ -755,7 +739,7 @@ ahc_linux_slave_configure(Scsi_Device *device) } static void -ahc_linux_slave_destroy(Scsi_Device *device) +ahc_linux_slave_destroy(struct scsi_device *device) { struct ahc_softc *ahc; struct ahc_linux_device *dev; @@ -836,7 +820,7 @@ ahc_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, * Abort the current SCSI command(s). */ static int -ahc_linux_abort(Scsi_Cmnd *cmd) +ahc_linux_abort(struct scsi_cmnd *cmd) { int error; @@ -850,7 +834,7 @@ ahc_linux_abort(Scsi_Cmnd *cmd) * Attempt to send a target reset message to the device that timed out. */ static int -ahc_linux_dev_reset(Scsi_Cmnd *cmd) +ahc_linux_dev_reset(struct scsi_cmnd *cmd) { int error; @@ -864,7 +848,7 @@ ahc_linux_dev_reset(Scsi_Cmnd *cmd) * Reset the SCSI bus. */ static int -ahc_linux_bus_reset(Scsi_Cmnd *cmd) +ahc_linux_bus_reset(struct scsi_cmnd *cmd) { struct ahc_softc *ahc; int found; @@ -881,7 +865,7 @@ ahc_linux_bus_reset(Scsi_Cmnd *cmd) return SUCCESS; } -Scsi_Host_Template aic7xxx_driver_template = { +struct scsi_host_template aic7xxx_driver_template = { .module = THIS_MODULE, .name = "aic7xxx", .proc_info = ahc_linux_proc_info, @@ -1189,7 +1173,7 @@ __setup("aic7xxx=", aic7xxx_setup); uint32_t aic7xxx_verbose; int -ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) +ahc_linux_register_host(struct ahc_softc *ahc, struct scsi_host_template *template) { char buf[80]; struct Scsi_Host *host; @@ -2017,7 +2001,7 @@ ahc_send_async(struct ahc_softc *ahc, char channel, void ahc_done(struct ahc_softc *ahc, struct scb *scb) { - Scsi_Cmnd *cmd; + struct scsi_cmnd *cmd; struct ahc_linux_device *dev; LIST_REMOVE(scb, pending_links); @@ -2171,7 +2155,7 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc, case SCSI_STATUS_CHECK_COND: case SCSI_STATUS_CMD_TERMINATED: { - Scsi_Cmnd *cmd; + struct scsi_cmnd *cmd; /* * Copy sense information to the OS's cmd @@ -2293,7 +2277,7 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc, } static void -ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, Scsi_Cmnd *cmd) +ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, struct scsi_cmnd *cmd) { /* * Typically, the complete queue has very few entries @@ -2482,7 +2466,7 @@ ahc_linux_dev_timed_unfreeze(u_long arg) } static int -ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) +ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) { struct ahc_softc *ahc; struct ahc_linux_device *dev; diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index 9cfb46b4b15..2afd0521c4a 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -59,6 +59,7 @@ #ifndef _AIC7XXX_LINUX_H_ #define _AIC7XXX_LINUX_H_ +#include #include #include #include @@ -68,16 +69,19 @@ #include #include #include +#include #include #include -#include -#include +#include +#include +#include +#include +#include +#include /* Core SCSI definitions */ #define AIC_LIB_PREFIX ahc -#include "scsi.h" -#include /* Name space conflict with BSD queue macros */ #ifdef LIST_HEAD @@ -106,7 +110,7 @@ /************************* Forward Declarations *******************************/ struct ahc_softc; typedef struct pci_dev *ahc_dev_softc_t; -typedef Scsi_Cmnd *ahc_io_ctx_t; +typedef struct scsi_cmnd *ahc_io_ctx_t; /******************************* Byte Order ***********************************/ #define ahc_htobe16(x) cpu_to_be16(x) @@ -144,7 +148,7 @@ typedef Scsi_Cmnd *ahc_io_ctx_t; extern u_int aic7xxx_no_probe; extern u_int aic7xxx_allow_memio; extern int aic7xxx_detect_complete; -extern Scsi_Host_Template aic7xxx_driver_template; +extern struct scsi_host_template aic7xxx_driver_template; /***************************** Bus Space/DMA **********************************/ @@ -408,7 +412,7 @@ struct ahc_linux_device { #define AHC_OTAG_THRESH 500 int lun; - Scsi_Device *scsi_device; + struct scsi_device *scsi_device; struct ahc_linux_target *target; }; @@ -564,7 +568,7 @@ ahc_insb(struct ahc_softc * ahc, long port, uint8_t *array, int count) /**************************** Initialization **********************************/ int ahc_linux_register_host(struct ahc_softc *, - Scsi_Host_Template *); + struct scsi_host_template *); uint64_t ahc_linux_get_memsize(void); @@ -795,13 +799,13 @@ int ahc_linux_proc_info(struct Scsi_Host *, char *, char **, /*************************** Domain Validation ********************************/ /*********************** Transaction Access Wrappers *************************/ -static __inline void ahc_cmd_set_transaction_status(Scsi_Cmnd *, uint32_t); +static __inline void ahc_cmd_set_transaction_status(struct scsi_cmnd *, uint32_t); static __inline void ahc_set_transaction_status(struct scb *, uint32_t); -static __inline void ahc_cmd_set_scsi_status(Scsi_Cmnd *, uint32_t); +static __inline void ahc_cmd_set_scsi_status(struct scsi_cmnd *, uint32_t); static __inline void ahc_set_scsi_status(struct scb *, uint32_t); -static __inline uint32_t ahc_cmd_get_transaction_status(Scsi_Cmnd *cmd); +static __inline uint32_t ahc_cmd_get_transaction_status(struct scsi_cmnd *cmd); static __inline uint32_t ahc_get_transaction_status(struct scb *); -static __inline uint32_t ahc_cmd_get_scsi_status(Scsi_Cmnd *cmd); +static __inline uint32_t ahc_cmd_get_scsi_status(struct scsi_cmnd *cmd); static __inline uint32_t ahc_get_scsi_status(struct scb *); static __inline void ahc_set_transaction_tag(struct scb *, int, u_int); static __inline u_long ahc_get_transfer_length(struct scb *); @@ -820,7 +824,7 @@ static __inline void ahc_platform_scb_free(struct ahc_softc *ahc, static __inline void ahc_freeze_scb(struct scb *scb); static __inline -void ahc_cmd_set_transaction_status(Scsi_Cmnd *cmd, uint32_t status) +void ahc_cmd_set_transaction_status(struct scsi_cmnd *cmd, uint32_t status) { cmd->result &= ~(CAM_STATUS_MASK << 16); cmd->result |= status << 16; @@ -833,7 +837,7 @@ void ahc_set_transaction_status(struct scb *scb, uint32_t status) } static __inline -void ahc_cmd_set_scsi_status(Scsi_Cmnd *cmd, uint32_t status) +void ahc_cmd_set_scsi_status(struct scsi_cmnd *cmd, uint32_t status) { cmd->result &= ~0xFFFF; cmd->result |= status; @@ -846,7 +850,7 @@ void ahc_set_scsi_status(struct scb *scb, uint32_t status) } static __inline -uint32_t ahc_cmd_get_transaction_status(Scsi_Cmnd *cmd) +uint32_t ahc_cmd_get_transaction_status(struct scsi_cmnd *cmd) { return ((cmd->result >> 16) & CAM_STATUS_MASK); } @@ -858,7 +862,7 @@ uint32_t ahc_get_transaction_status(struct scb *scb) } static __inline -uint32_t ahc_cmd_get_scsi_status(Scsi_Cmnd *cmd) +uint32_t ahc_cmd_get_scsi_status(struct scsi_cmnd *cmd) { return (cmd->result & 0xFFFF); } diff --git a/drivers/scsi/aic7xxx/aiclib.c b/drivers/scsi/aic7xxx/aiclib.c index 79bfd9efd8e..7c5a6db0e67 100644 --- a/drivers/scsi/aic7xxx/aiclib.c +++ b/drivers/scsi/aic7xxx/aiclib.c @@ -35,7 +35,6 @@ #include /* Core SCSI definitions */ -#include "scsi.h" #include #include "aiclib.h" #include "cam.h" -- cgit v1.2.3 From 38c29ce06d24691d6e6dd786175fcc54efd5995b Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Mon, 16 May 2005 21:37:58 -0500 Subject: [SCSI] aic7xxx: remove the last vestiges of the runq This was rendered obsolete by the busyq removal; remove some of the last remnants of its presence. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7xxx_osm.c | 5 ----- drivers/scsi/aic7xxx/aic7xxx_osm.h | 2 -- 2 files changed, 7 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index ff2a212c6e9..d0c71da58e8 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -1332,7 +1332,6 @@ ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg) return (ENOMEM); memset(ahc->platform_data, 0, sizeof(struct ahc_platform_data)); TAILQ_INIT(&ahc->platform_data->completeq); - TAILQ_INIT(&ahc->platform_data->device_runq); ahc->platform_data->irq = AHC_LINUX_NOIRQ; ahc_lockinit(ahc); init_timer(&ahc->platform_data->completeq_timer); @@ -2107,10 +2106,6 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) && dev->active == 0 && (dev->flags & AHC_DEV_TIMER_ACTIVE) == 0) ahc_linux_free_device(ahc, dev); - else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { - TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links); - dev->flags |= AHC_DEV_ON_RUN_LIST; - } if ((scb->flags & SCB_RECOVERY_SCB) != 0) { printf("Recovery SCB completes\n"); diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index 2afd0521c4a..9ce7639dc73 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -325,7 +325,6 @@ typedef enum { AHC_DEV_UNCONFIGURED = 0x01, AHC_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ AHC_DEV_TIMER_ACTIVE = 0x04, /* Our timer is active */ - AHC_DEV_ON_RUN_LIST = 0x08, /* Queued to be run later */ AHC_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */ AHC_DEV_Q_TAGGED = 0x20, /* Allow full SCSI2 command queueing */ AHC_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */ @@ -466,7 +465,6 @@ struct ahc_platform_data { * Fields accessed from interrupt context. */ struct ahc_linux_target *targets[AHC_NUM_TARGETS]; - TAILQ_HEAD(, ahc_linux_device) device_runq; struct ahc_completeq completeq; spinlock_t spin_lock; -- cgit v1.2.3 From 8e45ebcc661069bfb002c56dd942aedf43ba9239 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 17 May 2005 00:06:08 -0500 Subject: [SCSI] aic7xxx: remove the completeq This should finish the spurious queue removal from aic7xxx (there are other queues that are probably unnecessary, but at least the major and obviously unnecessary ones are done with). Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7xxx_osm.c | 121 +------------------------------------ drivers/scsi/aic7xxx/aic7xxx_osm.h | 17 +----- 2 files changed, 5 insertions(+), 133 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index d0c71da58e8..ca796b9d737 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -433,7 +433,6 @@ static void ahc_linux_release_simq(u_long arg); static void ahc_linux_dev_timed_unfreeze(u_long arg); static int ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag); static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc); -static void ahc_linux_thread_run_complete_queue(struct ahc_softc *ahc); static u_int ahc_linux_user_tagdepth(struct ahc_softc *ahc, struct ahc_devinfo *devinfo); static void ahc_linux_device_queue_depth(struct ahc_softc *ahc, @@ -454,29 +453,17 @@ static void ahc_linux_setup_tag_info_global(char *p); static aic_option_callback_t ahc_linux_setup_tag_info; static int aic7xxx_setup(char *s); static int ahc_linux_next_unit(void); -static struct ahc_cmd *ahc_linux_run_complete_queue(struct ahc_softc *ahc); /********************************* Inlines ************************************/ static __inline struct ahc_linux_device* ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target, u_int lun, int alloc); -static __inline void ahc_schedule_completeq(struct ahc_softc *ahc); static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*); static __inline int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb, struct ahc_dma_seg *sg, dma_addr_t addr, bus_size_t len); -static __inline void -ahc_schedule_completeq(struct ahc_softc *ahc) -{ - if ((ahc->platform_data->flags & AHC_RUN_CMPLT_Q_TIMER) == 0) { - ahc->platform_data->flags |= AHC_RUN_CMPLT_Q_TIMER; - ahc->platform_data->completeq_timer.expires = jiffies; - add_timer(&ahc->platform_data->completeq_timer); - } -} - static __inline struct ahc_linux_device* ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target, u_int lun, int alloc) @@ -503,42 +490,6 @@ ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target, return (dev); } -#define AHC_LINUX_MAX_RETURNED_ERRORS 4 -static struct ahc_cmd * -ahc_linux_run_complete_queue(struct ahc_softc *ahc) -{ - struct ahc_cmd *acmd; - int with_errors; - - with_errors = 0; - while ((acmd = TAILQ_FIRST(&ahc->platform_data->completeq)) != NULL) { - struct scsi_cmnd *cmd; - - if (with_errors > AHC_LINUX_MAX_RETURNED_ERRORS) { - /* - * Linux uses stack recursion to requeue - * commands that need to be retried. Avoid - * blowing out the stack by "spoon feeding" - * commands that completed with error back - * the operating system in case they are going - * to be retried. "ick" - */ - ahc_schedule_completeq(ahc); - break; - } - TAILQ_REMOVE(&ahc->platform_data->completeq, - acmd, acmd_links.tqe); - cmd = &acmd_scsi_cmd(acmd); - cmd->host_scribble = NULL; - if (ahc_cmd_get_transaction_status(cmd) != DID_OK - || (cmd->result & 0xFF) != SCSI_STATUS_OK) - with_errors++; - - cmd->scsi_done(cmd); - } - return (acmd); -} - static __inline void ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb) { @@ -856,7 +807,6 @@ ahc_linux_bus_reset(struct scsi_cmnd *cmd) ahc = *(struct ahc_softc **)cmd->device->host->hostdata; found = ahc_reset_channel(ahc, cmd->device->channel + 'A', /*initiate reset*/TRUE); - ahc_linux_run_complete_queue(ahc); if (bootverbose) printf("%s: SCSI bus reset delivered. " @@ -1331,13 +1281,8 @@ ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg) if (ahc->platform_data == NULL) return (ENOMEM); memset(ahc->platform_data, 0, sizeof(struct ahc_platform_data)); - TAILQ_INIT(&ahc->platform_data->completeq); ahc->platform_data->irq = AHC_LINUX_NOIRQ; ahc_lockinit(ahc); - init_timer(&ahc->platform_data->completeq_timer); - ahc->platform_data->completeq_timer.data = (u_long)ahc; - ahc->platform_data->completeq_timer.function = - (ahc_linux_callback_t *)ahc_linux_thread_run_complete_queue; init_MUTEX_LOCKED(&ahc->platform_data->eh_sem); ahc->seltime = (aic7xxx_seltime & 0x3) << 4; ahc->seltime_b = (aic7xxx_seltime & 0x3) << 4; @@ -1355,7 +1300,6 @@ ahc_platform_free(struct ahc_softc *ahc) int i, j; if (ahc->platform_data != NULL) { - del_timer_sync(&ahc->platform_data->completeq_timer); if (ahc->platform_data->host != NULL) { scsi_remove_host(ahc->platform_data->host); scsi_host_put(ahc->platform_data->host); @@ -1504,18 +1448,6 @@ ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, char channel, return 0; } -static void -ahc_linux_thread_run_complete_queue(struct ahc_softc *ahc) -{ - u_long flags; - - ahc_lock(ahc, &flags); - del_timer(&ahc->platform_data->completeq_timer); - ahc->platform_data->flags &= ~AHC_RUN_CMPLT_Q_TIMER; - ahc_linux_run_complete_queue(ahc); - ahc_unlock(ahc, &flags); -} - static u_int ahc_linux_user_tagdepth(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) { @@ -1785,7 +1717,6 @@ ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs) ahc = (struct ahc_softc *) dev_id; ahc_lock(ahc, &flags); ours = ahc_intr(ahc); - ahc_linux_run_complete_queue(ahc); ahc_unlock(ahc, &flags); return IRQ_RETVAL(ours); } @@ -1794,8 +1725,6 @@ void ahc_platform_flushwork(struct ahc_softc *ahc) { - while (ahc_linux_run_complete_queue(ahc) != NULL) - ; } static struct ahc_linux_target* @@ -2274,22 +2203,6 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc, static void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, struct scsi_cmnd *cmd) { - /* - * Typically, the complete queue has very few entries - * queued to it before the queue is emptied by - * ahc_linux_run_complete_queue, so sorting the entries - * by generation number should be inexpensive. - * We perform the sort so that commands that complete - * with an error are retuned in the order origionally - * queued to the controller so that any subsequent retries - * are performed in order. The underlying ahc routines do - * not guarantee the order that aborted commands will be - * returned to us. - */ - struct ahc_completeq *completeq; - struct ahc_cmd *list_cmd; - struct ahc_cmd *acmd; - /* * Map CAM error codes into Linux Error codes. We * avoid the conversion so that the DV code has the @@ -2343,26 +2256,7 @@ ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, struct scsi_cmnd *cmd) new_status = DID_ERROR; break; case CAM_REQUEUE_REQ: - /* - * If we want the request requeued, make sure there - * are sufficent retries. In the old scsi error code, - * we used to be able to specify a result code that - * bypassed the retry count. Now we must use this - * hack. We also "fake" a check condition with - * a sense code of ABORTED COMMAND. This seems to - * evoke a retry even if this command is being sent - * via the eh thread. Ick! Ick! Ick! - */ - if (cmd->retries > 0) - cmd->retries--; - new_status = DID_OK; - ahc_cmd_set_scsi_status(cmd, SCSI_STATUS_CHECK_COND); - cmd->result |= (DRIVER_SENSE << 24); - memset(cmd->sense_buffer, 0, - sizeof(cmd->sense_buffer)); - cmd->sense_buffer[0] = SSD_ERRCODE_VALID - | SSD_CURRENT_ERROR; - cmd->sense_buffer[2] = SSD_KEY_ABORTED_COMMAND; + new_status = DID_REQUEUE; break; default: /* We should never get here */ @@ -2373,17 +2267,7 @@ ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, struct scsi_cmnd *cmd) ahc_cmd_set_transaction_status(cmd, new_status); } - completeq = &ahc->platform_data->completeq; - list_cmd = TAILQ_FIRST(completeq); - acmd = (struct ahc_cmd *)cmd; - while (list_cmd != NULL - && acmd_scsi_cmd(list_cmd).serial_number - < acmd_scsi_cmd(acmd).serial_number) - list_cmd = TAILQ_NEXT(list_cmd, acmd_links.tqe); - if (list_cmd != NULL) - TAILQ_INSERT_BEFORE(list_cmd, acmd, acmd_links.tqe); - else - TAILQ_INSERT_TAIL(completeq, acmd, acmd_links.tqe); + cmd->scsi_done(cmd); } static void @@ -2747,7 +2631,6 @@ done: } spin_lock_irq(&ahc->platform_data->spin_lock); } - ahc_linux_run_complete_queue(ahc); return (retval); } diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index 9ce7639dc73..e70c1fa47db 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -436,16 +436,11 @@ struct ahc_linux_target { /* * Per-SCB OSM storage. */ -typedef enum { - AHC_UP_EH_SEMAPHORE = 0x1 -} ahc_linux_scb_flags; - struct scb_platform_data { struct ahc_linux_device *dev; dma_addr_t buf_busaddr; uint32_t xfer_len; uint32_t sense_resid; /* Auto-Sense residual */ - ahc_linux_scb_flags flags; }; /* @@ -454,22 +449,14 @@ struct scb_platform_data { * alignment restrictions of the various platforms supported by * this driver. */ -typedef enum { - AHC_RUN_CMPLT_Q_TIMER = 0x10 -} ahc_linux_softc_flags; - -TAILQ_HEAD(ahc_completeq, ahc_cmd); - struct ahc_platform_data { /* * Fields accessed from interrupt context. */ struct ahc_linux_target *targets[AHC_NUM_TARGETS]; - struct ahc_completeq completeq; spinlock_t spin_lock; u_int qfrozen; - struct timer_list completeq_timer; struct timer_list reset_timer; struct semaphore eh_sem; struct Scsi_Host *host; /* pointer to scsi host */ @@ -477,7 +464,9 @@ struct ahc_platform_data { uint32_t irq; /* IRQ for this adapter */ uint32_t bios_address; uint32_t mem_busaddr; /* Mem Base Addr */ - ahc_linux_softc_flags flags; + +#define AHC_UP_EH_SEMAPHORE 0x1 + uint32_t flags; }; /************************** OS Utility Wrappers *******************************/ -- cgit v1.2.3 From c7525233d2df39b95552f6f49c6b390a9c4d2e80 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 17 May 2005 18:07:34 -0500 Subject: [SCSI] aic7xxx: make correct use of slave_alloc/destroy and remove the per device timer The allocation of all of our components should be done in slave alloc. Currently it's rather fancifully refcounted in the queuecommand callback. This patch moves allocation and destroy to their correct places in slave_alloc/slave_destory. Now we can guarantee that everywhere a device is requested, it's actually been allocated, so don't check for this anymore. Additionally, the per device busy timer was the only source of potential use after free. It's been deleted because Linux does the correct thing with busy returns, so there's no need to implement a separate timer in the driver. Finally, implement code that forces all the device parameters to zero (i.e. async and narrow) in the slave alloc, inform the spi class of the bios recorded maximums and wait until slave configure before trying anything more adventurous. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7xxx_osm.c | 183 ++++++++++++++++--------------------- drivers/scsi/aic7xxx/aic7xxx_osm.h | 8 -- 2 files changed, 79 insertions(+), 112 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index ca796b9d737..c03f2948607 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -430,7 +430,6 @@ static void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, static void ahc_linux_sem_timeout(u_long arg); static void ahc_linux_freeze_simq(struct ahc_softc *ahc); static void ahc_linux_release_simq(u_long arg); -static void ahc_linux_dev_timed_unfreeze(u_long arg); static int ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag); static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc); static u_int ahc_linux_user_tagdepth(struct ahc_softc *ahc, @@ -457,7 +456,7 @@ static int ahc_linux_next_unit(void); /********************************* Inlines ************************************/ static __inline struct ahc_linux_device* ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, - u_int target, u_int lun, int alloc); + u_int target, u_int lun); static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*); static __inline int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb, @@ -466,7 +465,7 @@ static __inline int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb, static __inline struct ahc_linux_device* ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target, - u_int lun, int alloc) + u_int lun) { struct ahc_linux_target *targ; struct ahc_linux_device *dev; @@ -476,18 +475,9 @@ ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target, if (channel != 0) target_offset += 8; targ = ahc->platform_data->targets[target_offset]; - if (targ == NULL) { - if (alloc != 0) { - targ = ahc_linux_alloc_target(ahc, channel, target); - if (targ == NULL) - return (NULL); - } else - return (NULL); - } + BUG_ON(targ == NULL); dev = targ->devices[lun]; - if (dev == NULL && alloc != 0) - dev = ahc_linux_alloc_device(ahc, targ, lun); - return (dev); + return dev; } static __inline void @@ -640,7 +630,7 @@ ahc_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *)) return SCSI_MLQUEUE_HOST_BUSY; dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id, - cmd->device->lun, /*alloc*/TRUE); + cmd->device->lun); BUG_ON(dev == NULL); cmd->result = CAM_REQ_INPROG << 16; @@ -652,11 +642,69 @@ static int ahc_linux_slave_alloc(struct scsi_device *device) { struct ahc_softc *ahc; + struct ahc_linux_target *targ; + struct scsi_target *starget = device->sdev_target; + struct ahc_linux_device *dev; + u_int target_offset; + + target_offset = starget->id; + if (starget->channel != 0) + target_offset += 8; ahc = *((struct ahc_softc **)device->host->hostdata); if (bootverbose) printf("%s: Slave Alloc %d\n", ahc_name(ahc), device->id); - return (0); + targ = ahc->platform_data->targets[target_offset]; + if (targ == NULL) { + targ = ahc_linux_alloc_target(ahc, starget->channel, starget->id); + struct seeprom_config *sc = ahc->seep_config; + if (targ == NULL) + return -ENOMEM; + if (sc) { + unsigned short scsirate; + struct ahc_devinfo devinfo; + struct ahc_initiator_tinfo *tinfo; + struct ahc_tmode_tstate *tstate; + char channel = starget->channel + 'A'; + unsigned int our_id = ahc->our_id; + + if (starget->channel) + our_id = ahc->our_id_b; + + if ((ahc->features & AHC_ULTRA2) != 0) { + scsirate = sc->device_flags[target_offset] & CFXFER; + } else { + scsirate = (sc->device_flags[target_offset] & CFXFER) << 4; + if (sc->device_flags[target_offset] & CFSYNCH) + scsirate |= SOFS; + } + if (sc->device_flags[target_offset] & CFWIDEB) { + scsirate |= WIDEXFER; + spi_max_width(starget) = 1; + } else + spi_max_width(starget) = 0; + spi_min_period(starget) = + ahc_find_period(ahc, scsirate, AHC_SYNCRATE_DT); + tinfo = ahc_fetch_transinfo(ahc, channel, ahc->our_id, + targ->target, &tstate); + ahc_compile_devinfo(&devinfo, our_id, targ->target, + CAM_LUN_WILDCARD, channel, + ROLE_INITIATOR); + ahc_set_syncrate(ahc, &devinfo, NULL, 0, 0, 0, + AHC_TRANS_GOAL, /*paused*/FALSE); + ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, + AHC_TRANS_GOAL, /*paused*/FALSE); + } + + } + dev = targ->devices[device->lun]; + if (dev == NULL) { + dev = ahc_linux_alloc_device(ahc, targ, device->lun); + if (dev == NULL) + return -ENOMEM; + } + + return 0; } static int @@ -666,27 +714,20 @@ ahc_linux_slave_configure(struct scsi_device *device) struct ahc_linux_device *dev; ahc = *((struct ahc_softc **)device->host->hostdata); + if (bootverbose) printf("%s: Slave Configure %d\n", ahc_name(ahc), device->id); - /* - * Since Linux has attached to the device, configure - * it so we don't free and allocate the device - * structure on every command. - */ - dev = ahc_linux_get_device(ahc, device->channel, - device->id, device->lun, - /*alloc*/TRUE); - if (dev != NULL) { - dev->flags &= ~AHC_DEV_UNCONFIGURED; - dev->scsi_device = device; - ahc_linux_device_queue_depth(ahc, dev); - } + + dev = ahc_linux_get_device(ahc, device->channel, device->id, + device->lun); + dev->scsi_device = device; + ahc_linux_device_queue_depth(ahc, dev); /* Initial Domain Validation */ if (!spi_initial_dv(device->sdev_target)) spi_dv_device(device); - return (0); + return 0; } static void @@ -699,22 +740,11 @@ ahc_linux_slave_destroy(struct scsi_device *device) if (bootverbose) printf("%s: Slave Destroy %d\n", ahc_name(ahc), device->id); dev = ahc_linux_get_device(ahc, device->channel, - device->id, device->lun, - /*alloc*/FALSE); - /* - * Filter out "silly" deletions of real devices by only - * deleting devices that have had slave_configure() - * called on them. All other devices that have not - * been configured will automatically be deleted by - * the refcounting process. - */ - if (dev != NULL - && (dev->flags & AHC_DEV_SLAVE_CONFIGURED) != 0) { - dev->flags |= AHC_DEV_UNCONFIGURED; - if (dev->active == 0 - && (dev->flags & AHC_DEV_TIMER_ACTIVE) == 0) - ahc_linux_free_device(ahc, dev); - } + device->id, device->lun); + + BUG_ON(dev->active); + + ahc_linux_free_device(ahc, dev); } #if defined(__i386__) @@ -1361,7 +1391,7 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, dev = ahc_linux_get_device(ahc, devinfo->channel - 'A', devinfo->target, - devinfo->lun, /*alloc*/FALSE); + devinfo->lun); if (dev == NULL) return; was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED); @@ -1793,8 +1823,6 @@ ahc_linux_alloc_device(struct ahc_softc *ahc, if (dev == NULL) return (NULL); memset(dev, 0, sizeof(*dev)); - init_timer(&dev->timer); - dev->flags = AHC_DEV_UNCONFIGURED; dev->lun = lun; dev->target = targ; @@ -1817,7 +1845,7 @@ ahc_linux_alloc_device(struct ahc_softc *ahc, } static void -__ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) +ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) { struct ahc_linux_target *targ; @@ -1829,13 +1857,6 @@ __ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) ahc_linux_free_target(ahc, targ); } -static void -ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) -{ - del_timer_sync(&dev->timer); - __ahc_linux_free_device(ahc, dev); -} - void ahc_send_async(struct ahc_softc *ahc, char channel, u_int target, u_int lun, ac_code code, void *arg) @@ -2008,8 +2029,6 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) } } else if (ahc_get_transaction_status(scb) == CAM_SCSI_STATUS_ERROR) { ahc_linux_handle_scsi_status(ahc, dev, scb); - } else if (ahc_get_transaction_status(scb) == CAM_SEL_TIMEOUT) { - dev->flags |= AHC_DEV_UNCONFIGURED; } if (dev->openings == 1 @@ -2031,11 +2050,6 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) if (dev->active == 0) dev->commands_since_idle_or_otag = 0; - if ((dev->flags & AHC_DEV_UNCONFIGURED) != 0 - && dev->active == 0 - && (dev->flags & AHC_DEV_TIMER_ACTIVE) == 0) - ahc_linux_free_device(ahc, dev); - if ((scb->flags & SCB_RECOVERY_SCB) != 0) { printf("Recovery SCB completes\n"); if (ahc_get_transaction_status(scb) == CAM_BDR_SENT @@ -2174,27 +2188,6 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc, ahc_platform_set_tags(ahc, &devinfo, (dev->flags & AHC_DEV_Q_BASIC) ? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED); - /* FALLTHROUGH */ - } - case SCSI_STATUS_BUSY: - { - /* - * Set a short timer to defer sending commands for - * a bit since Linux will not delay in this case. - */ - if ((dev->flags & AHC_DEV_TIMER_ACTIVE) != 0) { - printf("%s:%c:%d: Device Timer still active during " - "busy processing\n", ahc_name(ahc), - dev->target->channel, dev->target->target); - break; - } - dev->flags |= AHC_DEV_TIMER_ACTIVE; - dev->qfrozen++; - init_timer(&dev->timer); - dev->timer.data = (u_long)dev; - dev->timer.expires = jiffies + (HZ/2); - dev->timer.function = ahc_linux_dev_timed_unfreeze; - add_timer(&dev->timer); break; } } @@ -2326,24 +2319,6 @@ ahc_linux_release_simq(u_long arg) scsi_unblock_requests(ahc->platform_data->host); } -static void -ahc_linux_dev_timed_unfreeze(u_long arg) -{ - struct ahc_linux_device *dev; - struct ahc_softc *ahc; - u_long s; - - dev = (struct ahc_linux_device *)arg; - ahc = dev->target->ahc; - ahc_lock(ahc, &s); - dev->flags &= ~AHC_DEV_TIMER_ACTIVE; - if (dev->qfrozen > 0) - dev->qfrozen--; - if (dev->active == 0) - __ahc_linux_free_device(ahc, dev); - ahc_unlock(ahc, &s); -} - static int ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) { @@ -2384,7 +2359,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) * command, return success. */ dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id, - cmd->device->lun, /*alloc*/FALSE); + cmd->device->lun); if (dev == NULL) { /* diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index e70c1fa47db..30c200d5bcd 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -322,13 +322,10 @@ struct ahc_cmd { */ TAILQ_HEAD(ahc_busyq, ahc_cmd); typedef enum { - AHC_DEV_UNCONFIGURED = 0x01, AHC_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ - AHC_DEV_TIMER_ACTIVE = 0x04, /* Our timer is active */ AHC_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */ AHC_DEV_Q_TAGGED = 0x20, /* Allow full SCSI2 command queueing */ AHC_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */ - AHC_DEV_SLAVE_CONFIGURED = 0x80 /* slave_configure() has been called */ } ahc_linux_dev_flags; struct ahc_linux_target; @@ -373,11 +370,6 @@ struct ahc_linux_device { ahc_linux_dev_flags flags; - /* - * Per device timer. - */ - struct timer_list timer; - /* * The high limit for the tags variable. */ -- cgit v1.2.3 From fb3089dfb58bf07992252b42e77c6f35d45dff5e Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 17 May 2005 21:09:52 -0500 Subject: [SCSI] aic7xxx: add back locking Tampering with the settings has to be done under the host lock ... slave_alloc isn't called under any lock, so this has to be done explicitly. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7xxx_osm.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index c03f2948607..b216de41bff 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -645,7 +645,9 @@ ahc_linux_slave_alloc(struct scsi_device *device) struct ahc_linux_target *targ; struct scsi_target *starget = device->sdev_target; struct ahc_linux_device *dev; - u_int target_offset; + unsigned int target_offset; + unsigned long flags; + int retval = -ENOMEM; target_offset = starget->id; if (starget->channel != 0) @@ -654,12 +656,14 @@ ahc_linux_slave_alloc(struct scsi_device *device) ahc = *((struct ahc_softc **)device->host->hostdata); if (bootverbose) printf("%s: Slave Alloc %d\n", ahc_name(ahc), device->id); + ahc_lock(ahc, &flags); targ = ahc->platform_data->targets[target_offset]; if (targ == NULL) { targ = ahc_linux_alloc_target(ahc, starget->channel, starget->id); struct seeprom_config *sc = ahc->seep_config; if (targ == NULL) - return -ENOMEM; + goto out; + if (sc) { unsigned short scsirate; struct ahc_devinfo devinfo; @@ -701,10 +705,13 @@ ahc_linux_slave_alloc(struct scsi_device *device) if (dev == NULL) { dev = ahc_linux_alloc_device(ahc, targ, device->lun); if (dev == NULL) - return -ENOMEM; + goto out; } + retval = 0; - return 0; + out: + ahc_unlock(ahc, &flags); + return retval; } static int -- cgit v1.2.3 From 2bf2c568c878b9c0bbacac5c3210a6bd81856d21 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Thu, 19 May 2005 21:30:13 -0500 Subject: [SCSI] aic7xxx: fix U160 mode The new period/dt setting routines don't get the coupling of these parameters correct. This means that Domain Validation never gets DT set, and thus the drive gets restricted to U80. Fix this by restoring the couplings in the set routines. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7xxx_osm.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index b216de41bff..f90efa265ba 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -2679,6 +2679,11 @@ static void ahc_linux_set_period(struct scsi_target *starget, int period) if (offset == 0) offset = MAX_OFFSET; + if (period < 9) + period = 9; /* 12.5ns is our minimum */ + if (period == 9) + ppr_options |= MSG_EXT_PPR_DT_REQ; + ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, starget->channel + 'A', ROLE_INITIATOR); @@ -2764,6 +2769,12 @@ static void ahc_linux_set_dt(struct scsi_target *starget, int dt) unsigned long flags; struct ahc_syncrate *syncrate; + if (dt) { + period = 9; /* 12.5ns is the only period valid for DT */ + ppr_options |= MSG_EXT_PPR_DT_REQ; + } else if (period == 9) + period = 10; /* if resetting DT, period must be >= 25ns */ + ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, starget->channel + 'A', ROLE_INITIATOR); syncrate = ahc_find_syncrate(ahc, &period, &ppr_options,AHC_SYNCRATE_DT); -- cgit v1.2.3 From 46f4e1b7d5fa3ddf2486bf69716c404147e38ebf Mon Sep 17 00:00:00 2001 From: Peter Osterlund Date: Fri, 20 May 2005 13:59:06 -0700 Subject: [PATCH] packet driver permission checking fix If you tried to open a packet device first in read-only mode and then a second time in read-write mode, the second open succeeded even though the device was not correctly set up for writing. If you then tried to write data to the device, the writes would fail with I/O errors. This patch prevents that problem by making the second open fail with -EBUSY. Signed-off-by: Peter Osterlund Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/pktcdvd.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index b9a6b7ad64f..bc56770bcc9 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2021,7 +2021,13 @@ static int pkt_open(struct inode *inode, struct file *file) BUG_ON(pd->refcnt < 0); pd->refcnt++; - if (pd->refcnt == 1) { + if (pd->refcnt > 1) { + if ((file->f_mode & FMODE_WRITE) && + !test_bit(PACKET_WRITABLE, &pd->flags)) { + ret = -EBUSY; + goto out_dec; + } + } else { if (pkt_open_dev(pd, file->f_mode & FMODE_WRITE)) { ret = -EIO; goto out_dec; -- cgit v1.2.3 From ba9950c820e556e39cd26581826b5581a64fb641 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Fri, 20 May 2005 13:59:07 -0700 Subject: [PATCH] uml: small fixes left over from rc4 Some changes that I sent in didn't make 2.6.12-rc4 for some reason. This adds them back. We have an x86_64 definition of TOP_ADDR a reimplementation of the x86_64 csum_partial_copy_from_user some syntax fixes in arch/um/kernel/ptrace.c removal of a CFLAGS definition in the x86_64 Makefile some include changes in the x86_64 ptrace.c and user-offsets.h a syntax fix in elf-x86_64.h Also moved an include in the i386 and x86_64 Makefiles to make the symlinks work, and some small fixes from Al Viro. Signed-off-by: Jeff Dike Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/Kconfig_x86_64 | 4 +++ arch/um/include/sysdep-i386/ptrace.h | 2 +- arch/um/include/sysdep-x86_64/checksum.h | 26 ++++++-------- arch/um/include/sysdep-x86_64/ptrace.h | 62 ++++++++++++++------------------ arch/um/kernel/ptrace.c | 6 ++-- arch/um/kernel/uml.lds.S | 2 ++ arch/um/sys-i386/Makefile | 4 +-- arch/um/sys-x86_64/Makefile | 6 ++-- arch/um/sys-x86_64/ksyms.c | 3 +- arch/um/sys-x86_64/ptrace.c | 9 ++--- arch/um/sys-x86_64/syscalls.c | 1 + arch/um/sys-x86_64/user-offsets.c | 8 +++++ include/asm-um/elf-i386.h | 2 +- include/asm-um/elf-x86_64.h | 24 ++++++++++++- 14 files changed, 89 insertions(+), 70 deletions(-) diff --git a/arch/um/Kconfig_x86_64 b/arch/um/Kconfig_x86_64 index fd8d7e8982b..f162f50f0b1 100644 --- a/arch/um/Kconfig_x86_64 +++ b/arch/um/Kconfig_x86_64 @@ -6,6 +6,10 @@ config 64BIT bool default y +config TOP_ADDR + hex + default 0x80000000 + config 3_LEVEL_PGTABLES bool default y diff --git a/arch/um/include/sysdep-i386/ptrace.h b/arch/um/include/sysdep-i386/ptrace.h index 84ec7ff5cf8..6eaeb991998 100644 --- a/arch/um/include/sysdep-i386/ptrace.h +++ b/arch/um/include/sysdep-i386/ptrace.h @@ -31,7 +31,6 @@ extern int sysemu_supported; #ifdef UML_CONFIG_MODE_SKAS #include "skas_ptregs.h" -#include "sysdep/faultinfo.h" #define REGS_IP(r) ((r)[HOST_IP]) #define REGS_SP(r) ((r)[HOST_SP]) @@ -59,6 +58,7 @@ extern int sysemu_supported; #define PTRACE_SYSEMU_SINGLESTEP 32 #endif +#include "sysdep/faultinfo.h" #include "choose-mode.h" union uml_pt_regs { diff --git a/arch/um/include/sysdep-x86_64/checksum.h b/arch/um/include/sysdep-x86_64/checksum.h index 572c6c19be3..ea97005af69 100644 --- a/arch/um/include/sysdep-x86_64/checksum.h +++ b/arch/um/include/sysdep-x86_64/checksum.h @@ -9,8 +9,6 @@ #include "linux/in6.h" #include "asm/uaccess.h" -extern unsigned int csum_partial_copy_from(const unsigned char *src, unsigned char *dst, int len, - int sum, int *err_ptr); extern unsigned csum_partial(const unsigned char *buff, unsigned len, unsigned sum); @@ -31,10 +29,15 @@ unsigned int csum_partial_copy_nocheck(const unsigned char *src, unsigned char * } static __inline__ -unsigned int csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst, - int len, int sum, int *err_ptr) +unsigned int csum_partial_copy_from_user(const unsigned char *src, + unsigned char *dst, int len, int sum, + int *err_ptr) { - return csum_partial_copy_from(src, dst, len, sum, err_ptr); + if(copy_from_user(dst, src, len)){ + *err_ptr = -EFAULT; + return(-1); + } + return csum_partial(dst, len, sum); } /** @@ -137,15 +140,6 @@ static inline unsigned add32_with_carry(unsigned a, unsigned b) return a; } -#endif +extern unsigned short ip_compute_csum(unsigned char * buff, int len); -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +#endif diff --git a/arch/um/include/sysdep-x86_64/ptrace.h b/arch/um/include/sysdep-x86_64/ptrace.h index 348e8fcd513..be8acd5efd9 100644 --- a/arch/um/include/sysdep-x86_64/ptrace.h +++ b/arch/um/include/sysdep-x86_64/ptrace.h @@ -135,6 +135,7 @@ extern int mode_tt; __CHOOSE_MODE(SC_EFLAGS(UPT_SC(r)), REGS_EFLAGS((r)->skas.regs)) #define UPT_SC(r) ((r)->tt.sc) #define UPT_SYSCALL_NR(r) __CHOOSE_MODE((r)->tt.syscall, (r)->skas.syscall) +#define UPT_SYSCALL_RET(r) UPT_RAX(r) extern int user_context(unsigned long sp); @@ -196,32 +197,32 @@ struct syscall_args { #define UPT_SET(regs, reg, val) \ - ({ unsigned long val; \ + ({ unsigned long __upt_val = val; \ switch(reg){ \ - case R8: UPT_R8(regs) = val; break; \ - case R9: UPT_R9(regs) = val; break; \ - case R10: UPT_R10(regs) = val; break; \ - case R11: UPT_R11(regs) = val; break; \ - case R12: UPT_R12(regs) = val; break; \ - case R13: UPT_R13(regs) = val; break; \ - case R14: UPT_R14(regs) = val; break; \ - case R15: UPT_R15(regs) = val; break; \ - case RIP: UPT_IP(regs) = val; break; \ - case RSP: UPT_SP(regs) = val; break; \ - case RAX: UPT_RAX(regs) = val; break; \ - case RBX: UPT_RBX(regs) = val; break; \ - case RCX: UPT_RCX(regs) = val; break; \ - case RDX: UPT_RDX(regs) = val; break; \ - case RSI: UPT_RSI(regs) = val; break; \ - case RDI: UPT_RDI(regs) = val; break; \ - case RBP: UPT_RBP(regs) = val; break; \ - case ORIG_RAX: UPT_ORIG_RAX(regs) = val; break; \ - case CS: UPT_CS(regs) = val; break; \ - case DS: UPT_DS(regs) = val; break; \ - case ES: UPT_ES(regs) = val; break; \ - case FS: UPT_FS(regs) = val; break; \ - case GS: UPT_GS(regs) = val; break; \ - case EFLAGS: UPT_EFLAGS(regs) = val; break; \ + case R8: UPT_R8(regs) = __upt_val; break; \ + case R9: UPT_R9(regs) = __upt_val; break; \ + case R10: UPT_R10(regs) = __upt_val; break; \ + case R11: UPT_R11(regs) = __upt_val; break; \ + case R12: UPT_R12(regs) = __upt_val; break; \ + case R13: UPT_R13(regs) = __upt_val; break; \ + case R14: UPT_R14(regs) = __upt_val; break; \ + case R15: UPT_R15(regs) = __upt_val; break; \ + case RIP: UPT_IP(regs) = __upt_val; break; \ + case RSP: UPT_SP(regs) = __upt_val; break; \ + case RAX: UPT_RAX(regs) = __upt_val; break; \ + case RBX: UPT_RBX(regs) = __upt_val; break; \ + case RCX: UPT_RCX(regs) = __upt_val; break; \ + case RDX: UPT_RDX(regs) = __upt_val; break; \ + case RSI: UPT_RSI(regs) = __upt_val; break; \ + case RDI: UPT_RDI(regs) = __upt_val; break; \ + case RBP: UPT_RBP(regs) = __upt_val; break; \ + case ORIG_RAX: UPT_ORIG_RAX(regs) = __upt_val; break; \ + case CS: UPT_CS(regs) = __upt_val; break; \ + case DS: UPT_DS(regs) = __upt_val; break; \ + case ES: UPT_ES(regs) = __upt_val; break; \ + case FS: UPT_FS(regs) = __upt_val; break; \ + case GS: UPT_GS(regs) = __upt_val; break; \ + case EFLAGS: UPT_EFLAGS(regs) = __upt_val; break; \ default : \ panic("Bad register in UPT_SET : %d\n", reg); \ break; \ @@ -245,14 +246,3 @@ struct syscall_args { CHOOSE_MODE((&(r)->tt.faultinfo), (&(r)->skas.faultinfo)) #endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 2b75d8d9ba7..2925e15324d 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -28,9 +28,9 @@ static inline void set_singlestepping(struct task_struct *child, int on) child->thread.singlestep_syscall = 0; #ifdef SUBARCH_SET_SINGLESTEPPING - SUBARCH_SET_SINGLESTEPPING(child, on) + SUBARCH_SET_SINGLESTEPPING(child, on); #endif - } +} /* * Called by kernel/ptrace.c when detaching.. @@ -83,7 +83,7 @@ long sys_ptrace(long request, long pid, long addr, long data) } #ifdef SUBACH_PTRACE_SPECIAL - SUBARCH_PTRACE_SPECIAL(child,request,addr,data) + SUBARCH_PTRACE_SPECIAL(child,request,addr,data); #endif ret = ptrace_check_attach(child, request == PTRACE_KILL); diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S index 76eadb30918..dd5355500bd 100644 --- a/arch/um/kernel/uml.lds.S +++ b/arch/um/kernel/uml.lds.S @@ -73,6 +73,8 @@ SECTIONS .got : { *(.got.plt) *(.got) } .dynamic : { *(.dynamic) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } /* We want the small data sections together, so single-instruction offsets can access them all, and initialized data all before uninitialized, so we can shorten the on-disk segment size. */ diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index fcd67c3414e..4351e560550 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile @@ -9,11 +9,11 @@ USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o SYMLINKS = bitops.c semaphore.c highmem.c module.c +include arch/um/scripts/Makefile.rules + bitops.c-dir = lib semaphore.c-dir = kernel highmem.c-dir = mm module.c-dir = kernel subdir- := util - -include arch/um/scripts/Makefile.rules diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile index 3d7da911cc8..608466ad6b2 100644 --- a/arch/um/sys-x86_64/Makefile +++ b/arch/um/sys-x86_64/Makefile @@ -14,11 +14,11 @@ obj-$(CONFIG_MODULES) += module.o um_module.o USER_OBJS := ptrace_user.o sigcontext.o -include arch/um/scripts/Makefile.rules - SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c memcpy.S \ semaphore.c thunk.S module.c +include arch/um/scripts/Makefile.rules + bitops.c-dir = lib csum-copy.S-dir = lib csum-partial.c-dir = lib @@ -28,6 +28,4 @@ semaphore.c-dir = kernel thunk.S-dir = lib module.c-dir = kernel -CFLAGS_csum-partial.o := -Dcsum_partial=arch_csum_partial - subdir- := util diff --git a/arch/um/sys-x86_64/ksyms.c b/arch/um/sys-x86_64/ksyms.c index a27f0ee6a4f..85927380820 100644 --- a/arch/um/sys-x86_64/ksyms.c +++ b/arch/um/sys-x86_64/ksyms.c @@ -16,5 +16,4 @@ EXPORT_SYMBOL(__up_wakeup); EXPORT_SYMBOL(__memcpy); /* Networking helper routines. */ -/*EXPORT_SYMBOL(csum_partial_copy_from); -EXPORT_SYMBOL(csum_partial_copy_to);*/ +EXPORT_SYMBOL(ip_compute_csum); diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c index b593bb256f2..74eee5c7c6d 100644 --- a/arch/um/sys-x86_64/ptrace.c +++ b/arch/um/sys-x86_64/ptrace.c @@ -5,10 +5,11 @@ */ #define __FRAME_OFFSETS -#include "asm/ptrace.h" -#include "linux/sched.h" -#include "linux/errno.h" -#include "asm/elf.h" +#include +#include +#include +#include +#include /* XXX x86_64 */ unsigned long not_ss; diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c index dd9914642b8..d4a59657fb9 100644 --- a/arch/um/sys-x86_64/syscalls.c +++ b/arch/um/sys-x86_64/syscalls.c @@ -15,6 +15,7 @@ #include "asm/unistd.h" #include "asm/prctl.h" /* XXX This should get the constants from libc */ #include "choose-mode.h" +#include "kern.h" asmlinkage long sys_uname64(struct new_utsname __user * name) { diff --git a/arch/um/sys-x86_64/user-offsets.c b/arch/um/sys-x86_64/user-offsets.c index 5e14792e483..513d17ceafd 100644 --- a/arch/um/sys-x86_64/user-offsets.c +++ b/arch/um/sys-x86_64/user-offsets.c @@ -3,6 +3,14 @@ #include #define __FRAME_OFFSETS #include +#include +/* For some reason, x86_64 defines u64 and u32 only in , which I + * refuse to include here, even though they're used throughout the headers. + * These are used in asm/user.h, and that include can't be avoided because of + * the sizeof(struct user_regs_struct) below. + */ +typedef __u64 u64; +typedef __u32 u32; #include #define DEFINE(sym, val) \ diff --git a/include/asm-um/elf-i386.h b/include/asm-um/elf-i386.h index b72e23519e0..9bab712dc5c 100644 --- a/include/asm-um/elf-i386.h +++ b/include/asm-um/elf-i386.h @@ -5,7 +5,7 @@ #ifndef __UM_ELF_I386_H #define __UM_ELF_I386_H -#include "user.h" +#include #define R_386_NONE 0 #define R_386_32 1 diff --git a/include/asm-um/elf-x86_64.h b/include/asm-um/elf-x86_64.h index 19309d001aa..8a8246d0393 100644 --- a/include/asm-um/elf-x86_64.h +++ b/include/asm-um/elf-x86_64.h @@ -8,6 +8,27 @@ #include +/* x86-64 relocation types, taken from asm-x86_64/elf.h */ +#define R_X86_64_NONE 0 /* No reloc */ +#define R_X86_64_64 1 /* Direct 64 bit */ +#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ +#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ +#define R_X86_64_PLT32 4 /* 32 bit PLT address */ +#define R_X86_64_COPY 5 /* Copy symbol at runtime */ +#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ +#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ +#define R_X86_64_RELATIVE 8 /* Adjust by program base */ +#define R_X86_64_GOTPCREL 9 /* 32 bit signed pc relative + offset to GOT */ +#define R_X86_64_32 10 /* Direct 32 bit zero extended */ +#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#define R_X86_64_16 12 /* Direct 16 bit zero extended */ +#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ +#define R_X86_64_8 14 /* Direct 8 bit sign extended */ +#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ + +#define R_X86_64_NUM 16 + typedef unsigned long elf_greg_t; #define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t)) @@ -44,7 +65,8 @@ typedef struct { } elf_fpregset_t; } while (0) #ifdef TIF_IA32 /* XXX */ - clear_thread_flag(TIF_IA32); \ +#error XXX, indeed + clear_thread_flag(TIF_IA32); #endif #define USE_ELF_CORE_DUMP -- cgit v1.2.3 From 13479d52c7a61a18900d7f36730b7d3b43723d97 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Fri, 20 May 2005 13:59:08 -0700 Subject: [PATCH] uml: Page fault fixes Any access to a PROT_NONE page should segfault the process. A JVM seems to do this on purpose. Also, Al noticed some bogus code, which is now deleted. Signed-off-by: Jeff Dike Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/trap_kern.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index 5fca2c61eb9..9ae2eff0d8f 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c @@ -57,10 +57,11 @@ int handle_page_fault(unsigned long address, unsigned long ip, *code_out = SEGV_ACCERR; if(is_write && !(vma->vm_flags & VM_WRITE)) goto out; + + if(!(vma->vm_flags & (VM_READ | VM_EXEC))) + goto out; + page = address & PAGE_MASK; - pgd = pgd_offset(mm, page); - pud = pud_offset(pgd, page); - pmd = pmd_offset(pud, page); do { survive: switch (handle_mm_fault(mm, vma, address, is_write)){ -- cgit v1.2.3 From 060e352236ece3325a684c72817fbacdac597574 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Fri, 20 May 2005 13:59:08 -0700 Subject: [PATCH] uml: Delay loop cleanups This patch cleans up the delay implementations a bit, makes the loops unoptimizable, and exports __udelay and __const_udelay. Signed-off-by: Jeff Dike Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/sys-i386/delay.c | 16 ++++++++++++---- arch/um/sys-x86_64/delay.c | 33 +++++++++++++++------------------ 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/arch/um/sys-i386/delay.c b/arch/um/sys-i386/delay.c index e9892eef51c..2c11b9770e8 100644 --- a/arch/um/sys-i386/delay.c +++ b/arch/um/sys-i386/delay.c @@ -1,5 +1,7 @@ -#include "linux/delay.h" -#include "asm/param.h" +#include +#include +#include +#include void __delay(unsigned long time) { @@ -20,13 +22,19 @@ void __udelay(unsigned long usecs) int i, n; n = (loops_per_jiffy * HZ * usecs) / MILLION; - for(i=0;i +#include +#include +#include void __delay(unsigned long loops) { unsigned long i; - for(i = 0; i < loops; i++) ; + for(i = 0; i < loops; i++) + cpu_relax(); } void __udelay(unsigned long usecs) { - int i, n; + unsigned long i, n; n = (loops_per_jiffy * HZ * usecs) / MILLION; - for(i=0;i Date: Fri, 20 May 2005 13:59:09 -0700 Subject: [PATCH] uml: multicast driver cleanup Byte-swapping of the port and IP address passed in to the multicast driver by the user used to happen in different places, which was a bug in itself. The port also was swapped before being printk-ed, which led to a misleading message. This patch moves the port swapping to the same place as the IP address swapping. It also cleans up the error paths of mcast_open. Signed-off-by: Jeff Dike Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/drivers/mcast_kern.c | 4 +--- arch/um/drivers/mcast_user.c | 47 ++++++++++++++------------------------------ 2 files changed, 16 insertions(+), 35 deletions(-) diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c index faf714e87b5..217438cdef3 100644 --- a/arch/um/drivers/mcast_kern.c +++ b/arch/um/drivers/mcast_kern.c @@ -73,7 +73,6 @@ int mcast_setup(char *str, char **mac_out, void *data) struct mcast_init *init = data; char *port_str = NULL, *ttl_str = NULL, *remain; char *last; - int n; *init = ((struct mcast_init) { .addr = "239.192.168.1", @@ -89,13 +88,12 @@ int mcast_setup(char *str, char **mac_out, void *data) } if(port_str != NULL){ - n = simple_strtoul(port_str, &last, 10); + init->port = simple_strtoul(port_str, &last, 10); if((*last != '\0') || (last == port_str)){ printk(KERN_ERR "mcast_setup - Bad port : '%s'\n", port_str); return(0); } - init->port = htons(n); } if(ttl_str != NULL){ diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c index 0fe1d9fa913..7a0d115b29d 100644 --- a/arch/um/drivers/mcast_user.c +++ b/arch/um/drivers/mcast_user.c @@ -38,7 +38,7 @@ static struct sockaddr_in *new_addr(char *addr, unsigned short port) } sin->sin_family = AF_INET; sin->sin_addr.s_addr = in_aton(addr); - sin->sin_port = port; + sin->sin_port = htons(port); return(sin); } @@ -55,28 +55,25 @@ static int mcast_open(void *data) struct mcast_data *pri = data; struct sockaddr_in *sin = pri->mcast_addr; struct ip_mreq mreq; - int fd, yes = 1; + int fd = -EINVAL, yes = 1, err = -EINVAL;; - if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0)) { - fd = -EINVAL; + if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0)) goto out; - } fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0){ printk("mcast_open : data socket failed, errno = %d\n", errno); - fd = -ENOMEM; + fd = -errno; goto out; } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { printk("mcast_open: SO_REUSEADDR failed, errno = %d\n", errno); - os_close_file(fd); - fd = -EINVAL; - goto out; + goto out_close; } /* set ttl according to config */ @@ -84,26 +81,20 @@ static int mcast_open(void *data) sizeof(pri->ttl)) < 0) { printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n", errno); - os_close_file(fd); - fd = -EINVAL; - goto out; + goto out_close; } /* set LOOP, so data does get fed back to local sockets */ if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) { printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n", errno); - os_close_file(fd); - fd = -EINVAL; - goto out; + goto out_close; } /* bind socket to mcast address */ if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) { printk("mcast_open : data bind failed, errno = %d\n", errno); - os_close_file(fd); - fd = -EINVAL; - goto out; + goto out_close; } /* subscribe to the multicast group */ @@ -117,12 +108,15 @@ static int mcast_open(void *data) "interface on the host.\n"); printk("eth0 should be configured in order to use the " "multicast transport.\n"); - os_close_file(fd); - fd = -EINVAL; + goto out_close; } out: - return(fd); + return fd; + + out_close: + os_close_file(fd); + return err; } static void mcast_close(int fd, void *data) @@ -164,14 +158,3 @@ struct net_user_info mcast_user_info = { .delete_address = NULL, .max_packet = MAX_PACKET - ETH_HEADER_OTHER }; - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ -- cgit v1.2.3 From 41a9cf8ebe08ccdd5799c175f9758f14617c0b0a Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Fri, 20 May 2005 13:59:10 -0700 Subject: [PATCH] uml: Export clear_user_* From: Oleg Drokin: This patch is needed to support kernel modules that want to use clear_user() (that is exported symbol on all other architectures). Signed-off-by: Jeff Dike Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/ksyms.c | 1 + arch/um/kernel/tt/ksyms.c | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index 78d69dc74b2..99439fa15ef 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c @@ -57,6 +57,7 @@ EXPORT_SYMBOL(copy_to_user_tt); EXPORT_SYMBOL(strncpy_from_user_skas); EXPORT_SYMBOL(copy_to_user_skas); EXPORT_SYMBOL(copy_from_user_skas); +EXPORT_SYMBOL(clear_user_skas); #endif EXPORT_SYMBOL(uml_strdup); diff --git a/arch/um/kernel/tt/ksyms.c b/arch/um/kernel/tt/ksyms.c index 92ec85d67c7..84a9385a8fe 100644 --- a/arch/um/kernel/tt/ksyms.c +++ b/arch/um/kernel/tt/ksyms.c @@ -12,6 +12,7 @@ EXPORT_SYMBOL(__do_copy_to_user); EXPORT_SYMBOL(__do_strncpy_from_user); EXPORT_SYMBOL(__do_strnlen_user); EXPORT_SYMBOL(__do_clear_user); +EXPORT_SYMBOL(clear_user_tt); EXPORT_SYMBOL(tracing_pid); EXPORT_SYMBOL(honeypot); -- cgit v1.2.3 From 9b67a3c4cd380968bffe8efb681470acda42b441 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Fri, 20 May 2005 13:59:10 -0700 Subject: [PATCH] uml: initrd cleanup The serial UML OS-abstraction layer patch (um/kernel dir). This moves all systemcalls from initrd_user.c file under os-Linux dir and join initrd_user.c and initrd_kern.c files in new file initrd.c Signed-off-by: Gennady Sharapov Signed-off-by: Jeff Dike Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/Makefile | 2 +- arch/um/kernel/initrd.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 arch/um/kernel/initrd.c diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 9736ca27c5f..a8918e80df9 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -14,7 +14,7 @@ obj-y = config.o exec_kern.o exitcode.o \ tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o umid.o \ user_util.o -obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o +obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o obj-$(CONFIG_GPROF) += gprof_syms.o obj-$(CONFIG_GCOV) += gmon_syms.o obj-$(CONFIG_TTY_LOG) += tty_log.o diff --git a/arch/um/kernel/initrd.c b/arch/um/kernel/initrd.c new file mode 100644 index 00000000000..82ecf904b09 --- /dev/null +++ b/arch/um/kernel/initrd.c @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/init.h" +#include "linux/bootmem.h" +#include "linux/initrd.h" +#include "asm/types.h" +#include "user_util.h" +#include "kern_util.h" +#include "initrd.h" +#include "init.h" +#include "os.h" + +/* Changed by uml_initrd_setup, which is a setup */ +static char *initrd __initdata = NULL; + +static int __init read_initrd(void) +{ + void *area; + long long size; + int err; + + if(initrd == NULL) return 0; + err = os_file_size(initrd, &size); + if(err) return 0; + area = alloc_bootmem(size); + if(area == NULL) return 0; + if(load_initrd(initrd, area, size) == -1) return 0; + initrd_start = (unsigned long) area; + initrd_end = initrd_start + size; + return 0; +} + +__uml_postsetup(read_initrd); + +static int __init uml_initrd_setup(char *line, int *add) +{ + initrd = line; + return 0; +} + +__uml_setup("initrd=", uml_initrd_setup, +"initrd=\n" +" This is used to boot UML from an initrd image. The argument is the\n" +" name of the file containing the image.\n\n" +); + +int load_initrd(char *filename, void *buf, int size) +{ + int fd, n; + + fd = os_open_file(filename, of_read(OPENFLAGS()), 0); + if(fd < 0){ + printk("Opening '%s' failed - err = %d\n", filename, -fd); + return(-1); + } + n = os_read_file(fd, buf, size); + if(n != size){ + printk("Read of %d bytes from '%s' failed, err = %d\n", size, + filename, -n); + return(-1); + } + + os_close_file(fd); + return(0); +} +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ -- cgit v1.2.3 From 7b9014c1da380384efe7752db38a0253a74d0238 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Fri, 20 May 2005 13:59:11 -0700 Subject: [PATCH] uml: Remove ubd-mmap support Finally rip out the ubd-mmap code, which turned out to be broken by design. Signed-off-by: Jeff Dike Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/drivers/ubd_kern.c | 296 +-------------------------------------------- arch/um/kernel/trap_kern.c | 29 ----- 2 files changed, 3 insertions(+), 322 deletions(-) diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 9a56ff94308..88f956c34fe 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -55,7 +55,7 @@ #include "mem_kern.h" #include "cow.h" -enum ubd_req { UBD_READ, UBD_WRITE, UBD_MMAP }; +enum ubd_req { UBD_READ, UBD_WRITE }; struct io_thread_req { enum ubd_req op; @@ -68,8 +68,6 @@ struct io_thread_req { unsigned long sector_mask; unsigned long long cow_offset; unsigned long bitmap_words[2]; - int map_fd; - unsigned long long map_offset; int error; }; @@ -122,10 +120,6 @@ static int ubd_ioctl(struct inode * inode, struct file * file, #define MAX_DEV (8) -/* Changed in early boot */ -static int ubd_do_mmap = 0; -#define UBD_MMAP_BLOCK_SIZE PAGE_SIZE - static struct block_device_operations ubd_blops = { .owner = THIS_MODULE, .open = ubd_open, @@ -175,12 +169,6 @@ struct ubd { int no_cow; struct cow cow; struct platform_device pdev; - - int map_writes; - int map_reads; - int nomap_writes; - int nomap_reads; - int write_maps; }; #define DEFAULT_COW { \ @@ -200,11 +188,6 @@ struct ubd { .openflags = OPEN_FLAGS, \ .no_cow = 0, \ .cow = DEFAULT_COW, \ - .map_writes = 0, \ - .map_reads = 0, \ - .nomap_writes = 0, \ - .nomap_reads = 0, \ - .write_maps = 0, \ } struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD }; @@ -314,13 +297,6 @@ static int ubd_setup_common(char *str, int *index_out) int major; str++; - if(!strcmp(str, "mmap")){ - CHOOSE_MODE(printk("mmap not supported by the ubd " - "driver in tt mode\n"), - ubd_do_mmap = 1); - return(0); - } - if(!strcmp(str, "sync")){ global_openflags = of_sync(global_openflags); return(0); @@ -524,7 +500,7 @@ static void ubd_handler(void) { struct io_thread_req req; struct request *rq = elv_next_request(ubd_queue); - int n, err; + int n; do_ubd = NULL; intr_count++; @@ -538,19 +514,6 @@ static void ubd_handler(void) return; } - if((req.op != UBD_MMAP) && - ((req.offset != ((__u64) (rq->sector)) << 9) || - (req.length != (rq->current_nr_sectors) << 9))) - panic("I/O op mismatch"); - - if(req.map_fd != -1){ - err = physmem_subst_mapping(req.buffer, req.map_fd, - req.map_offset, 1); - if(err) - printk("ubd_handler - physmem_subst_mapping failed, " - "err = %d\n", -err); - } - ubd_finish(rq, req.error); reactivate_fd(thread_fd, UBD_IRQ); do_ubd_request(ubd_queue); @@ -583,14 +546,10 @@ static int ubd_file_size(struct ubd *dev, __u64 *size_out) static void ubd_close(struct ubd *dev) { - if(ubd_do_mmap) - physmem_forget_descriptor(dev->fd); os_close_file(dev->fd); if(dev->cow.file == NULL) return; - if(ubd_do_mmap) - physmem_forget_descriptor(dev->cow.fd); os_close_file(dev->cow.fd); vfree(dev->cow.bitmap); dev->cow.bitmap = NULL; @@ -1010,94 +969,13 @@ static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, req->bitmap_words, bitmap_len); } -static int mmap_fd(struct request *req, struct ubd *dev, __u64 offset) -{ - __u64 sector; - unsigned char *bitmap; - int bit, i; - - /* mmap must have been requested on the command line */ - if(!ubd_do_mmap) - return(-1); - - /* The buffer must be page aligned */ - if(((unsigned long) req->buffer % UBD_MMAP_BLOCK_SIZE) != 0) - return(-1); - - /* The request must be a page long */ - if((req->current_nr_sectors << 9) != PAGE_SIZE) - return(-1); - - if(dev->cow.file == NULL) - return(dev->fd); - - sector = offset >> 9; - bitmap = (unsigned char *) dev->cow.bitmap; - bit = ubd_test_bit(sector, bitmap); - - for(i = 1; i < req->current_nr_sectors; i++){ - if(ubd_test_bit(sector + i, bitmap) != bit) - return(-1); - } - - if(bit || (rq_data_dir(req) == WRITE)) - offset += dev->cow.data_offset; - - /* The data on disk must be page aligned */ - if((offset % UBD_MMAP_BLOCK_SIZE) != 0) - return(-1); - - return(bit ? dev->fd : dev->cow.fd); -} - -static int prepare_mmap_request(struct ubd *dev, int fd, __u64 offset, - struct request *req, - struct io_thread_req *io_req) -{ - int err; - - if(rq_data_dir(req) == WRITE){ - /* Writes are almost no-ops since the new data is already in the - * host page cache - */ - dev->map_writes++; - if(dev->cow.file != NULL) - cowify_bitmap(io_req->offset, io_req->length, - &io_req->sector_mask, &io_req->cow_offset, - dev->cow.bitmap, dev->cow.bitmap_offset, - io_req->bitmap_words, - dev->cow.bitmap_len); - } - else { - int w; - - if((dev->cow.file != NULL) && (fd == dev->cow.fd)) - w = 0; - else w = dev->openflags.w; - - if((dev->cow.file != NULL) && (fd == dev->fd)) - offset += dev->cow.data_offset; - - err = physmem_subst_mapping(req->buffer, fd, offset, w); - if(err){ - printk("physmem_subst_mapping failed, err = %d\n", - -err); - return(1); - } - dev->map_reads++; - } - io_req->op = UBD_MMAP; - io_req->buffer = req->buffer; - return(0); -} - /* Called with ubd_io_lock held */ static int prepare_request(struct request *req, struct io_thread_req *io_req) { struct gendisk *disk = req->rq_disk; struct ubd *dev = disk->private_data; __u64 offset; - int len, fd; + int len; if(req->rq_status == RQ_INACTIVE) return(1); @@ -1114,34 +992,12 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req) io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd; io_req->fds[1] = dev->fd; - io_req->map_fd = -1; io_req->cow_offset = -1; io_req->offset = offset; io_req->length = len; io_req->error = 0; io_req->sector_mask = 0; - fd = mmap_fd(req, dev, io_req->offset); - if(fd > 0){ - /* If mmapping is otherwise OK, but the first access to the - * page is a write, then it's not mapped in yet. So we have - * to write the data to disk first, then we can map the disk - * page in and continue normally from there. - */ - if((rq_data_dir(req) == WRITE) && !is_remapped(req->buffer)){ - io_req->map_fd = dev->fd; - io_req->map_offset = io_req->offset + - dev->cow.data_offset; - dev->write_maps++; - } - else return(prepare_mmap_request(dev, fd, io_req->offset, req, - io_req)); - } - - if(rq_data_dir(req) == READ) - dev->nomap_reads++; - else dev->nomap_writes++; - io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE; io_req->offsets[0] = 0; io_req->offsets[1] = dev->cow.data_offset; @@ -1229,143 +1085,6 @@ static int ubd_ioctl(struct inode * inode, struct file * file, return(-EINVAL); } -static int ubd_check_remapped(int fd, unsigned long address, int is_write, - __u64 offset) -{ - __u64 bitmap_offset; - unsigned long new_bitmap[2]; - int i, err, n; - - /* If it's not a write access, we can't do anything about it */ - if(!is_write) - return(0); - - /* We have a write */ - for(i = 0; i < sizeof(ubd_dev) / sizeof(ubd_dev[0]); i++){ - struct ubd *dev = &ubd_dev[i]; - - if((dev->fd != fd) && (dev->cow.fd != fd)) - continue; - - /* It's a write to a ubd device */ - - /* This should be impossible now */ - if(!dev->openflags.w){ - /* It's a write access on a read-only device - probably - * shouldn't happen. If the kernel is trying to change - * something with no intention of writing it back out, - * then this message will clue us in that this needs - * fixing - */ - printk("Write access to mapped page from readonly ubd " - "device %d\n", i); - return(0); - } - - /* It's a write to a writeable ubd device - it must be COWed - * because, otherwise, the page would have been mapped in - * writeable - */ - - if(!dev->cow.file) - panic("Write fault on writeable non-COW ubd device %d", - i); - - /* It should also be an access to the backing file since the - * COW pages should be mapped in read-write - */ - - if(fd == dev->fd) - panic("Write fault on a backing page of ubd " - "device %d\n", i); - - /* So, we do the write, copying the backing data to the COW - * file... - */ - - err = os_seek_file(dev->fd, offset + dev->cow.data_offset); - if(err < 0) - panic("Couldn't seek to %lld in COW file of ubd " - "device %d, err = %d", - offset + dev->cow.data_offset, i, -err); - - n = os_write_file(dev->fd, (void *) address, PAGE_SIZE); - if(n != PAGE_SIZE) - panic("Couldn't copy data to COW file of ubd " - "device %d, err = %d", i, -n); - - /* ... updating the COW bitmap... */ - - cowify_bitmap(offset, PAGE_SIZE, NULL, &bitmap_offset, - dev->cow.bitmap, dev->cow.bitmap_offset, - new_bitmap, dev->cow.bitmap_len); - - err = os_seek_file(dev->fd, bitmap_offset); - if(err < 0) - panic("Couldn't seek to %lld in COW file of ubd " - "device %d, err = %d", bitmap_offset, i, -err); - - n = os_write_file(dev->fd, new_bitmap, sizeof(new_bitmap)); - if(n != sizeof(new_bitmap)) - panic("Couldn't update bitmap of ubd device %d, " - "err = %d", i, -n); - - /* Maybe we can map the COW page in, and maybe we can't. If - * it is a pre-V3 COW file, we can't, since the alignment will - * be wrong. If it is a V3 or later COW file which has been - * moved to a system with a larger page size, then maybe we - * can't, depending on the exact location of the page. - */ - - offset += dev->cow.data_offset; - - /* Remove the remapping, putting the original anonymous page - * back. If the COW file can be mapped in, that is done. - * Otherwise, the COW page is read in. - */ - - if(!physmem_remove_mapping((void *) address)) - panic("Address 0x%lx not remapped by ubd device %d", - address, i); - if((offset % UBD_MMAP_BLOCK_SIZE) == 0) - physmem_subst_mapping((void *) address, dev->fd, - offset, 1); - else { - err = os_seek_file(dev->fd, offset); - if(err < 0) - panic("Couldn't seek to %lld in COW file of " - "ubd device %d, err = %d", offset, i, - -err); - - n = os_read_file(dev->fd, (void *) address, PAGE_SIZE); - if(n != PAGE_SIZE) - panic("Failed to read page from offset %llx of " - "COW file of ubd device %d, err = %d", - offset, i, -n); - } - - return(1); - } - - /* It's not a write on a ubd device */ - return(0); -} - -static struct remapper ubd_remapper = { - .list = LIST_HEAD_INIT(ubd_remapper.list), - .proc = ubd_check_remapped, -}; - -static int ubd_remapper_setup(void) -{ - if(ubd_do_mmap) - register_remapper(&ubd_remapper); - - return(0); -} - -__initcall(ubd_remapper_setup); - static int same_backing_files(char *from_cmdline, char *from_cow, char *cow) { struct uml_stat buf1, buf2; @@ -1568,15 +1287,6 @@ void do_io(struct io_thread_req *req) int err; __u64 off; - if(req->op == UBD_MMAP){ - /* Touch the page to force the host to do any necessary IO to - * get it into memory - */ - n = *((volatile int *) req->buffer); - req->error = update_bitmap(req); - return; - } - nsectors = req->length / req->sectorsize; start = 0; do { diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index 9ae2eff0d8f..1de22d8a313 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c @@ -107,33 +107,6 @@ out_of_memory: goto out; } -LIST_HEAD(physmem_remappers); - -void register_remapper(struct remapper *info) -{ - list_add(&info->list, &physmem_remappers); -} - -static int check_remapped_addr(unsigned long address, int is_write) -{ - struct remapper *remapper; - struct list_head *ele; - __u64 offset; - int fd; - - fd = phys_mapping(__pa(address), &offset); - if(fd == -1) - return(0); - - list_for_each(ele, &physmem_remappers){ - remapper = list_entry(ele, struct remapper, list); - if((*remapper->proc)(fd, address, is_write, offset)) - return(1); - } - - return(0); -} - /* * We give a *copy* of the faultinfo in the regs to segv. * This must be done, since nesting SEGVs could overwrite @@ -152,8 +125,6 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) flush_tlb_kernel_vm(); return(0); } - else if(check_remapped_addr(address & PAGE_MASK, is_write)) - return(0); else if(current->mm == NULL) panic("Segfault with no mm"); err = handle_page_fault(address, ip, is_write, is_user, &si.si_code); -- cgit v1.2.3 From 12f49643bc44c428919b210148a930496827dd26 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Fri, 20 May 2005 13:59:12 -0700 Subject: [PATCH] uml: fixrange_init 3-level page table support From: Al Viro - add three-level page table support to fixrange_init. Signed-off-by: Jeff Dike Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/mem.c | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index f156661781c..c22825f13e4 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -100,12 +100,37 @@ void mem_init(void) #endif } +/* + * Create a page table and place a pointer to it in a middle page + * directory entry. + */ +static void __init one_page_table_init(pmd_t *pmd) +{ + if (pmd_none(*pmd)) { + pte_t *pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + set_pmd(pmd, __pmd(_KERNPG_TABLE + + (unsigned long) __pa(pte))); + if (pte != pte_offset_kernel(pmd, 0)) + BUG(); + } +} + +static void __init one_md_table_init(pud_t *pud) +{ +#ifdef CONFIG_3_LEVEL_PGTABLES + pmd_t *pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); + set_pud(pud, __pud(_KERNPG_TABLE + (unsigned long) __pa(pmd_table))); + if (pmd_table != pmd_offset(pud, 0)) + BUG(); +#endif +} + static void __init fixrange_init(unsigned long start, unsigned long end, pgd_t *pgd_base) { pgd_t *pgd; + pud_t *pud; pmd_t *pmd; - pte_t *pte; int i, j; unsigned long vaddr; @@ -115,15 +140,12 @@ static void __init fixrange_init(unsigned long start, unsigned long end, pgd = pgd_base + i; for ( ; (i < PTRS_PER_PGD) && (vaddr < end); pgd++, i++) { - pmd = (pmd_t *)pgd; + pud = pud_offset(pgd, vaddr); + if (pud_none(*pud)) + one_md_table_init(pud); + pmd = pmd_offset(pud, vaddr); for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) { - if (pmd_none(*pmd)) { - pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pmd(pmd, __pmd(_KERNPG_TABLE + - (unsigned long) __pa(pte))); - if (pte != pte_offset_kernel(pmd, 0)) - BUG(); - } + one_page_table_init(pmd); vaddr += PMD_SIZE; } j = 0; -- cgit v1.2.3 From 84ddaa8c86fc12ee1c3509be5ff3464821535c17 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Fri, 20 May 2005 13:59:12 -0700 Subject: [PATCH] uml: Change printf to printk in console driver From: Al Viro - we have error messages with KERN_ERR in them, so they should be printk-ed rather than printf-ed. Signed-off-by: Jeff Dike Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/drivers/chan_kern.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 0150038af79..14a12d6b3df 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -20,9 +20,17 @@ #include "os.h" #ifdef CONFIG_NOCONFIG_CHAN + +/* The printk's here are wrong because we are complaining that there is no + * output device, but printk is printing to that output device. The user will + * never see the error. printf would be better, except it can't run on a + * kernel stack because it will overflow it. + * Use printk for now since that will avoid crashing. + */ + static void *not_configged_init(char *str, int device, struct chan_opts *opts) { - printf(KERN_ERR "Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); return(NULL); } @@ -30,27 +38,27 @@ static void *not_configged_init(char *str, int device, struct chan_opts *opts) static int not_configged_open(int input, int output, int primary, void *data, char **dev_out) { - printf(KERN_ERR "Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); return(-ENODEV); } static void not_configged_close(int fd, void *data) { - printf(KERN_ERR "Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); } static int not_configged_read(int fd, char *c_out, void *data) { - printf(KERN_ERR "Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); return(-EIO); } static int not_configged_write(int fd, const char *buf, int len, void *data) { - printf(KERN_ERR "Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); return(-EIO); } @@ -58,7 +66,7 @@ static int not_configged_write(int fd, const char *buf, int len, void *data) static int not_configged_console_write(int fd, const char *buf, int len, void *data) { - printf(KERN_ERR "Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); return(-EIO); } @@ -66,7 +74,7 @@ static int not_configged_console_write(int fd, const char *buf, int len, static int not_configged_window_size(int fd, void *data, unsigned short *rows, unsigned short *cols) { - printf(KERN_ERR "Using a channel type which is configured out of " + printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); return(-ENODEV); } -- cgit v1.2.3 From 7f8cd80fb261177244c1479cfcad1387dbf3cd4b Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 20 May 2005 13:59:13 -0700 Subject: [PATCH] ppc32: Fix platform device initialization of 8250 serial ports Initialization of 8250 serial ports that are platform devices require that at empty entry exists in the array of plat_serial8250_port. With out an empty entry we can get some pretty random behavior. Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/syslib/mpc83xx_devices.c | 1 + arch/ppc/syslib/mpc85xx_devices.c | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/ppc/syslib/mpc83xx_devices.c b/arch/ppc/syslib/mpc83xx_devices.c index 5c1a919eaab..75c8e9834ae 100644 --- a/arch/ppc/syslib/mpc83xx_devices.c +++ b/arch/ppc/syslib/mpc83xx_devices.c @@ -61,6 +61,7 @@ static struct plat_serial8250_port serial_platform_data[] = { .iotype = UPIO_MEM, .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, }, + { }, }; struct platform_device ppc_sys_platform_devices[] = { diff --git a/arch/ppc/syslib/mpc85xx_devices.c b/arch/ppc/syslib/mpc85xx_devices.c index a231795ee26..1e658ef57e7 100644 --- a/arch/ppc/syslib/mpc85xx_devices.c +++ b/arch/ppc/syslib/mpc85xx_devices.c @@ -61,6 +61,7 @@ static struct plat_serial8250_port serial_platform_data[] = { .iotype = UPIO_MEM, .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ, }, + { }, }; struct platform_device ppc_sys_platform_devices[] = { -- cgit v1.2.3 From b2665f92ae67a2d086537979d317a6f3a5697c63 Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Fri, 20 May 2005 13:59:14 -0700 Subject: [PATCH] ppc32: fix CONFIG_TASK_SIZE handling on 44x This patch fixed CONFIG_TASK_SIZE handling on 44x. Currently head_44x.S hardcodes 0x80000000, which breaks if user chooses to change TASK_SIZE (e.g. for 3G user-space). Tested on Ocotea in 3G/1G configuration. Signed-off-by: Eugene Surovegin Signed-off-by: Matt Porter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/kernel/head_44x.S | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/ppc/kernel/head_44x.S b/arch/ppc/kernel/head_44x.S index 9b6a8e51365..6c7ae605246 100644 --- a/arch/ppc/kernel/head_44x.S +++ b/arch/ppc/kernel/head_44x.S @@ -330,8 +330,9 @@ interrupt_base: /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - andis. r11, r10, 0x8000 - beq 3f + lis r11, TASK_SIZE@h + cmplw r10, r11 + blt+ 3f lis r11, swapper_pg_dir@h ori r11, r11, swapper_pg_dir@l @@ -464,8 +465,9 @@ interrupt_base: /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - andis. r11, r10, 0x8000 - beq 3f + lis r11, TASK_SIZE@h + cmplw r10, r11 + blt+ 3f lis r11, swapper_pg_dir@h ori r11, r11, swapper_pg_dir@l @@ -533,8 +535,9 @@ interrupt_base: /* If we are faulting a kernel address, we have to use the * kernel page tables. */ - andis. r11, r10, 0x8000 - beq 3f + lis r11, TASK_SIZE@h + cmplw r10, r11 + blt+ 3f lis r11, swapper_pg_dir@h ori r11, r11, swapper_pg_dir@l -- cgit v1.2.3 From b39c4fab259b216148e705344a892c96efe1946d Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Fri, 20 May 2005 13:59:15 -0700 Subject: [PATCH] cpusets+hotplug+preepmt broken This patch removes the entwining of cpusets and hotplug code in the "No more Mr. Nice Guy" case of sched.c move_task_off_dead_cpu(). Since the hotplug code is holding a spinlock at this point, we cannot take the cpuset semaphore, cpuset_sem, as would seem to be required either to update the tasks cpuset, or to scan up the nested cpuset chain, looking for the nearest cpuset ancestor that still has some CPUs that are online. So we just punt and blast the tasks cpus_allowed with all bits allowed. This reverts these lines of code to what they were before the cpuset patch. And it updates the cpuset Doc file, to match. The one known alternative to this that seems to work came from Dinakar Guniguntala, and required the hotplug code to take the cpuset_sem semaphore much earlier in its processing. So far as we know, the increased locking entanglement between cpusets and hot plug of this alternative approach is not worth doing in this case. Signed-off-by: Paul Jackson Acked-by: Nathan Lynch Acked-by: Dinakar Guniguntala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/cpusets.txt | 3 +-- kernel/sched.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Documentation/cpusets.txt b/Documentation/cpusets.txt index 1ad26d2c20a..2f8f24eaefd 100644 --- a/Documentation/cpusets.txt +++ b/Documentation/cpusets.txt @@ -252,8 +252,7 @@ in a tasks processor placement. There is an exception to the above. If hotplug funtionality is used to remove all the CPUs that are currently assigned to a cpuset, then the kernel will automatically update the cpus_allowed of all -tasks attached to CPUs in that cpuset with the online CPUs of the -nearest parent cpuset that still has some CPUs online. When memory +tasks attached to CPUs in that cpuset to allow all CPUs. When memory hotplug functionality for removing Memory Nodes is available, a similar exception is expected to apply there as well. In general, the kernel prefers to violate cpuset placement, over starving a task diff --git a/kernel/sched.c b/kernel/sched.c index 0dc3158667a..66b2ed78482 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4243,7 +4243,7 @@ static void move_task_off_dead_cpu(int dead_cpu, struct task_struct *tsk) /* No more Mr. Nice Guy. */ if (dest_cpu == NR_CPUS) { - tsk->cpus_allowed = cpuset_cpus_allowed(tsk); + cpus_setall(tsk->cpus_allowed); dest_cpu = any_online_cpu(tsk->cpus_allowed); /* -- cgit v1.2.3 From b41e29398a873945d02e0009ce7e57608fdb4042 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Fri, 20 May 2005 14:27:55 -0700 Subject: [PATCH] x86_64: 386/x86-64 Further AMD dual core fixes - Remove duplicated ifdef - Make core_id match what Intel uses - Initialize phys_proc_id correctly for non DC case - Handle non power of two core numbers. Fixes for both i386 and x86-64 Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/cpu/amd.c | 9 ++++++--- arch/i386/kernel/cpu/common.c | 5 +---- arch/x86_64/kernel/setup.c | 25 ++++++++++++------------- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c index fa34a06c0d7..73aeaf5a9d4 100644 --- a/arch/i386/kernel/cpu/amd.c +++ b/arch/i386/kernel/cpu/amd.c @@ -195,7 +195,7 @@ static void __init init_amd(struct cpuinfo_x86 *c) c->x86_num_cores = 1; } -#ifdef CONFIG_X86_SMP +#ifdef CONFIG_X86_HT /* * On a AMD dual core setup the lower bits of the APIC id * distingush the cores. Assumes number of cores is a power @@ -203,8 +203,11 @@ static void __init init_amd(struct cpuinfo_x86 *c) */ if (c->x86_num_cores > 1) { int cpu = smp_processor_id(); - /* Fix up the APIC ID following AMD specifications. */ - cpu_core_id[cpu] >>= hweight32(c->x86_num_cores - 1); + unsigned bits = 0; + while ((1 << bits) < c->x86_num_cores) + bits++; + cpu_core_id[cpu] = phys_proc_id[cpu] & ((1<>= bits; printk(KERN_INFO "CPU %d(%d) -> Core %d\n", cpu, c->x86_num_cores, cpu_core_id[cpu]); } diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index 11e6e6f23fa..d199e525680 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -244,11 +244,8 @@ static void __init early_cpu_detect(void) early_intel_workaround(c); -#ifdef CONFIG_SMP #ifdef CONFIG_X86_HT - phys_proc_id[smp_processor_id()] = -#endif - cpu_core_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff; + phys_proc_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff; #endif } diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index b9fd0252c27..99f038ede23 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -719,7 +719,6 @@ static void __init display_cacheinfo(struct cpuinfo_x86 *c) } } -#ifdef CONFIG_SMP /* * On a AMD dual core setup the lower bits of the APIC id distingush the cores. * Assumes number of cores is a power of two. @@ -729,16 +728,24 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c) #ifdef CONFIG_SMP int cpu = smp_processor_id(); int node = 0; + unsigned bits; if (c->x86_num_cores == 1) return; - /* Fix up the APIC ID following the AMD specification. */ - cpu_core_id[cpu] >>= hweight32(c->x86_num_cores - 1); + + bits = 0; + while ((1 << bits) < c->x86_num_cores) + bits++; + + /* Low order bits define the core id (index of core in socket) */ + cpu_core_id[cpu] = phys_proc_id[cpu] & ((1 << bits)-1); + /* Convert the APIC ID into the socket ID */ + phys_proc_id[cpu] >>= bits; #ifdef CONFIG_NUMA /* When an ACPI SRAT table is available use the mappings from SRAT instead. */ if (acpi_numa <= 0) { - node = cpu_core_id[cpu]; + node = phys_proc_id[cpu]; if (!node_online(node)) node = first_node(node_online_map); cpu_to_node[cpu] = node; @@ -746,18 +753,11 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c) node = cpu_to_node[cpu]; } #endif - /* For now: - better than BAD_APIC_ID at least*/ - phys_proc_id[cpu] = cpu_core_id[cpu]; printk(KERN_INFO "CPU %d(%d) -> Node %d -> Core %d\n", cpu, c->x86_num_cores, node, cpu_core_id[cpu]); #endif } -#else -static void __init amd_detect_cmp(struct cpuinfo_x86 *c) -{ -} -#endif static int __init init_amd(struct cpuinfo_x86 *c) { @@ -963,8 +963,7 @@ void __init early_identify_cpu(struct cpuinfo_x86 *c) } #ifdef CONFIG_SMP - phys_proc_id[smp_processor_id()] = - cpu_core_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff; + phys_proc_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff; #endif } -- cgit v1.2.3 From c4d1fcf3a2ea89b6d6221fa8b4588c77aff50995 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Fri, 20 May 2005 14:27:56 -0700 Subject: [PATCH] x86_64: Don't allow accesses below register frame in ptrace There was a "off by one quad word" error in there. I don't think it is exploitable because it will only store into a unused area, but better to plug it. Found and fixed by John Blackwood Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/ptrace.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c index 60dc9b98951..525f6a128a2 100644 --- a/arch/x86_64/kernel/ptrace.c +++ b/arch/x86_64/kernel/ptrace.c @@ -380,7 +380,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data break; switch (addr) { - case 0 ... sizeof(struct user_regs_struct): + case 0 ... sizeof(struct user_regs_struct) - sizeof(long): tmp = getreg(child, addr); break; case offsetof(struct user, u_debugreg[0]): @@ -425,7 +425,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data break; switch (addr) { - case 0 ... sizeof(struct user_regs_struct): + case 0 ... sizeof(struct user_regs_struct) - sizeof(long): ret = putreg(child, addr, data); break; /* Disallows to set a breakpoint into the vsyscall */ -- cgit v1.2.3 From 7856dfeb23c16ef3d8dac8871b4d5b93c70b59b9 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Fri, 20 May 2005 14:27:57 -0700 Subject: [PATCH] x86_64: Fixed guard page handling again in iounmap Caused oopses again. Also fix potential mismatch in checking if change_page_attr was needed. To do it without races I needed to change mm/vmalloc.c to export a __remove_vm_area that does not take vmlist lock. Noticed by Terence Ripperda and based on a patch of his. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/mm/ioremap.c | 29 ++++++++--------------------- include/linux/vmalloc.h | 1 + mm/vmalloc.c | 33 ++++++++++++++++++++------------- 3 files changed, 29 insertions(+), 34 deletions(-) diff --git a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c index c6fb0cb6999..58aac23760e 100644 --- a/arch/x86_64/mm/ioremap.c +++ b/arch/x86_64/mm/ioremap.c @@ -133,7 +133,7 @@ ioremap_change_attr(unsigned long phys_addr, unsigned long size, unsigned long flags) { int err = 0; - if (flags && phys_addr + size - 1 < (end_pfn_map << PAGE_SHIFT)) { + if (phys_addr + size - 1 < (end_pfn_map << PAGE_SHIFT)) { unsigned long npages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; unsigned long vaddr = (unsigned long) __va(phys_addr); @@ -214,7 +214,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l remove_vm_area((void *)(PAGE_MASK & (unsigned long) addr)); return NULL; } - if (ioremap_change_attr(phys_addr, size, flags) < 0) { + if (flags && ioremap_change_attr(phys_addr, size, flags) < 0) { area->flags &= 0xffffff; vunmap(addr); return NULL; @@ -251,7 +251,7 @@ void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size) void iounmap(volatile void __iomem *addr) { - struct vm_struct *p, **pprev; + struct vm_struct *p; if (addr <= high_memory) return; @@ -260,24 +260,11 @@ void iounmap(volatile void __iomem *addr) return; write_lock(&vmlist_lock); - for (p = vmlist, pprev = &vmlist; p != NULL; pprev = &p->next, p = *pprev) - if (p->addr == (void *)(PAGE_MASK & (unsigned long)addr)) - break; - if (!p) { - printk("__iounmap: bad address %p\n", addr); - goto out_unlock; - } - *pprev = p->next; - unmap_vm_area(p); - if ((p->flags >> 20) && - p->phys_addr + p->size - 1 < virt_to_phys(high_memory)) { - /* p->size includes the guard page, but cpa doesn't like that */ - change_page_attr_addr((unsigned long)__va(p->phys_addr), - p->size >> PAGE_SHIFT, - PAGE_KERNEL); - global_flush_tlb(); - } -out_unlock: + p = __remove_vm_area((void *)((unsigned long)addr & PAGE_MASK)); + if (!p) + printk("iounmap: bad address %p\n", addr); + else if (p->flags >> 20) + ioremap_change_attr(p->phys_addr, p->size, 0); write_unlock(&vmlist_lock); kfree(p); } diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index 3a358c89518..6409d9cf596 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -41,6 +41,7 @@ extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags); extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, unsigned long start, unsigned long end); extern struct vm_struct *remove_vm_area(void *addr); +extern struct vm_struct *__remove_vm_area(void *addr); extern int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages); extern void unmap_vm_area(struct vm_struct *area); diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 2bd83e5c2bb..8ff16a1eee6 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -248,31 +248,20 @@ struct vm_struct *get_vm_area(unsigned long size, unsigned long flags) return __get_vm_area(size, flags, VMALLOC_START, VMALLOC_END); } -/** - * remove_vm_area - find and remove a contingous kernel virtual area - * - * @addr: base address - * - * Search for the kernel VM area starting at @addr, and remove it. - * This function returns the found VM area, but using it is NOT safe - * on SMP machines. - */ -struct vm_struct *remove_vm_area(void *addr) +/* Caller must hold vmlist_lock */ +struct vm_struct *__remove_vm_area(void *addr) { struct vm_struct **p, *tmp; - write_lock(&vmlist_lock); for (p = &vmlist ; (tmp = *p) != NULL ;p = &tmp->next) { if (tmp->addr == addr) goto found; } - write_unlock(&vmlist_lock); return NULL; found: unmap_vm_area(tmp); *p = tmp->next; - write_unlock(&vmlist_lock); /* * Remove the guard page. @@ -281,6 +270,24 @@ found: return tmp; } +/** + * remove_vm_area - find and remove a contingous kernel virtual area + * + * @addr: base address + * + * Search for the kernel VM area starting at @addr, and remove it. + * This function returns the found VM area, but using it is NOT safe + * on SMP machines, except for its size or flags. + */ +struct vm_struct *remove_vm_area(void *addr) +{ + struct vm_struct *v; + write_lock(&vmlist_lock); + v = __remove_vm_area(addr); + write_unlock(&vmlist_lock); + return v; +} + void __vunmap(void *addr, int deallocate_pages) { struct vm_struct *area; -- cgit v1.2.3 From 4057923614e2868a865aa6c6e3bc53542c818d4d Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Fri, 20 May 2005 14:27:57 -0700 Subject: [PATCH] i386: Fix race in iounmap We need to hold the vmlist_lock while doing change_page_attr, otherwise we could reset someone else's mapping. Requires previous patch to add __remove_vm_area Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/mm/ioremap.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c index db06f739991..ab542792b27 100644 --- a/arch/i386/mm/ioremap.c +++ b/arch/i386/mm/ioremap.c @@ -238,19 +238,21 @@ void iounmap(volatile void __iomem *addr) addr < phys_to_virt(ISA_END_ADDRESS)) return; - p = remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr)); + write_lock(&vmlist_lock); + p = __remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr)); if (!p) { - printk("__iounmap: bad address %p\n", addr); - return; + printk("iounmap: bad address %p\n", addr); + goto out_unlock; } if ((p->flags >> 20) && p->phys_addr < virt_to_phys(high_memory) - 1) { - /* p->size includes the guard page, but cpa doesn't like that */ change_page_attr(virt_to_page(__va(p->phys_addr)), p->size >> PAGE_SHIFT, PAGE_KERNEL); global_flush_tlb(); } +out_unlock: + write_unlock(&vmlist_lock); kfree(p); } -- cgit v1.2.3 From 607a16858397829806c5a4db999ce6daf327f98c Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Fri, 20 May 2005 14:27:58 -0700 Subject: [PATCH] x86_64: Fix 32bit system call restart The test case at http://cvs.sourceforge.net/viewcvs.py/posixtest/posixtestsuite/conforman ce/interfaces/clock_nanosleep/1-5.c fails if it runs as a 32bit process on x86_86 machines. The root cause is the sub 32bit process fails to restart the syscall after it is interrupted by a signal. The syscall number of sys_restart_syscall in table sys_call_table is __NR_restart_syscall (219) while it's __NR_ia32_restart_syscall (0) in ia32_sys_call_table. When regs->rax==(unsigned long)-ERESTART_RESTARTBLOCK, function do_signal doesn't distinguish if the process is 64bit or 32bit, and always sets restart syscall number as __NR_restart_syscall (219). Signed-off-by: Zhang Yanmin Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/signal.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c index d439ced150c..3fdcdba0fec 100644 --- a/arch/x86_64/kernel/signal.c +++ b/arch/x86_64/kernel/signal.c @@ -452,7 +452,9 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) regs->rip -= 2; } if (regs->rax == (unsigned long)-ERESTART_RESTARTBLOCK) { - regs->rax = __NR_restart_syscall; + regs->rax = test_thread_flag(TIF_IA32) ? + __NR_ia32_restart_syscall : + __NR_restart_syscall; regs->rip -= 2; } } -- cgit v1.2.3 From 14d98cad82b78956957e95567b8b5fb38ec5859f Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Fri, 20 May 2005 14:27:59 -0700 Subject: [PATCH] x86_64: Add option to disable timer check This works around the too fast timer seen on some ATI boards. I don't feel confident enough about it yet to enable it by default, but give users the option. Patch and debugging from Christopher Allen Wing , with minor tweaks (renamed the option and documented it) Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/x86_64/boot-options.txt | 3 +++ arch/x86_64/kernel/io_apic.c | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt index 44b6eea60ec..b9e6be00cad 100644 --- a/Documentation/x86_64/boot-options.txt +++ b/Documentation/x86_64/boot-options.txt @@ -25,6 +25,9 @@ APICs noapictimer Don't set up the APIC timer + no_timer_check Don't check the IO-APIC timer. This can work around + problems with incorrect timer initialization on some boards. + Early Console syntax: earlyprintk=vga diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index ac768432495..80e9b498c44 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -42,6 +42,8 @@ int sis_apic_bug; /* not actually supported, dummy for compile */ +static int no_timer_check; + static DEFINE_SPINLOCK(ioapic_lock); /* @@ -1601,7 +1603,7 @@ static inline void check_timer(void) * Ok, does IRQ0 through the IOAPIC work? */ unmask_IO_APIC_irq(0); - if (timer_irq_works()) { + if (!no_timer_check && timer_irq_works()) { nmi_watchdog_default(); if (nmi_watchdog == NMI_IO_APIC) { disable_8259A_irq(0); @@ -1671,6 +1673,13 @@ static inline void check_timer(void) panic("IO-APIC + timer doesn't work! Try using the 'noapic' kernel parameter\n"); } +static int __init notimercheck(char *s) +{ + no_timer_check = 1; + return 1; +} +__setup("no_timer_check", notimercheck); + /* * * IRQ's that are handled by the PIC in the MPS IOAPIC case. -- cgit v1.2.3 From 2df9fa36643f03b0462b170515c1e221c3709fa9 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Fri, 20 May 2005 14:27:59 -0700 Subject: [PATCH] x86_64: i386/x86-64: Export cpu_core_map Needed for the powernow k8 driver for dual core support. Signed-off-by: Andi Kleen Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/smpboot.c | 1 + arch/x86_64/kernel/smpboot.c | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index cbea7ac582e..35bfe138cb1 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -888,6 +888,7 @@ void *xquad_portio; cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned; cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned; +EXPORT_SYMBOL(cpu_core_map); static void __init smp_boot_cpus(unsigned int max_cpus) { diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index 5abdee1e16a..f1ec0f34594 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -94,6 +94,7 @@ int smp_threads_ready; cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned; cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned; +EXPORT_SYMBOL(cpu_core_map); /* * Trampoline 80x86 program as an array. -- cgit v1.2.3 From 912490db699d83cb3d03570b63df7448677a3f56 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sat, 21 May 2005 10:27:02 +0100 Subject: [PATCH] MMC: Proper MMC command classes support Defines for the different command classes as defined in the MMC and SD specifications. Removes the check for high command classes and instead checks that the command classes needed are present. Previous solution killed forward compatibility at no apparent gain. Signed-of-by: Pierre Ossman --- drivers/mmc/mmc_block.c | 5 ++++- include/linux/mmc/protocol.h | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index b5b4a7b1190..d4eee99c2bf 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -383,7 +383,10 @@ static int mmc_blk_probe(struct mmc_card *card) struct mmc_blk_data *md; int err; - if (card->csd.cmdclass & ~0x1ff) + /* + * Check that the card supports the command class(es) we need. + */ + if (!(card->csd.cmdclass & CCC_BLOCK_READ)) return -ENODEV; if (card->csd.read_blkbits < 9) { diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h index 7b904c5102f..896342817b9 100644 --- a/include/linux/mmc/protocol.h +++ b/include/linux/mmc/protocol.h @@ -195,6 +195,33 @@ struct _mmc_csd { #define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */ #define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */ +/* + * Card Command Classes (CCC) + */ +#define CCC_BASIC (1<<0) /* (0) Basic protocol functions */ + /* (CMD0,1,2,3,4,7,9,10,12,13,15) */ +#define CCC_STREAM_READ (1<<1) /* (1) Stream read commands */ + /* (CMD11) */ +#define CCC_BLOCK_READ (1<<2) /* (2) Block read commands */ + /* (CMD16,17,18) */ +#define CCC_STREAM_WRITE (1<<3) /* (3) Stream write commands */ + /* (CMD20) */ +#define CCC_BLOCK_WRITE (1<<4) /* (4) Block write commands */ + /* (CMD16,24,25,26,27) */ +#define CCC_ERASE (1<<5) /* (5) Ability to erase blocks */ + /* (CMD32,33,34,35,36,37,38,39) */ +#define CCC_WRITE_PROT (1<<6) /* (6) Able to write protect blocks */ + /* (CMD28,29,30) */ +#define CCC_LOCK_CARD (1<<7) /* (7) Able to lock down card */ + /* (CMD16,CMD42) */ +#define CCC_APP_SPEC (1<<8) /* (8) Application specific */ + /* (CMD55,56,57,ACMD*) */ +#define CCC_IO_MODE (1<<9) /* (9) I/O mode */ + /* (CMD5,39,40,52,53) */ +#define CCC_SWITCH (1<<10) /* (10) High speed switch */ + /* (CMD6,34,35,36,37,50) */ + /* (11) Reserved */ + /* (CMD?) */ /* * CSD field definitions -- cgit v1.2.3 From 857dde2e79082d2954ede7f10783addaae956777 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 21 May 2005 15:52:23 +0100 Subject: When we detect that a 16550 was in fact part of a NatSemi SuperIO chip with high-speed mode enabled, we switch it to high-speed mode so that baud_base becomes 921600. However, we also need to multiply the baud divisor by 8 at the same time, in case it's already in use as a console. Signed-off-by: David Woodhouse Acked-by: Tom Rini Signed-off-by: Russell King --- drivers/serial/8250.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 3bbf0cc6e53..30e8beb7143 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -682,8 +682,6 @@ static void autoconfig_16550a(struct uart_8250_port *up) * from EXCR1. Switch back to bank 0, change it in MCR. Then * switch back to bank 2, read it from EXCR1 again and check * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2 - * On PowerPC we don't want to change baud_base, as we have - * a number of different divisors. -- Tom Rini */ serial_outp(up, UART_LCR, 0); status1 = serial_in(up, UART_MCR); @@ -699,16 +697,25 @@ static void autoconfig_16550a(struct uart_8250_port *up) serial_outp(up, UART_MCR, status1); if ((status2 ^ status1) & UART_MCR_LOOP) { -#ifndef CONFIG_PPC + unsigned short quot; + serial_outp(up, UART_LCR, 0xE0); + + quot = serial_inp(up, UART_DLM) << 8; + quot += serial_inp(up, UART_DLL); + quot <<= 3; + status1 = serial_in(up, 0x04); /* EXCR1 */ status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ serial_outp(up, 0x04, status1); + + serial_outp(up, UART_DLL, quot & 0xff); + serial_outp(up, UART_DLM, quot >> 8); + serial_outp(up, UART_LCR, 0); - up->port.uartclk = 921600*16; -#endif + up->port.uartclk = 921600*16; up->port.type = PORT_NS16550A; up->capabilities |= UART_NATSEMI; return; -- cgit v1.2.3 From 10f02d1c59e55f529140dda3a92f0099d748451c Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Sat, 21 May 2005 17:50:15 +0200 Subject: [PATCH] spin_unlock_bh() and preempt_check_resched() In _spin_unlock_bh(lock): do { \ _raw_spin_unlock(lock); \ preempt_enable(); \ local_bh_enable(); \ __release(lock); \ } while (0) there is no reason for using preempt_enable() instead of a simple preempt_enable_no_resched() Since we know bottom halves are disabled, preempt_schedule() will always return at once (preempt_count!=0), and hence preempt_check_resched() is useless here... This fixes it by using "preempt_enable_no_resched()" instead of the "preempt_enable()", and thus avoids the useless preempt_check_resched() just before re-enabling bottom halves. Signed-off-by: Samuel Thibault Signed-off-by: Linus Torvalds --- include/linux/spinlock.h | 8 ++++---- kernel/spinlock.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index e895f3eaf53..d6ba068719b 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -248,7 +248,7 @@ typedef struct { #define _spin_trylock_bh(lock) ({preempt_disable(); local_bh_disable(); \ _raw_spin_trylock(lock) ? \ - 1 : ({preempt_enable(); local_bh_enable(); 0;});}) + 1 : ({preempt_enable_no_resched(); local_bh_enable(); 0;});}) #define _spin_lock(lock) \ do { \ @@ -383,7 +383,7 @@ do { \ #define _spin_unlock_bh(lock) \ do { \ _raw_spin_unlock(lock); \ - preempt_enable(); \ + preempt_enable_no_resched(); \ local_bh_enable(); \ __release(lock); \ } while (0) @@ -391,7 +391,7 @@ do { \ #define _write_unlock_bh(lock) \ do { \ _raw_write_unlock(lock); \ - preempt_enable(); \ + preempt_enable_no_resched(); \ local_bh_enable(); \ __release(lock); \ } while (0) @@ -423,8 +423,8 @@ do { \ #define _read_unlock_bh(lock) \ do { \ _raw_read_unlock(lock); \ + preempt_enable_no_resched(); \ local_bh_enable(); \ - preempt_enable(); \ __release(lock); \ } while (0) diff --git a/kernel/spinlock.c b/kernel/spinlock.c index e15ed17863f..0c3f9d8bbe1 100644 --- a/kernel/spinlock.c +++ b/kernel/spinlock.c @@ -294,7 +294,7 @@ EXPORT_SYMBOL(_spin_unlock_irq); void __lockfunc _spin_unlock_bh(spinlock_t *lock) { _raw_spin_unlock(lock); - preempt_enable(); + preempt_enable_no_resched(); local_bh_enable(); } EXPORT_SYMBOL(_spin_unlock_bh); @@ -318,7 +318,7 @@ EXPORT_SYMBOL(_read_unlock_irq); void __lockfunc _read_unlock_bh(rwlock_t *lock) { _raw_read_unlock(lock); - preempt_enable(); + preempt_enable_no_resched(); local_bh_enable(); } EXPORT_SYMBOL(_read_unlock_bh); @@ -342,7 +342,7 @@ EXPORT_SYMBOL(_write_unlock_irq); void __lockfunc _write_unlock_bh(rwlock_t *lock) { _raw_write_unlock(lock); - preempt_enable(); + preempt_enable_no_resched(); local_bh_enable(); } EXPORT_SYMBOL(_write_unlock_bh); @@ -354,7 +354,7 @@ int __lockfunc _spin_trylock_bh(spinlock_t *lock) if (_raw_spin_trylock(lock)) return 1; - preempt_enable(); + preempt_enable_no_resched(); local_bh_enable(); return 0; } -- cgit v1.2.3 From f359b74c80bc76c1f6c2cb8f2837882f2335ba0c Mon Sep 17 00:00:00 2001 From: Vladimir Saveliev Date: Sat, 21 May 2005 16:33:34 -0700 Subject: [PATCH] reiserfs: max_key fix This patch fixes a bug introduced by Al Viro's patch: [patch 136/174] reiserfs endianness: clone struct reiserfs_key The problem is MAX_KEY and MAX_IN_CORE_KEY defined in this patch do not look equal from reiserfs comp_key's point of view. This caused reiserfs' sanity check to complain. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/reiserfs/stree.c | 1 - fs/reiserfs/super.c | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index da23ba75f3d..c47f8fd31a2 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c @@ -230,7 +230,6 @@ const struct reiserfs_key MAX_KEY = { __constant_cpu_to_le32(0xffffffff)},} }; -const struct in_core_key MAX_IN_CORE_KEY = {~0U, ~0U, ~0ULL>>4, 15}; /* Get delimiting key of the buffer by looking for it in the buffers in the path, starting from the bottom of the path, and going upwards. We must check the path's validity at each step. If the key is not in diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 31e75125f48..b35b8774498 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -164,7 +164,9 @@ static int finish_unfinished (struct super_block * s) /* compose key to look for "save" links */ max_cpu_key.version = KEY_FORMAT_3_5; - max_cpu_key.on_disk_key = MAX_IN_CORE_KEY; + max_cpu_key.on_disk_key.k_dir_id = ~0U; + max_cpu_key.on_disk_key.k_objectid = ~0U; + set_cpu_key_k_offset (&max_cpu_key, ~0U); max_cpu_key.key_length = 3; #ifdef CONFIG_QUOTA -- cgit v1.2.3 From b5c44c2147a447f77e07fecdb087ae288e1f4e40 Mon Sep 17 00:00:00 2001 From: Suparna Bhattacharya Date: Sat, 21 May 2005 16:33:36 -0700 Subject: [PATCH] fix for __generic_file_aio_read() to return 0 on EOF I came across the following problem while running ltp-aiodio testcases from ltp-full-20050405 on linux-2.6.12-rc3-mm3. I tried running the tests with EXT3 as well as JFS filesystems. One or two fsx-linux testcases were hung after some time. These testcases were hanging at wait_for_all_aios(). Debugging shows that there were some iocbs which were not getting completed eventhough the last retry for those returned -EIOCBQUEUED. Also all such pending iocbs represented READ operation. Further debugging revealed that all such iocbs hit EOF in the DIO layer. To be more precise, the "pos" from which they were trying to read was greater than the "size" of the file. So the generic_file_direct_IO returned 0. This happens rarely as there is already a check in __generic_file_aio_read(), for whether "pos" < "size" before calling direct IO routine. >size = i_size_read(inode); >if (pos < size) { > retval = generic_file_direct_IO(READ, iocb, > iov, pos, nr_segs); But for READ, we are taking the inode->i_sem only in the DIO layer. So it is possible that some other process can change the size of the file before we take the i_sem. In such a case ( when "pos" > "size"), the __generic_file_aio_read() would return -EIOCBQUEUED even though there were no I/O requests submitted by the DIO layer. This would cause the AIO layer to expect aio_complete() for THE iocb, which doesnot happen. And thus the test hangs forever, waiting for an I/O completion, where there are no requests submitted at all. The following patch makes __generic_file_aio_read() return 0 (instead of returning -EIOCBQUEUED), on getting 0 from generic_file_direct_IO(), so that the AIO layer does the aio_complete(). Testing: I have tested the patch on a SMP machine(with 2 Pentium 4 (HT)) running linux-2.6.12-rc3-mm3. I ran the ltp-aiodio testcases and none of the fsx-linux tests hung. Also the aio-stress tests ran without any problem. Signed-off-by: Suzuki K P Signed-off-by: Suparna Bhattacharya Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/filemap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/filemap.c b/mm/filemap.c index 47263ac3e4e..1d33fec7bac 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1004,7 +1004,7 @@ __generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, if (pos < size) { retval = generic_file_direct_IO(READ, iocb, iov, pos, nr_segs); - if (retval >= 0 && !is_sync_kiocb(iocb)) + if (retval > 0 && !is_sync_kiocb(iocb)) retval = -EIOCBQUEUED; if (retval > 0) *ppos = pos + retval; -- cgit v1.2.3 From 1263cc67c09bc7f913a6877f3ba0427f0b76617e Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 23 May 2005 10:03:52 +1000 Subject: [PATCH] ppc64: Fix booting on latest G5 models The latest speedbumped Apple G5 models have a "bug" in the Open Firmware device tree that lacks the proper interrupt routing information for the northbridge i2c controller. Apple's driver silently falls back into a sub-optimal "polled" mode (heh, maybe they didn't even notice the bug because of that :), our driver didn't properly check and crashes :( This patch fixes our driver to not crash, and adds code to the prom_init() OF trampoline code that detects the "bug" and adds the missing information back for this chipset revision. This fixes booting and thermal control on these models. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/prom_init.c | 44 +++++++++++++++++++++++++++++++++++++++- drivers/i2c/busses/i2c-keywest.c | 5 +++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c index 35ec42de962..6f79b7b9b44 100644 --- a/arch/ppc64/kernel/prom_init.c +++ b/arch/ppc64/kernel/prom_init.c @@ -1750,7 +1750,44 @@ static void __init flatten_device_tree(void) prom_printf("Device tree struct 0x%x -> 0x%x\n", RELOC(dt_struct_start), RELOC(dt_struct_end)); - } +} + + +static void __init fixup_device_tree(void) +{ + unsigned long offset = reloc_offset(); + phandle u3, i2c, mpic; + u32 u3_rev; + u32 interrupts[2]; + u32 parent; + + /* Some G5s have a missing interrupt definition, fix it up here */ + u3 = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000")); + if ((long)u3 <= 0) + return; + i2c = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/i2c@f8001000")); + if ((long)i2c <= 0) + return; + mpic = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/mpic@f8040000")); + if ((long)mpic <= 0) + return; + + /* check if proper rev of u3 */ + if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) <= 0) + return; + if (u3_rev != 0x35) + return; + /* does it need fixup ? */ + if (prom_getproplen(i2c, "interrupts") > 0) + return; + /* interrupt on this revision of u3 is number 0 and level */ + interrupts[0] = 0; + interrupts[1] = 1; + prom_setprop(i2c, "interrupts", &interrupts, sizeof(interrupts)); + parent = (u32)mpic; + prom_setprop(i2c, "interrupt-parent", &parent, sizeof(parent)); +} + static void __init prom_find_boot_cpu(void) { @@ -1919,6 +1956,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long PTRRELOC(&prom_tce_alloc_end), sizeof(RELOC(prom_tce_alloc_end))); } + /* + * Fixup any known bugs in the device-tree + */ + fixup_device_tree(); + /* * Now finally create the flattened device-tree */ diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c index dd0d4c46314..867d443e713 100644 --- a/drivers/i2c/busses/i2c-keywest.c +++ b/drivers/i2c/busses/i2c-keywest.c @@ -516,6 +516,11 @@ create_iface(struct device_node *np, struct device *dev) u32 *psteps, *prate; int rc; + if (np->n_intrs < 1 || np->n_addrs < 1) { + printk(KERN_ERR "%s: Missing interrupt or address !\n", + np->full_name); + return -ENODEV; + } if (pmac_low_i2c_lock(np)) return -ENODEV; -- cgit v1.2.3 From e16fa6b9d2ad9467cf5bdf517e6b6f45e5867ad6 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Mon, 23 May 2005 12:29:56 -0500 Subject: [PATCH] ppc32: Fix an off-by-one error in ipic_init There is an off-by-one error in the IPIC code that configures the external interrupts (Edge or Level Sensitive). Signed-off-by: Randy Vinson Signed-off-by: Kumar Gala Signed-off-by: Linus Torvalds --- arch/ppc/syslib/ipic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/ppc/syslib/ipic.c b/arch/ppc/syslib/ipic.c index acb2cde3171..580ed658e87 100644 --- a/arch/ppc/syslib/ipic.c +++ b/arch/ppc/syslib/ipic.c @@ -479,7 +479,7 @@ void __init ipic_init(phys_addr_t phys_addr, temp = 0; for (i = 0 ; i < senses_count ; i++) { if ((senses[i] & IRQ_SENSE_MASK) == IRQ_SENSE_EDGE) { - temp |= 1 << (16 - i); + temp |= 1 << (15 - i); if (i != 0) irq_desc[i + irq_offset + MPC83xx_IRQ_EXT1 - 1].status = 0; else -- cgit v1.2.3 From f10d20c1f192aa90fc935207f22da32462e793ee Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 23 May 2005 16:54:14 +1000 Subject: [PATCH] ppc64: Fix g5 hw timebase sync The hardware sync of the timebase on SMP G5s uses a black magic incantation to the i2c clock chip that was inspired from what Darwin does. However, this was an earlier version of Darwin that was ... buggy ! heh. This causes the latest models to break though when starting SMP, so it's worth fixing. Here's a new version of the incantation based on careful transcription of the said incantations as found in the latest version of apple's temple. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/pmac_smp.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/arch/ppc64/kernel/pmac_smp.c b/arch/ppc64/kernel/pmac_smp.c index c27588ede2f..a23de37227b 100644 --- a/arch/ppc64/kernel/pmac_smp.c +++ b/arch/ppc64/kernel/pmac_smp.c @@ -68,6 +68,7 @@ extern struct smp_ops_t *smp_ops; static void (*pmac_tb_freeze)(int freeze); static struct device_node *pmac_tb_clock_chip_host; +static u8 pmac_tb_pulsar_addr; static DEFINE_SPINLOCK(timebase_lock); static unsigned long timebase; @@ -106,12 +107,9 @@ static void smp_core99_pulsar_tb_freeze(int freeze) u8 data; int rc; - /* Strangely, the device-tree says address is 0xd2, but darwin - * accesses 0xd0 ... - */ pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined); rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, - 0xd4 | pmac_low_i2c_read, + pmac_tb_pulsar_addr | pmac_low_i2c_read, 0x2e, &data, 1); if (rc != 0) goto bail; @@ -120,7 +118,7 @@ static void smp_core99_pulsar_tb_freeze(int freeze) pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub); rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, - 0xd4 | pmac_low_i2c_write, + pmac_tb_pulsar_addr | pmac_low_i2c_write, 0x2e, &data, 1); bail: if (rc != 0) { @@ -185,6 +183,12 @@ static int __init smp_core99_probe(void) if (ncpus <= 1) return 1; + /* HW sync only on these platforms */ + if (!machine_is_compatible("PowerMac7,2") && + !machine_is_compatible("PowerMac7,3") && + !machine_is_compatible("RackMac3,1")) + goto nohwsync; + /* Look for the clock chip */ for (cc = NULL; (cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL;) { struct device_node *p = of_get_parent(cc); @@ -198,11 +202,18 @@ static int __init smp_core99_probe(void) goto next; switch (*reg) { case 0xd2: - pmac_tb_freeze = smp_core99_cypress_tb_freeze; - printk(KERN_INFO "Timebase clock is Cypress chip\n"); + if (device_is_compatible(cc, "pulsar-legacy-slewing")) { + pmac_tb_freeze = smp_core99_pulsar_tb_freeze; + pmac_tb_pulsar_addr = 0xd2; + printk(KERN_INFO "Timebase clock is Pulsar chip\n"); + } else if (device_is_compatible(cc, "cy28508")) { + pmac_tb_freeze = smp_core99_cypress_tb_freeze; + printk(KERN_INFO "Timebase clock is Cypress chip\n"); + } break; case 0xd4: pmac_tb_freeze = smp_core99_pulsar_tb_freeze; + pmac_tb_pulsar_addr = 0xd4; printk(KERN_INFO "Timebase clock is Pulsar chip\n"); break; } @@ -210,12 +221,15 @@ static int __init smp_core99_probe(void) pmac_tb_clock_chip_host = p; smp_ops->give_timebase = smp_core99_give_timebase; smp_ops->take_timebase = smp_core99_take_timebase; + of_node_put(cc); + of_node_put(p); break; } next: of_node_put(p); } + nohwsync: mpic_request_ipis(); return ncpus; -- cgit v1.2.3 From 314324121f9b94b2ca657a494cf2b9cb0e4a28cc Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 23 May 2005 12:03:06 -0700 Subject: [TCP]: Fix stretch ACK performance killer when doing ucopy. When we are doing ucopy, we try to defer the ACK generation to cleanup_rbuf(). This works most of the time very well, but if the ucopy prequeue is large, this ACKing behavior kills performance. With TSO, it is possible to fill the prequeue so large that by the time the ACK is sent and gets back to the sender, most of the window has emptied of data and performance suffers significantly. This behavior does help in some cases, so we should think about re-enabling this trick in the future, using some kind of limit in order to avoid the bug case. Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 79835a67a27..5bad504630a 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4355,16 +4355,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, goto no_ack; } - if (eaten) { - if (tcp_in_quickack_mode(tp)) { - tcp_send_ack(sk); - } else { - tcp_send_delayed_ack(sk); - } - } else { - __tcp_ack_snd_check(sk, 0); - } - + __tcp_ack_snd_check(sk, 0); no_ack: if (eaten) __kfree_skb(skb); -- cgit v1.2.3 From 15333038d577b0c0255c0f14a38d9e6895937453 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 23 May 2005 12:36:25 -0700 Subject: [CRYPTO]: Only reschedule if !in_atomic() The netlink gfp_any() problem made me double-check the uses of in_softirq() in crypto/*. It seems to me that we should be checking in_atomic() instead of in_softirq() in crypto_yield. Otherwise people calling the crypto ops with spin locks held or preemption disabled will get burnt, right? Signed-off-by: David S. Miller --- crypto/internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/internal.h b/crypto/internal.h index e68e43886d3..964b9a60ca2 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -38,7 +38,7 @@ static inline void crypto_kunmap(void *vaddr, int out) static inline void crypto_yield(struct crypto_tfm *tfm) { - if (!in_softirq()) + if (!in_atomic()) cond_resched(); } -- cgit v1.2.3 From deaf2622bdc74270381873c7936c91500c683853 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 23 May 2005 12:45:26 -0700 Subject: [NET]: Kill stray reference to sock->passcred. That struct member was deleted, but a comment was not updated to reflect this. Signed-off-by: David S. Miller --- include/linux/net.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/net.h b/include/linux/net.h index 6d997ff3f10..20cb226b226 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -101,7 +101,6 @@ enum sock_type { * @sk: internal networking protocol agnostic socket representation * @wait: wait queue for several uses * @type: socket type (%SOCK_STREAM, etc) - * @passcred: credentials (used only in Unix Sockets (aka PF_LOCAL)) */ struct socket { socket_state state; -- cgit v1.2.3 From 82d1542c1df6b3a0105843deddebeff03068d1dc Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Mon, 23 May 2005 12:53:14 -0700 Subject: [NET]: include/linux/if_tr.h clean-up I removed the ethernet definitions (which were commented out) and cleaned up the tabs. Signed-off-by: Jon Mason --- include/linux/if_tr.h | 39 +++++++++++++++------------------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/include/linux/if_tr.h b/include/linux/if_tr.h index 4fd451f81cc..a2b01e1e72f 100644 --- a/include/linux/if_tr.h +++ b/include/linux/if_tr.h @@ -9,7 +9,7 @@ * * Author: Fred N. van Kempen, * Donald Becker, - * Peter De Schrijver, + * Peter De Schrijver, * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -19,24 +19,16 @@ #ifndef _LINUX_IF_TR_H #define _LINUX_IF_TR_H - /* IEEE 802.5 Token-Ring magic constants. The frame sizes omit the preamble and FCS/CRC (frame check sequence). */ -#define TR_ALEN 6 /* Octets in one ethernet addr */ -#define TR_HLEN (sizeof(struct trh_hdr)+sizeof(struct trllc)) -#define AC 0x10 -#define LLC_FRAME 0x40 -#if 0 -#define ETH_HLEN 14 /* Total octets in header. */ -#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ -#define ETH_DATA_LEN 1500 /* Max. octets in payload */ -#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ -#endif - +#define TR_ALEN 6 /* Octets in one token-ring addr */ +#define TR_HLEN (sizeof(struct trh_hdr)+sizeof(struct trllc)) +#define AC 0x10 +#define LLC_FRAME 0x40 /* LLC and SNAP constants */ -#define EXTENDED_SAP 0xAA -#define UI_CMD 0x03 +#define EXTENDED_SAP 0xAA +#define UI_CMD 0x03 /* This is an Token-Ring frame header. */ struct trh_hdr { @@ -96,14 +88,13 @@ struct tr_statistics { }; /* source routing stuff */ - -#define TR_RII 0x80 -#define TR_RCF_DIR_BIT 0x80 -#define TR_RCF_LEN_MASK 0x1f00 -#define TR_RCF_BROADCAST 0x8000 /* all-routes broadcast */ -#define TR_RCF_LIMITED_BROADCAST 0xC000 /* single-route broadcast */ -#define TR_RCF_FRAME2K 0x20 -#define TR_RCF_BROADCAST_MASK 0xC000 -#define TR_MAXRIFLEN 18 +#define TR_RII 0x80 +#define TR_RCF_DIR_BIT 0x80 +#define TR_RCF_LEN_MASK 0x1f00 +#define TR_RCF_BROADCAST 0x8000 /* all-routes broadcast */ +#define TR_RCF_LIMITED_BROADCAST 0xC000 /* single-route broadcast */ +#define TR_RCF_FRAME2K 0x20 +#define TR_RCF_BROADCAST_MASK 0xC000 +#define TR_MAXRIFLEN 18 #endif /* _LINUX_IF_TR_H */ -- cgit v1.2.3 From d8659255c599ba497bcfb8b4abc187d9e0951d99 Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Mon, 23 May 2005 12:54:51 -0700 Subject: [TG3]: Add 5752M device ID. Add 0x1601 as 5752M, it's a 5752 but for mobile PCs. Stolen from Broadcom bcm5700-8.1.55 driver. Someone forgot to add it to tg3 ;-) Signed-off-by: David S. Miller --- drivers/net/tg3.c | 2 ++ include/linux/pci_ids.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 4d2bdbdd34e..ebd882fbc70 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -206,6 +206,8 @@ static struct pci_device_id tg3_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752M, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753M, diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index ae27792b5aa..7b9720e3536 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2064,6 +2064,7 @@ #define PCI_VENDOR_ID_BROADCOM 0x14e4 #define PCI_DEVICE_ID_TIGON3_5752 0x1600 +#define PCI_DEVICE_ID_TIGON3_5752M 0x1601 #define PCI_DEVICE_ID_TIGON3_5700 0x1644 #define PCI_DEVICE_ID_TIGON3_5701 0x1645 #define PCI_DEVICE_ID_TIGON3_5702 0x1646 -- cgit v1.2.3 From 205902ecc7bcb2a007ed27bb3518e8f70e5d113e Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 23 May 2005 13:09:19 -0700 Subject: [NET]: netdevice.h: be'ify packet_type Everybody does struct packet_type foo_packet_type = { .type = __constant_htons(ETH_P_FOO); }; 5 introduced warnings will be properly fixed later. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index ac11d73be4c..b25bd02720d 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -503,7 +503,7 @@ static inline void *netdev_priv(struct net_device *dev) #define SET_NETDEV_DEV(net, pdev) ((net)->class_dev.dev = (pdev)) struct packet_type { - unsigned short type; /* This is really htons(ether_type). */ + __be16 type; /* This is really htons(ether_type). */ struct net_device *dev; /* NULL is wildcarded here */ int (*func) (struct sk_buff *, struct net_device *, struct packet_type *); -- cgit v1.2.3 From 180e42503300629692b513daeb55a6bb0b51500c Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 23 May 2005 13:11:07 -0700 Subject: [IPV6]: Fix xfrm tunnel oops with large packets Signed-off-by: Herbert Xu Acked-by: Hideaki YOSHIFUJI Signed-off-by: David S. Miller --- net/ipv6/xfrm6_output.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 601a148f60f..6b9867717d1 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -84,6 +84,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb) mtu = IPV6_MIN_MTU; if (skb->len > mtu) { + skb->dev = dst->dev; icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); ret = -EMSGSIZE; } -- cgit v1.2.3 From 413f5431a5a27e44c6610de640e507e1e3c885f4 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 23 May 2005 13:13:15 -0700 Subject: [TG3]: Update driver version and reldate. Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index ebd882fbc70..fb168855b25 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -61,8 +61,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.27" -#define DRV_MODULE_RELDATE "May 5, 2005" +#define DRV_MODULE_VERSION "3.28" +#define DRV_MODULE_RELDATE "May 23, 2005" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v1.2.3 From ded7340d9d9142807a1ef94ab9c51d13ab76a1c9 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 23 May 2005 13:59:47 -0700 Subject: [TG3]: Increase TEST_BUFFER_SIZE to 8K. This makes the DMA bug workaround test more likely to find the problem on some systems. Signed-off-by: David S. Miller --- drivers/net/tg3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index fb168855b25..2bb022ab668 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8996,7 +8996,7 @@ static int __devinit tg3_do_test_dma(struct tg3 *tp, u32 *buf, dma_addr_t buf_dm return ret; } -#define TEST_BUFFER_SIZE 0x400 +#define TEST_BUFFER_SIZE 0x2000 static int __devinit tg3_test_dma(struct tg3 *tp) { -- cgit v1.2.3 From d1faeaeb95a05275cf0c5b51b88f2fa833434625 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 23 May 2005 14:00:44 -0700 Subject: [TG3]: Update driver version. Signed-off-by: David S. Miller --- drivers/net/tg3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 2bb022ab668..f10dd74988c 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -61,7 +61,7 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.28" +#define DRV_MODULE_VERSION "3.29" #define DRV_MODULE_RELDATE "May 23, 2005" #define TG3_DEF_MAC_MODE 0 -- cgit v1.2.3 From 816242da3735957bee99aeba40aa60c4f120a101 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 23 May 2005 15:52:08 -0700 Subject: [SPARC64]: Add boot option to force UltraSPARC-III P-Cache on. Older UltraSPARC-III chips have a P-Cache bug that makes us disable it by default at boot time. However, this does hurt performance substantially, particularly with memcpy(), and the bug is _incredibly_ obscure. I have never seen it triggered in practice, ever. So provide a "-P" boot option that forces the P-Cache on. It taints the kernel, so if it does trigger and cause some data corruption or OOPS, we will find out in the logs that this option was on when it happened. Signed-off-by: David S. Miller --- arch/sparc64/kernel/setup.c | 11 +++++++++++ arch/sparc64/kernel/smp.c | 3 +++ arch/sparc64/kernel/traps.c | 19 +++++++++++++++++++ include/asm-sparc64/spitfire.h | 3 +++ 4 files changed, 36 insertions(+) diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index 12c3d84b746..b7e6a91952b 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -383,6 +383,17 @@ static void __init process_switch(char c) /* Use PROM debug console. */ register_console(&prom_debug_console); break; + case 'P': + /* Force UltraSPARC-III P-Cache on. */ + if (tlb_type != cheetah) { + printk("BOOT: Ignoring P-Cache force option.\n"); + break; + } + cheetah_pcache_forced_on = 1; + add_taint(TAINT_MACHINE_CHECK); + cheetah_enable_pcache(); + break; + default: printk("Unknown boot switch (-%c)\n", c); break; diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 6dff06a44e7..e5b9c7a2778 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -123,6 +123,9 @@ void __init smp_callin(void) smp_setup_percpu_timer(); + if (cheetah_pcache_forced_on) + cheetah_enable_pcache(); + local_irq_enable(); calibrate_delay(); diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 56b203a2af6..a9f4596d7c2 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -421,6 +421,25 @@ asmlinkage void cee_log(unsigned long ce_status, } } +int cheetah_pcache_forced_on; + +void cheetah_enable_pcache(void) +{ + unsigned long dcr; + + printk("CHEETAH: Enabling P-Cache on cpu %d.\n", + smp_processor_id()); + + __asm__ __volatile__("ldxa [%%g0] %1, %0" + : "=r" (dcr) + : "i" (ASI_DCU_CONTROL_REG)); + dcr |= (DCU_PE | DCU_HPE | DCU_SPE | DCU_SL); + __asm__ __volatile__("stxa %0, [%%g0] %1\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (dcr), "i" (ASI_DCU_CONTROL_REG)); +} + /* Cheetah error trap handling. */ static unsigned long ecache_flush_physbase; static unsigned long ecache_flush_linesize; diff --git a/include/asm-sparc64/spitfire.h b/include/asm-sparc64/spitfire.h index ad78ce64d69..9d7613eea81 100644 --- a/include/asm-sparc64/spitfire.h +++ b/include/asm-sparc64/spitfire.h @@ -48,6 +48,9 @@ enum ultra_tlb_layout { extern enum ultra_tlb_layout tlb_type; +extern int cheetah_pcache_forced_on; +extern void cheetah_enable_pcache(void); + #define sparc64_highest_locked_tlbent() \ (tlb_type == spitfire ? \ SPITFIRE_HIGHEST_LOCKED_TLBENT : \ -- cgit v1.2.3 From 187a1a94d629621d1471b42308e63573b1150773 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Mon, 23 May 2005 15:50:26 -0700 Subject: [PATCH] driver core: restore event order for device_add() As a result of the split of the kobject-registration and the corresponding hotplug event, the order of events for device_add() has changed. This restores the old order, cause it confused some userspace applications. Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/base/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index d21eb774449..fbc223486f8 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -245,6 +245,7 @@ int device_add(struct device *dev) if ((error = kobject_add(&dev->kobj))) goto Error; + kobject_hotplug(&dev->kobj, KOBJ_ADD); if ((error = device_pm_add(dev))) goto PMError; if ((error = bus_add_device(dev))) @@ -257,14 +258,13 @@ int device_add(struct device *dev) /* notify platform of device entry */ if (platform_notify) platform_notify(dev); - - kobject_hotplug(&dev->kobj, KOBJ_ADD); Done: put_device(dev); return error; BusError: device_pm_remove(dev); PMError: + kobject_hotplug(&dev->kobj, KOBJ_REMOVE); kobject_del(&dev->kobj); Error: if (parent) -- cgit v1.2.3 From 9092f46b5aed4515d9a427d5dab3be1584851f07 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 18 May 2005 13:41:33 -0400 Subject: [PATCH] tulip: add return to ULI526X clause in tulip_mdio_write The 'if' clause for ULI526X in tulip_mdio_write allows for spin_unlock_irqrestore to be called twice for tp->mii_lock. I believe this is caused by the unintentional omission of a return at the end of that clause. This patch adds that return. Signed-off-by: John W. Linville --- drivers/net/tulip/media.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c index edae09a4b02..919c40cd635 100644 --- a/drivers/net/tulip/media.c +++ b/drivers/net/tulip/media.c @@ -174,6 +174,7 @@ void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int val) break; } spin_unlock_irqrestore(&tp->mii_lock, flags); + return; } /* Establish sync by sending 32 logic ones. */ -- cgit v1.2.3 From 7e43c84e3e5423ae72ae31e4cd7bbccfd1605194 Mon Sep 17 00:00:00 2001 From: "blaisorblade@yahoo.it" Date: Wed, 25 May 2005 01:31:42 +0200 Subject: [PATCH] Cleanup DEFINE_WAIT Use LIST_HEAD_INIT rather than doing it by hand in DEFINE_WAIT. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Linus Torvalds --- include/linux/wait.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/linux/wait.h b/include/linux/wait.h index 17c874a8eb3..c9486c3efb4 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -386,9 +386,7 @@ int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *key); wait_queue_t name = { \ .task = current, \ .func = autoremove_wake_function, \ - .task_list = { .next = &(name).task_list, \ - .prev = &(name).task_list, \ - }, \ + .task_list = LIST_HEAD_INIT((name).task_list), \ } #define DEFINE_WAIT_BIT(name, word, bit) \ -- cgit v1.2.3 From 6431e6a28e8df423e1ebcda065e9ff086198d2c6 Mon Sep 17 00:00:00 2001 From: Dominik Hackl Date: Tue, 24 May 2005 19:29:46 -0700 Subject: [PATCH] voyager_smp.c static inline fix This patch fixes a compile bug by moving a static inline function to the right place. The body of a static inline function has to be declared before the use of this function. Signed-off-by: Dominik Hackl Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/mach-voyager/voyager_smp.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c index 903d739ca74..a6e0ddd65bd 100644 --- a/arch/i386/mach-voyager/voyager_smp.c +++ b/arch/i386/mach-voyager/voyager_smp.c @@ -97,7 +97,6 @@ static void ack_vic_irq(unsigned int irq); static void vic_enable_cpi(void); static void do_boot_cpu(__u8 cpuid); static void do_quad_bootstrap(void); -static inline void wrapper_smp_local_timer_interrupt(struct pt_regs *); int hard_smp_processor_id(void); @@ -125,6 +124,14 @@ send_QIC_CPI(__u32 cpuset, __u8 cpi) } } +static inline void +wrapper_smp_local_timer_interrupt(struct pt_regs *regs) +{ + irq_enter(); + smp_local_timer_interrupt(regs); + irq_exit(); +} + static inline void send_one_CPI(__u8 cpu, __u8 cpi) { @@ -1249,14 +1256,6 @@ smp_vic_timer_interrupt(struct pt_regs *regs) smp_local_timer_interrupt(regs); } -static inline void -wrapper_smp_local_timer_interrupt(struct pt_regs *regs) -{ - irq_enter(); - smp_local_timer_interrupt(regs); - irq_exit(); -} - /* local (per CPU) timer interrupt. It does both profiling and * process statistics/rescheduling. * -- cgit v1.2.3 From c33880aaddbbab1ccf36f4457ed1090621f2e39a Mon Sep 17 00:00:00 2001 From: Kirill Korotaev Date: Tue, 24 May 2005 19:29:47 -0700 Subject: [PATCH] sigkill priority fix If SIGKILL does not have priority, we cannot instantly kill task before it makes some unexpected job. It can be critical, but we were unable to reproduce this easily until Heiko Carstens reported this problem on LKML. Signed-Off-By: Kirill Korotaev Signed-Off-By: Alexey Kuznetsov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/signal.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/kernel/signal.c b/kernel/signal.c index 8f3debc77c5..b3c24c732c5 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -522,7 +522,16 @@ static int __dequeue_signal(struct sigpending *pending, sigset_t *mask, { int sig = 0; - sig = next_signal(pending, mask); + /* SIGKILL must have priority, otherwise it is quite easy + * to create an unkillable process, sending sig < SIGKILL + * to self */ + if (unlikely(sigismember(&pending->signal, SIGKILL))) { + if (!sigismember(mask, SIGKILL)) + sig = SIGKILL; + } + + if (likely(!sig)) + sig = next_signal(pending, mask); if (sig) { if (current->notifier) { if (sigismember(current->notifier_mask, sig)) { -- cgit v1.2.3 From cafdd8ba08935d9b161bb781851dc4c0e6f70427 Mon Sep 17 00:00:00 2001 From: William Lee Irwin III Date: Tue, 24 May 2005 19:31:09 -0700 Subject: [PATCH] try_to_unmap_cluster() passes out-of-bounds pte to pte_unmap() try_to_unmap_cluster() does: for (pte = pte_offset_map(pmd, address); address < end; pte++, address += PAGE_SIZE) { ... } pte_unmap(pte); It may take a little staring to notice, but pte can actually fall off the end of the pte page in this iteration, which makes life difficult for kmap_atomic() and the users not expecting it to BUG(). Of course, we're somewhat lucky in that arithmetic elsewhere in the function guarantees that at least one iteration is made, lest this force larger rearrangements to be made. This issue and patch also apply to non-mm mainline and with trivial adjustments, at least two related kernels. Discovered during internal testing at Oracle. Signed-off-by: William Irwin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/rmap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm/rmap.c b/mm/rmap.c index a6203b4e127..9827409eb7c 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -626,7 +626,7 @@ static void try_to_unmap_cluster(unsigned long cursor, pgd_t *pgd; pud_t *pud; pmd_t *pmd; - pte_t *pte; + pte_t *pte, *original_pte; pte_t pteval; struct page *page; unsigned long address; @@ -658,7 +658,7 @@ static void try_to_unmap_cluster(unsigned long cursor, if (!pmd_present(*pmd)) goto out_unlock; - for (pte = pte_offset_map(pmd, address); + for (original_pte = pte = pte_offset_map(pmd, address); address < end; pte++, address += PAGE_SIZE) { if (!pte_present(*pte)) @@ -694,7 +694,7 @@ static void try_to_unmap_cluster(unsigned long cursor, (*mapcount)--; } - pte_unmap(pte); + pte_unmap(original_pte); out_unlock: spin_unlock(&mm->page_table_lock); } -- cgit v1.2.3 From 558ac33e094f3a47c74a3a66b19cd3616f183184 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 24 May 2005 19:31:10 -0700 Subject: [PATCH] saa6752hs build fix For older gcc's. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/saa7134/saa6752hs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c index fe6abe34168..1db02268298 100644 --- a/drivers/media/video/saa7134/saa6752hs.c +++ b/drivers/media/video/saa7134/saa6752hs.c @@ -43,15 +43,15 @@ enum saa6752hs_videoformat { static const struct v4l2_format v4l2_format_table[] = { [SAA6752HS_VF_D1] = { - .fmt.pix.width = 720, .fmt.pix.height = 576 }, + .fmt = { .pix = { .width = 720, .height = 576 }, }, }, [SAA6752HS_VF_2_3_D1] = { - .fmt.pix.width = 480, .fmt.pix.height = 576 }, + .fmt = { .pix = { .width = 480, .height = 576 }, }, }, [SAA6752HS_VF_1_2_D1] = { - .fmt.pix.width = 352, .fmt.pix.height = 576 }, + .fmt = { .pix = { .width = 352, .height = 576 }, }, }, [SAA6752HS_VF_SIF] = { - .fmt.pix.width = 352, .fmt.pix.height = 288 }, + .fmt = { .pix = { .width = 352, .height = 288 }, }, }, [SAA6752HS_VF_UNKNOWN] = { - .fmt.pix.width = 0, .fmt.pix.height = 0}, + .fmt = { .pix = { .width = 0, .height = 0 }, }, }, }; struct saa6752hs_state { -- cgit v1.2.3 From d981289627a7e2d8ef62dfcaa11fb60da68f30c6 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 24 May 2005 19:31:10 -0700 Subject: [PATCH] aic7xxx_osm build fix Fix a c99ism. Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/aic7xxx/aic7xxx_osm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index f90efa265ba..c13e5632001 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -659,8 +659,11 @@ ahc_linux_slave_alloc(struct scsi_device *device) ahc_lock(ahc, &flags); targ = ahc->platform_data->targets[target_offset]; if (targ == NULL) { - targ = ahc_linux_alloc_target(ahc, starget->channel, starget->id); - struct seeprom_config *sc = ahc->seep_config; + struct seeprom_config *sc; + + targ = ahc_linux_alloc_target(ahc, starget->channel, + starget->id); + sc = ahc->seep_config; if (targ == NULL) goto out; -- cgit v1.2.3 From 2a24ab628aa7b190be32f63dfb6d96f3fb61580a Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 24 May 2005 20:31:20 -0700 Subject: Linux 2.6.12-rc5 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1bb028317f2..c11a317ea91 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 12 -EXTRAVERSION =-rc4 +EXTRAVERSION =-rc5 NAME=Woozy Numbat # *DOCUMENTATION* -- cgit v1.2.3 From 8f80e5c911465743ccd3a328f992c7d8aaebf1e8 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 25 May 2005 13:41:26 +1000 Subject: [PATCH] ppc64: fix initialisation of gettimeofday calculations On PPC64, we keep track of when we need to update jiffies (and the variables used to calculate the time of day) based on the time base. If the time base frequence is sufficiently high compared to the processor clock frequency, then it is possible for the time of day variables to be corrupted at the time of the first decrementer interrupt we take. This became obvious on a legacy iSeries where the time base frequency is the same as the processor clock. This one line patch fixes the initialisation so that the time of day variables and the indicator we use to tell when updates are due are better synchronised. Signed-off-by: Stephen Rothwell Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/time.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c index 772a465b49f..3d54745108c 100644 --- a/arch/ppc64/kernel/time.c +++ b/arch/ppc64/kernel/time.c @@ -515,6 +515,7 @@ void __init time_init(void) do_gtod.varp = &do_gtod.vars[0]; do_gtod.var_idx = 0; do_gtod.varp->tb_orig_stamp = tb_last_stamp; + get_paca()->next_jiffy_update_tb = tb_last_stamp + tb_ticks_per_jiffy; do_gtod.varp->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC; do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; do_gtod.varp->tb_to_xs = tb_to_xs; -- cgit v1.2.3 From d0e8e29100c9866878d43bbb40ca17e8fe429851 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 25 May 2005 16:29:26 +1000 Subject: [PATCH] ppc64 iSeries: fix boot time setting For quite a while, there has existed a hypervisor bug on legacy iSeries which means that we do not get the boot time set in the kernel. This patch works around that bug. This was most noticable when the root partition needed to be checked at every boot as the kernel thought it was some time in 1905 until user mode reset the time correctly. Signed-off-by: Stephen Rothwell Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/mf.c | 85 ++++++++++++++++++++++++++++++++---------- arch/ppc64/kernel/rtc.c | 39 +------------------ include/asm-ppc64/iSeries/mf.h | 1 + 3 files changed, 67 insertions(+), 58 deletions(-) diff --git a/arch/ppc64/kernel/mf.c b/arch/ppc64/kernel/mf.c index 1bd52ece497..5aca7e8005a 100644 --- a/arch/ppc64/kernel/mf.c +++ b/arch/ppc64/kernel/mf.c @@ -1,7 +1,7 @@ /* * mf.c * Copyright (C) 2001 Troy D. Armstrong IBM Corporation - * Copyright (C) 2004 Stephen Rothwell IBM Corporation + * Copyright (C) 2004-2005 Stephen Rothwell IBM Corporation * * This modules exists as an interface between a Linux secondary partition * running on an iSeries and the primary partition's Virtual Service @@ -36,10 +36,12 @@ #include #include +#include #include #include #include #include +#include /* * This is the structure layout for the Machine Facilites LPAR event @@ -696,36 +698,23 @@ static void get_rtc_time_complete(void *token, struct ce_msg_data *ce_msg) complete(&rtc->com); } -int mf_get_rtc(struct rtc_time *tm) +static int rtc_set_tm(int rc, u8 *ce_msg, struct rtc_time *tm) { - struct ce_msg_comp_data ce_complete; - struct rtc_time_data rtc_data; - int rc; - - memset(&ce_complete, 0, sizeof(ce_complete)); - memset(&rtc_data, 0, sizeof(rtc_data)); - init_completion(&rtc_data.com); - ce_complete.handler = &get_rtc_time_complete; - ce_complete.token = &rtc_data; - rc = signal_ce_msg_simple(0x40, &ce_complete); - if (rc) - return rc; - wait_for_completion(&rtc_data.com); tm->tm_wday = 0; tm->tm_yday = 0; tm->tm_isdst = 0; - if (rtc_data.rc) { + if (rc) { tm->tm_sec = 0; tm->tm_min = 0; tm->tm_hour = 0; tm->tm_mday = 15; tm->tm_mon = 5; tm->tm_year = 52; - return rtc_data.rc; + return rc; } - if ((rtc_data.ce_msg.ce_msg[2] == 0xa9) || - (rtc_data.ce_msg.ce_msg[2] == 0xaf)) { + if ((ce_msg[2] == 0xa9) || + (ce_msg[2] == 0xaf)) { /* TOD clock is not set */ tm->tm_sec = 1; tm->tm_min = 1; @@ -736,7 +725,6 @@ int mf_get_rtc(struct rtc_time *tm) mf_set_rtc(tm); } { - u8 *ce_msg = rtc_data.ce_msg.ce_msg; u8 year = ce_msg[5]; u8 sec = ce_msg[6]; u8 min = ce_msg[7]; @@ -765,6 +753,63 @@ int mf_get_rtc(struct rtc_time *tm) return 0; } +int mf_get_rtc(struct rtc_time *tm) +{ + struct ce_msg_comp_data ce_complete; + struct rtc_time_data rtc_data; + int rc; + + memset(&ce_complete, 0, sizeof(ce_complete)); + memset(&rtc_data, 0, sizeof(rtc_data)); + init_completion(&rtc_data.com); + ce_complete.handler = &get_rtc_time_complete; + ce_complete.token = &rtc_data; + rc = signal_ce_msg_simple(0x40, &ce_complete); + if (rc) + return rc; + wait_for_completion(&rtc_data.com); + return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm); +} + +struct boot_rtc_time_data { + int busy; + struct ce_msg_data ce_msg; + int rc; +}; + +static void get_boot_rtc_time_complete(void *token, struct ce_msg_data *ce_msg) +{ + struct boot_rtc_time_data *rtc = token; + + memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg)); + rtc->rc = 0; + rtc->busy = 0; +} + +int mf_get_boot_rtc(struct rtc_time *tm) +{ + struct ce_msg_comp_data ce_complete; + struct boot_rtc_time_data rtc_data; + int rc; + + memset(&ce_complete, 0, sizeof(ce_complete)); + memset(&rtc_data, 0, sizeof(rtc_data)); + rtc_data.busy = 1; + ce_complete.handler = &get_boot_rtc_time_complete; + ce_complete.token = &rtc_data; + rc = signal_ce_msg_simple(0x40, &ce_complete); + if (rc) + return rc; + /* We need to poll here as we are not yet taking interrupts */ + while (rtc_data.busy) { + extern unsigned long lpevent_count; + struct ItLpQueue *lpq = get_paca()->lpqueue_ptr; + if (lpq && ItLpQueue_isLpIntPending(lpq)) + lpevent_count += ItLpQueue_process(lpq, NULL); + } + return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm); +} + int mf_set_rtc(struct rtc_time *tm) { char ce_time[12]; diff --git a/arch/ppc64/kernel/rtc.c b/arch/ppc64/kernel/rtc.c index 3e70b91375f..67989055a9f 100644 --- a/arch/ppc64/kernel/rtc.c +++ b/arch/ppc64/kernel/rtc.c @@ -292,47 +292,10 @@ int iSeries_set_rtc_time(struct rtc_time *tm) void iSeries_get_boot_time(struct rtc_time *tm) { - unsigned long time; - static unsigned long lastsec = 1; - - u32 dataWord1 = *((u32 *)(&xSpCommArea.xBcdTimeAtIplStart)); - u32 dataWord2 = *(((u32 *)&(xSpCommArea.xBcdTimeAtIplStart)) + 1); - int year = 1970; - int year1 = ( dataWord1 >> 24 ) & 0x000000FF; - int year2 = ( dataWord1 >> 16 ) & 0x000000FF; - int sec = ( dataWord1 >> 8 ) & 0x000000FF; - int min = dataWord1 & 0x000000FF; - int hour = ( dataWord2 >> 24 ) & 0x000000FF; - int day = ( dataWord2 >> 8 ) & 0x000000FF; - int mon = dataWord2 & 0x000000FF; - if ( piranha_simulator ) return; - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year1); - BCD_TO_BIN(year2); - year = year1 * 100 + year2; - - time = mktime(year, mon, day, hour, min, sec); - time += ( jiffies / HZ ); - - /* Now THIS is a nasty hack! - * It ensures that the first two calls get different answers. - * That way the loop in init_time (time.c) will not think - * the clock is stuck. - */ - if ( lastsec ) { - time -= lastsec; - --lastsec; - } - - to_tm(time, tm); - tm->tm_year -= 1900; + mf_get_boot_rtc(tm); tm->tm_mon -= 1; } #endif diff --git a/include/asm-ppc64/iSeries/mf.h b/include/asm-ppc64/iSeries/mf.h index 2e59a8e15a0..db333e1ee21 100644 --- a/include/asm-ppc64/iSeries/mf.h +++ b/include/asm-ppc64/iSeries/mf.h @@ -52,6 +52,7 @@ extern void mf_clear_src(void); extern void mf_init(void); extern int mf_get_rtc(struct rtc_time *tm); +extern int mf_get_boot_rtc(struct rtc_time *tm); extern int mf_set_rtc(struct rtc_time *tm); #endif /* _ASM_PPC64_ISERIES_MF_H */ -- cgit v1.2.3 From 0e15850200437c60b969025500e466383ec51ed8 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 25 May 2005 09:49:13 +0100 Subject: [PATCH] Speedtouch resync after lost signal. There's a bigger Speedtouch update coming your way after 2.6.12 but in the meantime, let's at least make it automatically resync if the DSL signal is lost. Signed-off-by: David Woodhouse Signed-off-by: Linus Torvalds --- drivers/usb/atm/speedtch.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 233f9229bad..2a1697bfd69 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -386,6 +386,8 @@ static void speedtch_poll_status(struct speedtch_instance_data *instance) if (instance->u.atm_dev->signal != ATM_PHY_SIG_LOST) { instance->u.atm_dev->signal = ATM_PHY_SIG_LOST; printk(KERN_NOTICE "ADSL line is down\n"); + /* It'll never resync again unless we ask it to... */ + speedtch_start_synchro(instance); } break; -- cgit v1.2.3 From 384f1fcd2db8bc5a15f20f10793d8e1c82acd6c5 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 25 May 2005 17:00:15 +0200 Subject: [PATCH] relax ide-cd dma restrictions This has been sitting for a while, and is causing lots of grief for people burning CDs. It relaxes the dma restriction for ide-cd, requiring only the length to be 32-byte aligned, address should be fine at normal double word alignment. Signed-off-by: Jens Axboe Signed-off-by: Linus Torvalds --- drivers/ide/ide-cd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 33a020faeab..4f7ce705622 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -1933,7 +1933,7 @@ static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq) /* * check if dma is safe */ - if ((rq->data_len & mask) || (addr & mask)) + if ((rq->data_len & 3) || (addr & mask)) info->dma = 0; } -- cgit v1.2.3 From 5daf05fbf73fc199e7a93a818e504856d07c5586 Mon Sep 17 00:00:00 2001 From: Gerd Knorr Date: Wed, 25 May 2005 12:31:26 -0700 Subject: [PATCH] v4l: bttv i2c oops fix Don't try to access the i2c bus if the register wasn't successful. Signed-off-by: Gerd Knorr Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/bttv-i2c.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c index e3f477dff82..c2368bc832e 100644 --- a/drivers/media/video/bttv-i2c.c +++ b/drivers/media/video/bttv-i2c.c @@ -363,6 +363,9 @@ int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, /* read EEPROM content */ void __devinit bttv_readee(struct bttv *btv, unsigned char *eedata, int addr) { + memset(eedata, 0, 256); + if (0 != btv->i2c_rc) + return; btv->i2c_client.addr = addr >> 1; tveeprom_read(&btv->i2c_client, eedata, 256); } -- cgit v1.2.3 From dca79a046b93a81496bb30ca01177fb17f37ab72 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 25 May 2005 12:31:27 -0700 Subject: [PATCH] ipmi build fix It looks like the recent IPMI patches had some -mm-onlyisms. Signed-off-by: Neil Horman Cc: Corey Minyard Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_devintf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 4bb9af736fb..6dc765dc541 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -520,7 +520,7 @@ MODULE_PARM_DESC(ipmi_major, "Sets the major number of the IPMI device. By" " interface. Other values will set the major device number" " to that value."); -static struct class *ipmi_class; +static struct class_simple *ipmi_class; static void ipmi_new_smi(int if_num) { @@ -534,7 +534,7 @@ static void ipmi_new_smi(int if_num) static void ipmi_smi_gone(int if_num) { - class_simple_device_remove(ipmi_class, MKDEV(ipmi_major, if_num)); + class_simple_device_remove(MKDEV(ipmi_major, if_num)); devfs_remove("ipmidev/%d", if_num); } -- cgit v1.2.3 From 4f60fdf613536402e3313c5019b3ae6060b2ae4a Mon Sep 17 00:00:00 2001 From: Alexander Nyberg Date: Wed, 25 May 2005 12:31:28 -0700 Subject: [PATCH] x86_64: CONFIG_BUG=n fixes Fixes some !CONFIG_BUG warnings: include/asm/mmu_context.h: I funktion `switch_mm': include/asm/mmu_context.h:57: varning: implicit declaration of function `out_of_line_bug' Signed-off-by: Alexander Nyberg Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/traps.c | 2 ++ arch/x86_64/kernel/x8664_ksyms.c | 3 ++- include/asm-x86_64/bug.h | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 65a37f52c56..3dfec8fdabc 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -332,10 +332,12 @@ void handle_BUG(struct pt_regs *regs) printk(KERN_ALERT "Kernel BUG at %.50s:%d\n", f.filename, f.line); } +#ifdef CONFIG_BUG void out_of_line_bug(void) { BUG(); } +#endif static DEFINE_SPINLOCK(die_lock); static int die_owner = -1; diff --git a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c index a43dedb58fa..68ec03070e5 100644 --- a/arch/x86_64/kernel/x8664_ksyms.c +++ b/arch/x86_64/kernel/x8664_ksyms.c @@ -193,8 +193,9 @@ EXPORT_SYMBOL(smp_num_siblings); extern void do_softirq_thunk(void); EXPORT_SYMBOL(do_softirq_thunk); -void out_of_line_bug(void); +#ifdef CONFIG_BUG EXPORT_SYMBOL(out_of_line_bug); +#endif EXPORT_SYMBOL(init_level4_pgt); diff --git a/include/asm-x86_64/bug.h b/include/asm-x86_64/bug.h index bdbf66eab6e..3d2a666a5dd 100644 --- a/include/asm-x86_64/bug.h +++ b/include/asm-x86_64/bug.h @@ -21,6 +21,8 @@ struct bug_frame { asm volatile("ud2 ; .quad %c1 ; .short %c0" :: \ "i"(__LINE__), "i" (__stringify(__FILE__))) void out_of_line_bug(void); +#else +static inline void out_of_line_bug(void) { } #endif #include -- cgit v1.2.3 From e4f50f003dc568f6fc3904d451c562007bd09640 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 25 May 2005 12:31:29 -0700 Subject: [PATCH] IB: allow NULL sa_query callbacks Check if a client passes a NULL callback into an SA query, and if so, never call back. This fixes an oops if someone unloads ib_ipoib and ib_sa in rapid succession. ib_ipoib does an MCMember delete with a NULL callback and 0 timeout on unload, which is usually fine since the delete completes successfully. However, if ib_sa is unloaded immediately afterwards, the delete will be canceled and ib_sa will try to call the (now already unloaded) ib_ipoib module back with the cancel completion, which triggers the oops. Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/core/sa_query.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index d4233ee61c3..276e1a53010 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -587,7 +587,7 @@ int ib_sa_path_rec_get(struct ib_device *device, u8 port_num, init_mad(query->sa_query.mad, agent); - query->sa_query.callback = ib_sa_path_rec_callback; + query->sa_query.callback = callback ? ib_sa_path_rec_callback : NULL; query->sa_query.release = ib_sa_path_rec_release; query->sa_query.port = port; query->sa_query.mad->mad_hdr.method = IB_MGMT_METHOD_GET; @@ -663,7 +663,7 @@ int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num, init_mad(query->sa_query.mad, agent); - query->sa_query.callback = ib_sa_mcmember_rec_callback; + query->sa_query.callback = callback ? ib_sa_mcmember_rec_callback : NULL; query->sa_query.release = ib_sa_mcmember_rec_release; query->sa_query.port = port; query->sa_query.mad->mad_hdr.method = method; @@ -698,20 +698,21 @@ static void send_handler(struct ib_mad_agent *agent, if (!query) return; - switch (mad_send_wc->status) { - case IB_WC_SUCCESS: - /* No callback -- already got recv */ - break; - case IB_WC_RESP_TIMEOUT_ERR: - query->callback(query, -ETIMEDOUT, NULL); - break; - case IB_WC_WR_FLUSH_ERR: - query->callback(query, -EINTR, NULL); - break; - default: - query->callback(query, -EIO, NULL); - break; - } + if (query->callback) + switch (mad_send_wc->status) { + case IB_WC_SUCCESS: + /* No callback -- already got recv */ + break; + case IB_WC_RESP_TIMEOUT_ERR: + query->callback(query, -ETIMEDOUT, NULL); + break; + case IB_WC_WR_FLUSH_ERR: + query->callback(query, -EINTR, NULL); + break; + default: + query->callback(query, -EIO, NULL); + break; + } dma_unmap_single(agent->device->dma_device, pci_unmap_addr(query, mapping), @@ -736,7 +737,7 @@ static void recv_handler(struct ib_mad_agent *mad_agent, query = idr_find(&query_idr, mad_recv_wc->wc->wr_id); spin_unlock_irqrestore(&idr_lock, flags); - if (query) { + if (query && query->callback) { if (mad_recv_wc->wc->status == IB_WC_SUCCESS) query->callback(query, mad_recv_wc->recv_buf.mad->mad_hdr.status ? -- cgit v1.2.3 From 561e148ea972a6e8d2c8f7aecc658b3a64f7a6de Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 25 May 2005 12:31:30 -0700 Subject: [PATCH] IB: fix potential ib_umad leak Free all unclaimed MAD receive buffers when userspace closes our file so we don't leak memory. Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/core/user_mad.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 56b9c2fa2ec..9d912d6877f 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -499,6 +499,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp) static int ib_umad_close(struct inode *inode, struct file *filp) { struct ib_umad_file *file = filp->private_data; + struct ib_umad_packet *packet, *tmp; int i; for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i) @@ -507,6 +508,9 @@ static int ib_umad_close(struct inode *inode, struct file *filp) ib_unregister_mad_agent(file->agent[i]); } + list_for_each_entry_safe(packet, tmp, &file->recv_list, list) + kfree(packet); + kfree(file); return 0; -- cgit v1.2.3 From 3bf4fb820d7382318d178bd765c20028415466ab Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 25 May 2005 12:31:31 -0700 Subject: [PATCH] IB: fix endianness of path record MTU field Make MTU field in SA PathRecord and MCMemberRecord a u8 rather than an enum to avoid complications with endianness. Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/include/ib_sa.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/include/ib_sa.h b/drivers/infiniband/include/ib_sa.h index f4f747707b3..00222285eb9 100644 --- a/drivers/infiniband/include/ib_sa.h +++ b/drivers/infiniband/include/ib_sa.h @@ -147,7 +147,7 @@ struct ib_sa_path_rec { /* reserved */ u8 sl; u8 mtu_selector; - enum ib_mtu mtu; + u8 mtu; u8 rate_selector; u8 rate; u8 packet_life_time_selector; @@ -180,7 +180,7 @@ struct ib_sa_mcmember_rec { u32 qkey; u16 mlid; u8 mtu_selector; - enum ib_mtu mtu; + u8 mtu; u8 traffic_class; u16 pkey; u8 rate_selector; -- cgit v1.2.3 From a8bacec09352b86bd389cc93a20008577fa14764 Mon Sep 17 00:00:00 2001 From: Colin Leroy Date: Wed, 25 May 2005 12:31:34 -0700 Subject: [PATCH] Make sure therm_adt746x only handles known hardware This patch limits therm_adt746x to currently existing fan controllers in Apple laptops. It may avoid problems with future hardware. Signed-off-by: Colin Leroy Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/macintosh/therm_adt746x.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index e0ac63effa5..c7e84abe895 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -545,6 +545,12 @@ thermostat_init(void) else return -ENODEV; + prop = (u32 *)get_property(np, "hwsensor-params-version", NULL); + printk(KERN_INFO "adt746x: version %d (%ssupported)\n", *prop, + (*prop == 1)?"":"un"); + if (*prop != 1) + return -ENODEV; + prop = (u32 *)get_property(np, "reg", NULL); if (!prop) return -ENODEV; -- cgit v1.2.3 From d20c507f28dbee33086e8212b98f9ddc5372cd81 Mon Sep 17 00:00:00 2001 From: Colin Leroy Date: Wed, 25 May 2005 12:31:35 -0700 Subject: [PATCH] therm_adt746x: show correct sensor locations This patch shows the correct locations of the heat sensors present in iBook and PowerBooks G4, instead of displaying them as being on CPU and GPU (which is not always the case). Signed-off-by: Colin Leroy Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/macintosh/therm_adt746x.c | 119 ++++++++++++++++++++++++-------------- 1 file changed, 77 insertions(+), 42 deletions(-) diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index c7e84abe895..d09308f3096 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -39,15 +39,16 @@ #define MANUAL_MASK 0xe0 #define AUTO_MASK 0x20 -static u8 TEMP_REG[3] = {0x26, 0x25, 0x27}; /* local, cpu, gpu */ -static u8 LIMIT_REG[3] = {0x6b, 0x6a, 0x6c}; /* local, cpu, gpu */ +static u8 TEMP_REG[3] = {0x26, 0x25, 0x27}; /* local, sensor1, sensor2 */ +static u8 LIMIT_REG[3] = {0x6b, 0x6a, 0x6c}; /* local, sensor1, sensor2 */ static u8 MANUAL_MODE[2] = {0x5c, 0x5d}; static u8 REM_CONTROL[2] = {0x00, 0x40}; static u8 FAN_SPEED[2] = {0x28, 0x2a}; static u8 FAN_SPD_SET[2] = {0x30, 0x31}; -static u8 default_limits_local[3] = {70, 50, 70}; /* local, cpu, gpu */ -static u8 default_limits_chip[3] = {80, 65, 80}; /* local, cpu, gpu */ +static u8 default_limits_local[3] = {70, 50, 70}; /* local, sensor1, sensor2 */ +static u8 default_limits_chip[3] = {80, 65, 80}; /* local, sensor1, sensor2 */ +static char *sensor_location[3] = {NULL, NULL, NULL}; static int limit_adjust = 0; static int fan_speed = -1; @@ -58,7 +59,7 @@ MODULE_DESCRIPTION("Driver for ADT746x thermostat in iBook G4 and " MODULE_LICENSE("GPL"); module_param(limit_adjust, int, 0644); -MODULE_PARM_DESC(limit_adjust,"Adjust maximum temperatures (50 cpu, 70 gpu) " +MODULE_PARM_DESC(limit_adjust,"Adjust maximum temperatures (50 sensor1, 70 sensor2) " "by N degrees."); module_param(fan_speed, int, 0644); @@ -213,10 +214,10 @@ static void write_fan_speed(struct thermostat *th, int speed, int fan) if (th->last_speed[fan] != speed) { if (speed == -1) printk(KERN_DEBUG "adt746x: Setting speed to automatic " - "for %s fan.\n", fan?"GPU":"CPU"); + "for %s fan.\n", sensor_location[fan+1]); else printk(KERN_DEBUG "adt746x: Setting speed to %d " - "for %s fan.\n", speed, fan?"GPU":"CPU"); + "for %s fan.\n", speed, sensor_location[fan+1]); } else return; @@ -300,11 +301,11 @@ static void update_fans_speed (struct thermostat *th) printk(KERN_DEBUG "adt746x: setting fans speed to %d " "(limit exceeded by %d on %s) \n", new_speed, var, - fan_number?"GPU/pwr":"CPU"); + sensor_location[fan_number+1]); write_both_fan_speed(th, new_speed); th->last_var[fan_number] = var; } else if (var < -2) { - /* don't stop fan if GPU/power is cold and CPU is not + /* don't stop fan if sensor2 is cold and sensor1 is not * so cold (lastvar >= -1) */ if (i == 2 && lastvar < -1) { if (th->last_speed[fan_number] != 0) @@ -318,7 +319,7 @@ static void update_fans_speed (struct thermostat *th) if (started) return; /* we don't want to re-stop the fan - * if CPU is heating and GPU/power is not */ + * if sensor1 is heating and sensor2 is not */ } } @@ -353,7 +354,7 @@ static int monitor_task(void *arg) static void set_limit(struct thermostat *th, int i) { - /* Set CPU limit higher to avoid powerdowns */ + /* Set sensor1 limit higher to avoid powerdowns */ th->limits[i] = default_limits_chip[i] + limit_adjust; write_reg(th, LIMIT_REG[i], th->limits[i]); @@ -461,6 +462,12 @@ static ssize_t show_##name(struct device *dev, char *buf) \ return sprintf(buf, "%d\n", data); \ } +#define BUILD_SHOW_FUNC_STR(name, data) \ +static ssize_t show_##name(struct device *dev, char *buf) \ +{ \ + return sprintf(buf, "%s\n", data); \ +} + #define BUILD_SHOW_FUNC_FAN(name, data) \ static ssize_t show_##name(struct device *dev, char *buf) \ { \ @@ -476,7 +483,7 @@ static ssize_t store_##name(struct device *dev, const char *buf, size_t n) \ int val; \ int i; \ val = simple_strtol(buf, NULL, 10); \ - printk(KERN_INFO "Adjusting limits by %d°C\n", val); \ + printk(KERN_INFO "Adjusting limits by %d degrees\n", val); \ limit_adjust = val; \ for (i=0; i < 3; i++) \ set_limit(thermostat, i); \ @@ -495,35 +502,41 @@ static ssize_t store_##name(struct device *dev, const char *buf, size_t n) \ return n; \ } -BUILD_SHOW_FUNC_INT(cpu_temperature, (read_reg(thermostat, TEMP_REG[1]))) -BUILD_SHOW_FUNC_INT(gpu_temperature, (read_reg(thermostat, TEMP_REG[2]))) -BUILD_SHOW_FUNC_INT(cpu_limit, thermostat->limits[1]) -BUILD_SHOW_FUNC_INT(gpu_limit, thermostat->limits[2]) +BUILD_SHOW_FUNC_INT(sensor1_temperature, (read_reg(thermostat, TEMP_REG[1]))) +BUILD_SHOW_FUNC_INT(sensor2_temperature, (read_reg(thermostat, TEMP_REG[2]))) +BUILD_SHOW_FUNC_INT(sensor1_limit, thermostat->limits[1]) +BUILD_SHOW_FUNC_INT(sensor2_limit, thermostat->limits[2]) +BUILD_SHOW_FUNC_STR(sensor1_location, sensor_location[1]) +BUILD_SHOW_FUNC_STR(sensor2_location, sensor_location[2]) BUILD_SHOW_FUNC_INT(specified_fan_speed, fan_speed) -BUILD_SHOW_FUNC_FAN(cpu_fan_speed, 0) -BUILD_SHOW_FUNC_FAN(gpu_fan_speed, 1) +BUILD_SHOW_FUNC_FAN(sensor1_fan_speed, 0) +BUILD_SHOW_FUNC_FAN(sensor2_fan_speed, 1) BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed) BUILD_SHOW_FUNC_INT(limit_adjust, limit_adjust) BUILD_STORE_FUNC_DEG(limit_adjust, thermostat) -static DEVICE_ATTR(cpu_temperature, S_IRUGO, - show_cpu_temperature,NULL); -static DEVICE_ATTR(gpu_temperature, S_IRUGO, - show_gpu_temperature,NULL); -static DEVICE_ATTR(cpu_limit, S_IRUGO, - show_cpu_limit, NULL); -static DEVICE_ATTR(gpu_limit, S_IRUGO, - show_gpu_limit, NULL); +static DEVICE_ATTR(sensor1_temperature, S_IRUGO, + show_sensor1_temperature,NULL); +static DEVICE_ATTR(sensor2_temperature, S_IRUGO, + show_sensor2_temperature,NULL); +static DEVICE_ATTR(sensor1_limit, S_IRUGO, + show_sensor1_limit, NULL); +static DEVICE_ATTR(sensor2_limit, S_IRUGO, + show_sensor2_limit, NULL); +static DEVICE_ATTR(sensor1_location, S_IRUGO, + show_sensor1_location, NULL); +static DEVICE_ATTR(sensor2_location, S_IRUGO, + show_sensor2_location, NULL); static DEVICE_ATTR(specified_fan_speed, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, show_specified_fan_speed,store_specified_fan_speed); -static DEVICE_ATTR(cpu_fan_speed, S_IRUGO, - show_cpu_fan_speed, NULL); -static DEVICE_ATTR(gpu_fan_speed, S_IRUGO, - show_gpu_fan_speed, NULL); +static DEVICE_ATTR(sensor1_fan_speed, S_IRUGO, + show_sensor1_fan_speed, NULL); +static DEVICE_ATTR(sensor2_fan_speed, S_IRUGO, + show_sensor2_fan_speed, NULL); static DEVICE_ATTR(limit_adjust, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, show_limit_adjust, store_limit_adjust); @@ -534,6 +547,7 @@ thermostat_init(void) { struct device_node* np; u32 *prop; + int i = 0, offset = 0; np = of_find_node_by_name(NULL, "fan"); if (!np) @@ -569,6 +583,23 @@ thermostat_init(void) "limit_adjust: %d, fan_speed: %d\n", therm_bus, therm_address, limit_adjust, fan_speed); + if (get_property(np, "hwsensor-location", NULL)) { + for (i = 0; i < 3; i++) { + sensor_location[i] = get_property(np, + "hwsensor-location", NULL) + offset; + + if (sensor_location[i] == NULL) + sensor_location[i] = ""; + + printk(KERN_INFO "sensor %d: %s\n", i, sensor_location[i]); + offset += strlen(sensor_location[i]) + 1; + } + } else { + sensor_location[0] = "?"; + sensor_location[1] = "?"; + sensor_location[2] = "?"; + } + of_dev = of_platform_device_create(np, "temperatures"); if (of_dev == NULL) { @@ -576,15 +607,17 @@ thermostat_init(void) return -ENODEV; } - device_create_file(&of_dev->dev, &dev_attr_cpu_temperature); - device_create_file(&of_dev->dev, &dev_attr_gpu_temperature); - device_create_file(&of_dev->dev, &dev_attr_cpu_limit); - device_create_file(&of_dev->dev, &dev_attr_gpu_limit); + device_create_file(&of_dev->dev, &dev_attr_sensor1_temperature); + device_create_file(&of_dev->dev, &dev_attr_sensor2_temperature); + device_create_file(&of_dev->dev, &dev_attr_sensor1_limit); + device_create_file(&of_dev->dev, &dev_attr_sensor2_limit); + device_create_file(&of_dev->dev, &dev_attr_sensor1_location); + device_create_file(&of_dev->dev, &dev_attr_sensor2_location); device_create_file(&of_dev->dev, &dev_attr_limit_adjust); device_create_file(&of_dev->dev, &dev_attr_specified_fan_speed); - device_create_file(&of_dev->dev, &dev_attr_cpu_fan_speed); + device_create_file(&of_dev->dev, &dev_attr_sensor1_fan_speed); if(therm_type == ADT7460) - device_create_file(&of_dev->dev, &dev_attr_gpu_fan_speed); + device_create_file(&of_dev->dev, &dev_attr_sensor2_fan_speed); #ifndef CONFIG_I2C_KEYWEST request_module("i2c-keywest"); @@ -597,17 +630,19 @@ static void __exit thermostat_exit(void) { if (of_dev) { - device_remove_file(&of_dev->dev, &dev_attr_cpu_temperature); - device_remove_file(&of_dev->dev, &dev_attr_gpu_temperature); - device_remove_file(&of_dev->dev, &dev_attr_cpu_limit); - device_remove_file(&of_dev->dev, &dev_attr_gpu_limit); + device_remove_file(&of_dev->dev, &dev_attr_sensor1_temperature); + device_remove_file(&of_dev->dev, &dev_attr_sensor2_temperature); + device_remove_file(&of_dev->dev, &dev_attr_sensor1_limit); + device_remove_file(&of_dev->dev, &dev_attr_sensor2_limit); + device_remove_file(&of_dev->dev, &dev_attr_sensor1_location); + device_remove_file(&of_dev->dev, &dev_attr_sensor2_location); device_remove_file(&of_dev->dev, &dev_attr_limit_adjust); device_remove_file(&of_dev->dev, &dev_attr_specified_fan_speed); - device_remove_file(&of_dev->dev, &dev_attr_cpu_fan_speed); + device_remove_file(&of_dev->dev, &dev_attr_sensor1_fan_speed); if(therm_type == ADT7460) device_remove_file(&of_dev->dev, - &dev_attr_gpu_fan_speed); + &dev_attr_sensor2_fan_speed); of_device_unregister(of_dev); } -- cgit v1.2.3 From 525a099771d348a25d12ef9c47aa8680c7317e35 Mon Sep 17 00:00:00 2001 From: NAKAMURA Kenta Date: Wed, 25 May 2005 19:28:38 -0400 Subject: [PATCH] sata_sil: new ID 1002:437A for ATI IXP400 --- drivers/scsi/sata_sil.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c index f0489dc302a..2b2ff48be39 100644 --- a/drivers/scsi/sata_sil.c +++ b/drivers/scsi/sata_sil.c @@ -82,6 +82,7 @@ static struct pci_device_id sil_pci_tbl[] = { { 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 }, { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, + { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, { } /* terminate list */ }; -- cgit v1.2.3 From 4c3a53d4108367f639e5e0fe9366dfd7679c5514 Mon Sep 17 00:00:00 2001 From: Francisco Javier Date: Wed, 25 May 2005 19:29:37 -0400 Subject: [PATCH] sata_promise: add PCI ID for FastTrak TX2200 2-ports --- drivers/scsi/sata_promise.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index 19a13e3590f..c4e9e029812 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -151,6 +151,8 @@ static struct ata_port_info pdc_port_info[] = { static struct pci_device_id pdc_ata_pci_tbl[] = { { PCI_VENDOR_ID_PROMISE, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_2037x }, + { PCI_VENDOR_ID_PROMISE, 0x3571, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_2037x }, { PCI_VENDOR_ID_PROMISE, 0x3373, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_2037x }, { PCI_VENDOR_ID_PROMISE, 0x3375, PCI_ANY_ID, PCI_ANY_ID, 0, 0, -- cgit v1.2.3