diff options
| author | Ingo Molnar <mingo@elte.hu> | 2008-07-28 15:14:43 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2008-07-28 15:14:43 -0400 |
| commit | 414f746d232d41ed6ae8632c4495ae795373c44b (patch) | |
| tree | 167f9bc8f139c6e82e6732b38c7a938b8a9d31cd /drivers | |
| parent | 5a7a201c51c324876d00a54e7208af6af12d1ca4 (diff) | |
| parent | c9272c4f9fbe2087beb3392f526dc5b19efaa56b (diff) | |
Merge branch 'linus' into cpus4096
Diffstat (limited to 'drivers')
378 files changed, 31470 insertions, 3685 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index d592dbb1d12a..b7f2963693a7 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c | |||
| @@ -272,6 +272,8 @@ static atomic_t c3_cpu_count; | |||
| 272 | /* Common C-state entry for C2, C3, .. */ | 272 | /* Common C-state entry for C2, C3, .. */ |
| 273 | static void acpi_cstate_enter(struct acpi_processor_cx *cstate) | 273 | static void acpi_cstate_enter(struct acpi_processor_cx *cstate) |
| 274 | { | 274 | { |
| 275 | /* Don't trace irqs off for idle */ | ||
| 276 | stop_critical_timings(); | ||
| 275 | if (cstate->entry_method == ACPI_CSTATE_FFH) { | 277 | if (cstate->entry_method == ACPI_CSTATE_FFH) { |
| 276 | /* Call into architectural FFH based C-state */ | 278 | /* Call into architectural FFH based C-state */ |
| 277 | acpi_processor_ffh_cstate_enter(cstate); | 279 | acpi_processor_ffh_cstate_enter(cstate); |
| @@ -284,6 +286,7 @@ static void acpi_cstate_enter(struct acpi_processor_cx *cstate) | |||
| 284 | gets asserted in time to freeze execution properly. */ | 286 | gets asserted in time to freeze execution properly. */ |
| 285 | unused = inl(acpi_gbl_FADT.xpm_timer_block.address); | 287 | unused = inl(acpi_gbl_FADT.xpm_timer_block.address); |
| 286 | } | 288 | } |
| 289 | start_critical_timings(); | ||
| 287 | } | 290 | } |
| 288 | #endif /* !CONFIG_CPU_IDLE */ | 291 | #endif /* !CONFIG_CPU_IDLE */ |
| 289 | 292 | ||
| @@ -1418,6 +1421,8 @@ static inline void acpi_idle_update_bm_rld(struct acpi_processor *pr, | |||
| 1418 | */ | 1421 | */ |
| 1419 | static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) | 1422 | static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) |
| 1420 | { | 1423 | { |
| 1424 | /* Don't trace irqs off for idle */ | ||
| 1425 | stop_critical_timings(); | ||
| 1421 | if (cx->entry_method == ACPI_CSTATE_FFH) { | 1426 | if (cx->entry_method == ACPI_CSTATE_FFH) { |
| 1422 | /* Call into architectural FFH based C-state */ | 1427 | /* Call into architectural FFH based C-state */ |
| 1423 | acpi_processor_ffh_cstate_enter(cx); | 1428 | acpi_processor_ffh_cstate_enter(cx); |
| @@ -1432,6 +1437,7 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) | |||
| 1432 | gets asserted in time to freeze execution properly. */ | 1437 | gets asserted in time to freeze execution properly. */ |
| 1433 | unused = inl(acpi_gbl_FADT.xpm_timer_block.address); | 1438 | unused = inl(acpi_gbl_FADT.xpm_timer_block.address); |
| 1434 | } | 1439 | } |
| 1440 | start_critical_timings(); | ||
| 1435 | } | 1441 | } |
| 1436 | 1442 | ||
| 1437 | /** | 1443 | /** |
diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index de8d186f5abf..2014253f6c88 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c | |||
| @@ -169,7 +169,7 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev) | |||
| 169 | 169 | ||
| 170 | irq = platform_get_irq(pdev, 0); | 170 | irq = platform_get_irq(pdev, 0); |
| 171 | if (irq) | 171 | if (irq) |
| 172 | set_irq_type(irq, IRQT_RISING); | 172 | set_irq_type(irq, IRQ_TYPE_EDGE_RISING); |
| 173 | 173 | ||
| 174 | /* Setup expansion bus chip selects */ | 174 | /* Setup expansion bus chip selects */ |
| 175 | *data->cs0_cfg = data->cs0_bits; | 175 | *data->cs0_cfg = data->cs0_bits; |
diff --git a/drivers/base/core.c b/drivers/base/core.c index 7d5c63c81a59..068aa1c9538c 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
| @@ -116,12 +116,10 @@ static void device_release(struct kobject *kobj) | |||
| 116 | dev->type->release(dev); | 116 | dev->type->release(dev); |
| 117 | else if (dev->class && dev->class->dev_release) | 117 | else if (dev->class && dev->class->dev_release) |
| 118 | dev->class->dev_release(dev); | 118 | dev->class->dev_release(dev); |
| 119 | else { | 119 | else |
| 120 | printk(KERN_ERR "Device '%s' does not have a release() " | 120 | WARN(1, KERN_ERR "Device '%s' does not have a release() " |
| 121 | "function, it is broken and must be fixed.\n", | 121 | "function, it is broken and must be fixed.\n", |
| 122 | dev->bus_id); | 122 | dev->bus_id); |
| 123 | WARN_ON(1); | ||
| 124 | } | ||
| 125 | } | 123 | } |
| 126 | 124 | ||
| 127 | static struct kobj_type device_ktype = { | 125 | static struct kobj_type device_ktype = { |
diff --git a/drivers/base/isa.c b/drivers/base/isa.c index d2222397a401..efd577574948 100644 --- a/drivers/base/isa.c +++ b/drivers/base/isa.c | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <linux/slab.h> | 7 | #include <linux/slab.h> |
| 8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
| 9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
| 10 | #include <linux/dma-mapping.h> | ||
| 10 | #include <linux/isa.h> | 11 | #include <linux/isa.h> |
| 11 | 12 | ||
| 12 | static struct device isa_bus = { | 13 | static struct device isa_bus = { |
| @@ -141,6 +142,9 @@ int isa_register_driver(struct isa_driver *isa_driver, unsigned int ndev) | |||
| 141 | isa_dev->dev.release = isa_dev_release; | 142 | isa_dev->dev.release = isa_dev_release; |
| 142 | isa_dev->id = id; | 143 | isa_dev->id = id; |
| 143 | 144 | ||
| 145 | isa_dev->dev.coherent_dma_mask = DMA_24BIT_MASK; | ||
| 146 | isa_dev->dev.dma_mask = &isa_dev->dev.coherent_dma_mask; | ||
| 147 | |||
| 144 | error = device_register(&isa_dev->dev); | 148 | error = device_register(&isa_dev->dev); |
| 145 | if (error) { | 149 | if (error) { |
| 146 | put_device(&isa_dev->dev); | 150 | put_device(&isa_dev->dev); |
diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 855ed1a9f97b..3ad49a00029f 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c | |||
| @@ -204,9 +204,8 @@ memory_block_action(struct memory_block *mem, unsigned long action) | |||
| 204 | } | 204 | } |
| 205 | break; | 205 | break; |
| 206 | default: | 206 | default: |
| 207 | printk(KERN_WARNING "%s(%p, %ld) unknown action: %ld\n", | 207 | WARN(1, KERN_WARNING "%s(%p, %ld) unknown action: %ld\n", |
| 208 | __func__, mem, action, action); | 208 | __func__, mem, action, action); |
| 209 | WARN_ON(1); | ||
| 210 | ret = -EINVAL; | 209 | ret = -EINVAL; |
| 211 | } | 210 | } |
| 212 | 211 | ||
diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 40fc14f03540..75dd6e22faff 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c | |||
| @@ -168,19 +168,16 @@ int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv) | |||
| 168 | int err = 0; | 168 | int err = 0; |
| 169 | 169 | ||
| 170 | if (!cls) { | 170 | if (!cls) { |
| 171 | printk(KERN_WARNING "sysdev: invalid class passed to " | 171 | WARN(1, KERN_WARNING "sysdev: invalid class passed to " |
| 172 | "sysdev_driver_register!\n"); | 172 | "sysdev_driver_register!\n"); |
| 173 | WARN_ON(1); | ||
| 174 | return -EINVAL; | 173 | return -EINVAL; |
| 175 | } | 174 | } |
| 176 | 175 | ||
| 177 | /* Check whether this driver has already been added to a class. */ | 176 | /* Check whether this driver has already been added to a class. */ |
| 178 | if (drv->entry.next && !list_empty(&drv->entry)) { | 177 | if (drv->entry.next && !list_empty(&drv->entry)) |
| 179 | printk(KERN_WARNING "sysdev: class %s: driver (%p) has already" | 178 | WARN(1, KERN_WARNING "sysdev: class %s: driver (%p) has already" |
| 180 | " been registered to a class, something is wrong, but " | 179 | " been registered to a class, something is wrong, but " |
| 181 | "will forge on!\n", cls->name, drv); | 180 | "will forge on!\n", cls->name, drv); |
| 182 | WARN_ON(1); | ||
| 183 | } | ||
| 184 | 181 | ||
| 185 | mutex_lock(&sysdev_drivers_lock); | 182 | mutex_lock(&sysdev_drivers_lock); |
| 186 | if (cls && kset_get(&cls->kset)) { | 183 | if (cls && kset_get(&cls->kset)) { |
| @@ -194,8 +191,7 @@ int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv) | |||
| 194 | } | 191 | } |
| 195 | } else { | 192 | } else { |
| 196 | err = -EINVAL; | 193 | err = -EINVAL; |
| 197 | printk(KERN_ERR "%s: invalid device class\n", __func__); | 194 | WARN(1, KERN_ERR "%s: invalid device class\n", __func__); |
| 198 | WARN_ON(1); | ||
| 199 | } | 195 | } |
| 200 | mutex_unlock(&sysdev_drivers_lock); | 196 | mutex_unlock(&sysdev_drivers_lock); |
| 201 | return err; | 197 | return err; |
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index 19b88504e960..ca7c72a486b2 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c | |||
| @@ -304,9 +304,9 @@ static ssize_t dsp56k_write(struct file *file, const char __user *buf, size_t co | |||
| 304 | } | 304 | } |
| 305 | 305 | ||
| 306 | static long dsp56k_ioctl(struct file *file, unsigned int cmd, | 306 | static long dsp56k_ioctl(struct file *file, unsigned int cmd, |
| 307 | unsigned long arg) | 307 | unsigned long arg) |
| 308 | { | 308 | { |
| 309 | int dev = iminor(inode) & 0x0f; | 309 | int dev = iminor(file->f_path.dentry->d_inode) & 0x0f; |
| 310 | void __user *argp = (void __user *)arg; | 310 | void __user *argp = (void __user *)arg; |
| 311 | 311 | ||
| 312 | switch(dev) | 312 | switch(dev) |
diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c index f9f72a211292..006be92ee3f3 100644 --- a/drivers/char/nwflash.c +++ b/drivers/char/nwflash.c | |||
| @@ -125,15 +125,15 @@ static ssize_t flash_read(struct file *file, char __user *buf, size_t size, | |||
| 125 | ssize_t ret; | 125 | ssize_t ret; |
| 126 | 126 | ||
| 127 | if (flashdebug) | 127 | if (flashdebug) |
| 128 | printk(KERN_DEBUG "flash_read: flash_read: offset=0x%lX, " | 128 | printk(KERN_DEBUG "flash_read: flash_read: offset=0x%llx, " |
| 129 | "buffer=%p, count=0x%X.\n", p, buf, count); | 129 | "buffer=%p, count=0x%zx.\n", *ppos, buf, size); |
| 130 | /* | 130 | /* |
| 131 | * We now lock against reads and writes. --rmk | 131 | * We now lock against reads and writes. --rmk |
| 132 | */ | 132 | */ |
| 133 | if (mutex_lock_interruptible(&nwflash_mutex)) | 133 | if (mutex_lock_interruptible(&nwflash_mutex)) |
| 134 | return -ERESTARTSYS; | 134 | return -ERESTARTSYS; |
| 135 | 135 | ||
| 136 | ret = simple_read_from_buffer(buf, size, ppos, FLASH_BASE, gbFlashSize); | 136 | ret = simple_read_from_buffer(buf, size, ppos, (void *)FLASH_BASE, gbFlashSize); |
| 137 | mutex_unlock(&nwflash_mutex); | 137 | mutex_unlock(&nwflash_mutex); |
| 138 | 138 | ||
| 139 | return ret; | 139 | return ret; |
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index dbefbb30ed44..d9799e2bcfbf 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c | |||
| @@ -144,6 +144,7 @@ static ssize_t rtc_read(struct file *file, char __user *buf, | |||
| 144 | size_t count, loff_t *ppos); | 144 | size_t count, loff_t *ppos); |
| 145 | 145 | ||
| 146 | static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg); | 146 | static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg); |
| 147 | static void rtc_get_rtc_time(struct rtc_time *rtc_tm); | ||
| 147 | 148 | ||
| 148 | #ifdef RTC_IRQ | 149 | #ifdef RTC_IRQ |
| 149 | static unsigned int rtc_poll(struct file *file, poll_table *wait); | 150 | static unsigned int rtc_poll(struct file *file, poll_table *wait); |
| @@ -235,7 +236,7 @@ static inline unsigned char rtc_is_updating(void) | |||
| 235 | * (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.) | 236 | * (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.) |
| 236 | */ | 237 | */ |
| 237 | 238 | ||
| 238 | irqreturn_t rtc_interrupt(int irq, void *dev_id) | 239 | static irqreturn_t rtc_interrupt(int irq, void *dev_id) |
| 239 | { | 240 | { |
| 240 | /* | 241 | /* |
| 241 | * Can be an alarm interrupt, update complete interrupt, | 242 | * Can be an alarm interrupt, update complete interrupt, |
| @@ -1303,7 +1304,7 @@ static int rtc_proc_open(struct inode *inode, struct file *file) | |||
| 1303 | } | 1304 | } |
| 1304 | #endif | 1305 | #endif |
| 1305 | 1306 | ||
| 1306 | void rtc_get_rtc_time(struct rtc_time *rtc_tm) | 1307 | static void rtc_get_rtc_time(struct rtc_time *rtc_tm) |
| 1307 | { | 1308 | { |
| 1308 | unsigned long uip_watchdog = jiffies, flags; | 1309 | unsigned long uip_watchdog = jiffies, flags; |
| 1309 | unsigned char ctrl; | 1310 | unsigned char ctrl; |
diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c index 4ba3aec9e1cd..7b0c35207d9b 100644 --- a/drivers/char/ser_a2232.c +++ b/drivers/char/ser_a2232.c | |||
| @@ -192,7 +192,7 @@ static inline void a2232_receive_char(struct a2232_port *port, int ch, int err) | |||
| 192 | Maybe one could implement a more efficient version by not only | 192 | Maybe one could implement a more efficient version by not only |
| 193 | transferring one character at a time. | 193 | transferring one character at a time. |
| 194 | */ | 194 | */ |
| 195 | struct tty_struct *tty = port->gs.tty; | 195 | struct tty_struct *tty = port->gs.port.tty; |
| 196 | 196 | ||
| 197 | #if 0 | 197 | #if 0 |
| 198 | switch(err) { | 198 | switch(err) { |
| @@ -226,7 +226,7 @@ static void a2232_disable_tx_interrupts(void *ptr) | |||
| 226 | 226 | ||
| 227 | /* Does this here really have to be? */ | 227 | /* Does this here really have to be? */ |
| 228 | local_irq_save(flags); | 228 | local_irq_save(flags); |
| 229 | port->gs.flags &= ~GS_TX_INTEN; | 229 | port->gs.port.flags &= ~GS_TX_INTEN; |
| 230 | local_irq_restore(flags); | 230 | local_irq_restore(flags); |
| 231 | } | 231 | } |
| 232 | 232 | ||
| @@ -242,7 +242,7 @@ static void a2232_enable_tx_interrupts(void *ptr) | |||
| 242 | 242 | ||
| 243 | /* Does this here really have to be? */ | 243 | /* Does this here really have to be? */ |
| 244 | local_irq_save(flags); | 244 | local_irq_save(flags); |
| 245 | port->gs.flags |= GS_TX_INTEN; | 245 | port->gs.port.flags |= GS_TX_INTEN; |
| 246 | local_irq_restore(flags); | 246 | local_irq_restore(flags); |
| 247 | } | 247 | } |
| 248 | 248 | ||
| @@ -276,9 +276,9 @@ static void a2232_shutdown_port(void *ptr) | |||
| 276 | 276 | ||
| 277 | local_irq_save(flags); | 277 | local_irq_save(flags); |
| 278 | 278 | ||
| 279 | port->gs.flags &= ~GS_ACTIVE; | 279 | port->gs.port.flags &= ~GS_ACTIVE; |
| 280 | 280 | ||
| 281 | if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) { | 281 | if (port->gs.port.tty && port->gs.port.tty->termios->c_cflag & HUPCL) { |
| 282 | /* Set DTR and RTS to Low, flush output. | 282 | /* Set DTR and RTS to Low, flush output. |
| 283 | The NetBSD driver "msc.c" does it this way. */ | 283 | The NetBSD driver "msc.c" does it this way. */ |
| 284 | stat->Command = ( (stat->Command & ~A2232CMD_CMask) | | 284 | stat->Command = ( (stat->Command & ~A2232CMD_CMask) | |
| @@ -309,7 +309,7 @@ static int a2232_set_real_termios(void *ptr) | |||
| 309 | volatile struct a2232status *status; | 309 | volatile struct a2232status *status; |
| 310 | volatile struct a2232memory *mem; | 310 | volatile struct a2232memory *mem; |
| 311 | 311 | ||
| 312 | if (!port->gs.tty || !port->gs.tty->termios) return 0; | 312 | if (!port->gs.port.tty || !port->gs.port.tty->termios) return 0; |
| 313 | 313 | ||
| 314 | status = a2232stat(port->which_a2232, port->which_port_on_a2232); | 314 | status = a2232stat(port->which_a2232, port->which_port_on_a2232); |
| 315 | mem = a2232mem(port->which_a2232); | 315 | mem = a2232mem(port->which_a2232); |
| @@ -345,7 +345,7 @@ static int a2232_set_real_termios(void *ptr) | |||
| 345 | } | 345 | } |
| 346 | a2232_param |= rate; | 346 | a2232_param |= rate; |
| 347 | 347 | ||
| 348 | cflag = port->gs.tty->termios->c_cflag; | 348 | cflag = port->gs.port.tty->termios->c_cflag; |
| 349 | 349 | ||
| 350 | // get character size | 350 | // get character size |
| 351 | chsize = cflag & CSIZE; | 351 | chsize = cflag & CSIZE; |
| @@ -382,7 +382,7 @@ static int a2232_set_real_termios(void *ptr) | |||
| 382 | the conventional way of inserting START/STOP characters | 382 | the conventional way of inserting START/STOP characters |
| 383 | by hand in throttle()/unthrottle(). | 383 | by hand in throttle()/unthrottle(). |
| 384 | */ | 384 | */ |
| 385 | softflow = !!( port->gs.tty->termios->c_iflag & IXOFF ); | 385 | softflow = !!( port->gs.port.tty->termios->c_iflag & IXOFF ); |
| 386 | 386 | ||
| 387 | // get Parity (Enabled/Disabled? If Enabled, Odd or Even?) | 387 | // get Parity (Enabled/Disabled? If Enabled, Odd or Even?) |
| 388 | parity = cflag & (PARENB | PARODD); | 388 | parity = cflag & (PARENB | PARODD); |
| @@ -400,9 +400,9 @@ static int a2232_set_real_termios(void *ptr) | |||
| 400 | /* Hmm. Maybe an own a2232_port structure | 400 | /* Hmm. Maybe an own a2232_port structure |
| 401 | member would be cleaner? */ | 401 | member would be cleaner? */ |
| 402 | if (cflag & CLOCAL) | 402 | if (cflag & CLOCAL) |
| 403 | port->gs.flags &= ~ASYNC_CHECK_CD; | 403 | port->gs.port.flags &= ~ASYNC_CHECK_CD; |
| 404 | else | 404 | else |
| 405 | port->gs.flags |= ASYNC_CHECK_CD; | 405 | port->gs.port.flags |= ASYNC_CHECK_CD; |
| 406 | 406 | ||
| 407 | 407 | ||
| 408 | /* Now we have all parameters and can go to set them: */ | 408 | /* Now we have all parameters and can go to set them: */ |
| @@ -482,18 +482,18 @@ static int a2232_open(struct tty_struct * tty, struct file * filp) | |||
| 482 | port = &a2232_ports[line]; | 482 | port = &a2232_ports[line]; |
| 483 | 483 | ||
| 484 | tty->driver_data = port; | 484 | tty->driver_data = port; |
| 485 | port->gs.tty = tty; | 485 | port->gs.port.tty = tty; |
| 486 | port->gs.count++; | 486 | port->gs.port.count++; |
| 487 | retval = gs_init_port(&port->gs); | 487 | retval = gs_init_port(&port->gs); |
| 488 | if (retval) { | 488 | if (retval) { |
| 489 | port->gs.count--; | 489 | port->gs.port.count--; |
| 490 | return retval; | 490 | return retval; |
| 491 | } | 491 | } |
| 492 | port->gs.flags |= GS_ACTIVE; | 492 | port->gs.port.flags |= GS_ACTIVE; |
| 493 | retval = gs_block_til_ready(port, filp); | 493 | retval = gs_block_til_ready(port, filp); |
| 494 | 494 | ||
| 495 | if (retval) { | 495 | if (retval) { |
| 496 | port->gs.count--; | 496 | port->gs.port.count--; |
| 497 | return retval; | 497 | return retval; |
| 498 | } | 498 | } |
| 499 | 499 | ||
| @@ -522,7 +522,7 @@ int ch, err, n, p; | |||
| 522 | for (p = 0; p < NUMLINES; p++){ /* for every port on this board */ | 522 | for (p = 0; p < NUMLINES; p++){ /* for every port on this board */ |
| 523 | err = 0; | 523 | err = 0; |
| 524 | port = &a2232_ports[n*NUMLINES+p]; | 524 | port = &a2232_ports[n*NUMLINES+p]; |
| 525 | if ( port->gs.flags & GS_ACTIVE ){ /* if the port is used */ | 525 | if ( port->gs.port.flags & GS_ACTIVE ){ /* if the port is used */ |
| 526 | 526 | ||
| 527 | status = a2232stat(n,p); | 527 | status = a2232stat(n,p); |
| 528 | 528 | ||
| @@ -577,8 +577,8 @@ int ch, err, n, p; | |||
| 577 | obuf = mem->OutBuf[p]; | 577 | obuf = mem->OutBuf[p]; |
| 578 | bufpos = status->OutHead; | 578 | bufpos = status->OutHead; |
| 579 | while ( (port->gs.xmit_cnt > 0) && | 579 | while ( (port->gs.xmit_cnt > 0) && |
| 580 | (!port->gs.tty->stopped) && | 580 | (!port->gs.port.tty->stopped) && |
| 581 | (!port->gs.tty->hw_stopped) ){ /* While there are chars to transmit */ | 581 | (!port->gs.port.tty->hw_stopped) ){ /* While there are chars to transmit */ |
| 582 | if (((bufpos+1) & A2232_IOBUFLENMASK) != status->OutTail) { /* If the A2232 buffer is not full */ | 582 | if (((bufpos+1) & A2232_IOBUFLENMASK) != status->OutTail) { /* If the A2232 buffer is not full */ |
| 583 | ch = port->gs.xmit_buf[port->gs.xmit_tail]; /* get the next char to transmit */ | 583 | ch = port->gs.xmit_buf[port->gs.xmit_tail]; /* get the next char to transmit */ |
| 584 | port->gs.xmit_tail = (port->gs.xmit_tail+1) & (SERIAL_XMIT_SIZE-1); /* modulo-addition for the gs.xmit_buf ring-buffer */ | 584 | port->gs.xmit_tail = (port->gs.xmit_tail+1) & (SERIAL_XMIT_SIZE-1); /* modulo-addition for the gs.xmit_buf ring-buffer */ |
| @@ -592,8 +592,8 @@ int ch, err, n, p; | |||
| 592 | status->OutHead = bufpos; | 592 | status->OutHead = bufpos; |
| 593 | 593 | ||
| 594 | /* WakeUp if output buffer runs low */ | 594 | /* WakeUp if output buffer runs low */ |
| 595 | if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) { | 595 | if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.port.tty) { |
| 596 | tty_wakeup(port->gs.tty); | 596 | tty_wakeup(port->gs.port.tty); |
| 597 | } | 597 | } |
| 598 | } // if the port is used | 598 | } // if the port is used |
| 599 | } // for every port on the board | 599 | } // for every port on the board |
| @@ -613,16 +613,16 @@ int ch, err, n, p; | |||
| 613 | struct a2232_port *port = &a2232_ports[n*7+p]; | 613 | struct a2232_port *port = &a2232_ports[n*7+p]; |
| 614 | port->cd_status = !(ncd & 1); /* ncd&1 <=> CD is now off */ | 614 | port->cd_status = !(ncd & 1); /* ncd&1 <=> CD is now off */ |
| 615 | 615 | ||
| 616 | if (!(port->gs.flags & ASYNC_CHECK_CD)) | 616 | if (!(port->gs.port.flags & ASYNC_CHECK_CD)) |
| 617 | ; /* Don't report DCD changes */ | 617 | ; /* Don't report DCD changes */ |
| 618 | else if (port->cd_status) { // if DCD on: DCD went UP! | 618 | else if (port->cd_status) { // if DCD on: DCD went UP! |
| 619 | 619 | ||
| 620 | /* Are we blocking in open?*/ | 620 | /* Are we blocking in open?*/ |
| 621 | wake_up_interruptible(&port->gs.open_wait); | 621 | wake_up_interruptible(&port->gs.port.open_wait); |
| 622 | } | 622 | } |
| 623 | else { // if DCD off: DCD went DOWN! | 623 | else { // if DCD off: DCD went DOWN! |
| 624 | if (port->gs.tty) | 624 | if (port->gs.port.tty) |
| 625 | tty_hangup (port->gs.tty); | 625 | tty_hangup (port->gs.port.tty); |
| 626 | } | 626 | } |
| 627 | 627 | ||
| 628 | } // if CD changed for this port | 628 | } // if CD changed for this port |
| @@ -655,8 +655,8 @@ static void a2232_init_portstructs(void) | |||
| 655 | #ifdef NEW_WRITE_LOCKING | 655 | #ifdef NEW_WRITE_LOCKING |
| 656 | mutex_init(&(port->gs.port_write_mutex)); | 656 | mutex_init(&(port->gs.port_write_mutex)); |
| 657 | #endif | 657 | #endif |
| 658 | init_waitqueue_head(&port->gs.open_wait); | 658 | init_waitqueue_head(&port->gs.port.open_wait); |
| 659 | init_waitqueue_head(&port->gs.close_wait); | 659 | init_waitqueue_head(&port->gs.port.close_wait); |
| 660 | } | 660 | } |
| 661 | } | 661 | } |
| 662 | 662 | ||
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index e1fc193d9396..ae766d868454 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
| @@ -580,91 +580,133 @@ void tpm_continue_selftest(struct tpm_chip *chip) | |||
| 580 | } | 580 | } |
| 581 | EXPORT_SYMBOL_GPL(tpm_continue_selftest); | 581 | EXPORT_SYMBOL_GPL(tpm_continue_selftest); |
| 582 | 582 | ||
| 583 | #define TPM_INTERNAL_RESULT_SIZE 200 | ||
| 584 | |||
| 583 | ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, | 585 | ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, |
| 584 | char *buf) | 586 | char *buf) |
| 585 | { | 587 | { |
| 586 | u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 35)]; | 588 | u8 *data; |
| 587 | ssize_t rc; | 589 | ssize_t rc; |
| 588 | 590 | ||
| 589 | struct tpm_chip *chip = dev_get_drvdata(dev); | 591 | struct tpm_chip *chip = dev_get_drvdata(dev); |
| 590 | if (chip == NULL) | 592 | if (chip == NULL) |
| 591 | return -ENODEV; | 593 | return -ENODEV; |
| 592 | 594 | ||
| 595 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | ||
| 596 | if (!data) | ||
| 597 | return -ENOMEM; | ||
| 598 | |||
| 593 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | 599 | memcpy(data, tpm_cap, sizeof(tpm_cap)); |
| 594 | data[TPM_CAP_IDX] = TPM_CAP_FLAG; | 600 | data[TPM_CAP_IDX] = TPM_CAP_FLAG; |
| 595 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM; | 601 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM; |
| 596 | 602 | ||
| 597 | rc = transmit_cmd(chip, data, sizeof(data), | 603 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, |
| 598 | "attemtping to determine the permanent state"); | 604 | "attemtping to determine the permanent enabled state"); |
| 599 | if (rc) | 605 | if (rc) { |
| 606 | kfree(data); | ||
| 600 | return 0; | 607 | return 0; |
| 601 | return sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_DISABLE_IDX]); | 608 | } |
| 609 | |||
| 610 | rc = sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_DISABLE_IDX]); | ||
| 611 | |||
| 612 | kfree(data); | ||
| 613 | return rc; | ||
| 602 | } | 614 | } |
| 603 | EXPORT_SYMBOL_GPL(tpm_show_enabled); | 615 | EXPORT_SYMBOL_GPL(tpm_show_enabled); |
| 604 | 616 | ||
| 605 | ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr, | 617 | ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr, |
| 606 | char *buf) | 618 | char *buf) |
| 607 | { | 619 | { |
| 608 | u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 35)]; | 620 | u8 *data; |
| 609 | ssize_t rc; | 621 | ssize_t rc; |
| 610 | 622 | ||
| 611 | struct tpm_chip *chip = dev_get_drvdata(dev); | 623 | struct tpm_chip *chip = dev_get_drvdata(dev); |
| 612 | if (chip == NULL) | 624 | if (chip == NULL) |
| 613 | return -ENODEV; | 625 | return -ENODEV; |
| 614 | 626 | ||
| 627 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | ||
| 628 | if (!data) | ||
| 629 | return -ENOMEM; | ||
| 630 | |||
| 615 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | 631 | memcpy(data, tpm_cap, sizeof(tpm_cap)); |
| 616 | data[TPM_CAP_IDX] = TPM_CAP_FLAG; | 632 | data[TPM_CAP_IDX] = TPM_CAP_FLAG; |
| 617 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM; | 633 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM; |
| 618 | 634 | ||
| 619 | rc = transmit_cmd(chip, data, sizeof(data), | 635 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, |
| 620 | "attemtping to determine the permanent state"); | 636 | "attemtping to determine the permanent active state"); |
| 621 | if (rc) | 637 | if (rc) { |
| 638 | kfree(data); | ||
| 622 | return 0; | 639 | return 0; |
| 623 | return sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_INACTIVE_IDX]); | 640 | } |
| 641 | |||
| 642 | rc = sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_INACTIVE_IDX]); | ||
| 643 | |||
| 644 | kfree(data); | ||
| 645 | return rc; | ||
| 624 | } | 646 | } |
| 625 | EXPORT_SYMBOL_GPL(tpm_show_active); | 647 | EXPORT_SYMBOL_GPL(tpm_show_active); |
| 626 | 648 | ||
| 627 | ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr, | 649 | ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr, |
| 628 | char *buf) | 650 | char *buf) |
| 629 | { | 651 | { |
| 630 | u8 data[sizeof(tpm_cap)]; | 652 | u8 *data; |
| 631 | ssize_t rc; | 653 | ssize_t rc; |
| 632 | 654 | ||
| 633 | struct tpm_chip *chip = dev_get_drvdata(dev); | 655 | struct tpm_chip *chip = dev_get_drvdata(dev); |
| 634 | if (chip == NULL) | 656 | if (chip == NULL) |
| 635 | return -ENODEV; | 657 | return -ENODEV; |
| 636 | 658 | ||
| 659 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | ||
| 660 | if (!data) | ||
| 661 | return -ENOMEM; | ||
| 662 | |||
| 637 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | 663 | memcpy(data, tpm_cap, sizeof(tpm_cap)); |
| 638 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | 664 | data[TPM_CAP_IDX] = TPM_CAP_PROP; |
| 639 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_OWNER; | 665 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_OWNER; |
| 640 | 666 | ||
| 641 | rc = transmit_cmd(chip, data, sizeof(data), | 667 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, |
| 642 | "attempting to determine the owner state"); | 668 | "attempting to determine the owner state"); |
| 643 | if (rc) | 669 | if (rc) { |
| 670 | kfree(data); | ||
| 644 | return 0; | 671 | return 0; |
| 645 | return sprintf(buf, "%d\n", data[TPM_GET_CAP_RET_BOOL_1_IDX]); | 672 | } |
| 673 | |||
| 674 | rc = sprintf(buf, "%d\n", data[TPM_GET_CAP_RET_BOOL_1_IDX]); | ||
| 675 | |||
| 676 | kfree(data); | ||
| 677 | return rc; | ||
| 646 | } | 678 | } |
| 647 | EXPORT_SYMBOL_GPL(tpm_show_owned); | 679 | EXPORT_SYMBOL_GPL(tpm_show_owned); |
| 648 | 680 | ||
| 649 | ssize_t tpm_show_temp_deactivated(struct device * dev, | 681 | ssize_t tpm_show_temp_deactivated(struct device * dev, |
| 650 | struct device_attribute * attr, char *buf) | 682 | struct device_attribute * attr, char *buf) |
| 651 | { | 683 | { |
| 652 | u8 data[sizeof(tpm_cap)]; | 684 | u8 *data; |
| 653 | ssize_t rc; | 685 | ssize_t rc; |
| 654 | 686 | ||
| 655 | struct tpm_chip *chip = dev_get_drvdata(dev); | 687 | struct tpm_chip *chip = dev_get_drvdata(dev); |
| 656 | if (chip == NULL) | 688 | if (chip == NULL) |
| 657 | return -ENODEV; | 689 | return -ENODEV; |
| 658 | 690 | ||
| 691 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | ||
| 692 | if (!data) | ||
| 693 | return -ENOMEM; | ||
| 694 | |||
| 659 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | 695 | memcpy(data, tpm_cap, sizeof(tpm_cap)); |
| 660 | data[TPM_CAP_IDX] = TPM_CAP_FLAG; | 696 | data[TPM_CAP_IDX] = TPM_CAP_FLAG; |
| 661 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_VOL; | 697 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_VOL; |
| 662 | 698 | ||
| 663 | rc = transmit_cmd(chip, data, sizeof(data), | 699 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, |
| 664 | "attempting to determine the temporary state"); | 700 | "attempting to determine the temporary state"); |
| 665 | if (rc) | 701 | if (rc) { |
| 702 | kfree(data); | ||
| 666 | return 0; | 703 | return 0; |
| 667 | return sprintf(buf, "%d\n", data[TPM_GET_CAP_TEMP_INACTIVE_IDX]); | 704 | } |
| 705 | |||
| 706 | rc = sprintf(buf, "%d\n", data[TPM_GET_CAP_TEMP_INACTIVE_IDX]); | ||
| 707 | |||
| 708 | kfree(data); | ||
| 709 | return rc; | ||
| 668 | } | 710 | } |
| 669 | EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); | 711 | EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); |
| 670 | 712 | ||
| @@ -678,7 +720,7 @@ static const u8 pcrread[] = { | |||
| 678 | ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, | 720 | ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, |
| 679 | char *buf) | 721 | char *buf) |
| 680 | { | 722 | { |
| 681 | u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(pcrread)), 30)]; | 723 | u8 *data; |
| 682 | ssize_t rc; | 724 | ssize_t rc; |
| 683 | int i, j, num_pcrs; | 725 | int i, j, num_pcrs; |
| 684 | __be32 index; | 726 | __be32 index; |
| @@ -688,21 +730,27 @@ ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, | |||
| 688 | if (chip == NULL) | 730 | if (chip == NULL) |
| 689 | return -ENODEV; | 731 | return -ENODEV; |
| 690 | 732 | ||
| 733 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | ||
| 734 | if (!data) | ||
| 735 | return -ENOMEM; | ||
| 736 | |||
| 691 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | 737 | memcpy(data, tpm_cap, sizeof(tpm_cap)); |
| 692 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | 738 | data[TPM_CAP_IDX] = TPM_CAP_PROP; |
| 693 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_PCR; | 739 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_PCR; |
| 694 | 740 | ||
| 695 | rc = transmit_cmd(chip, data, sizeof(data), | 741 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, |
| 696 | "attempting to determine the number of PCRS"); | 742 | "attempting to determine the number of PCRS"); |
| 697 | if (rc) | 743 | if (rc) { |
| 744 | kfree(data); | ||
| 698 | return 0; | 745 | return 0; |
| 746 | } | ||
| 699 | 747 | ||
| 700 | num_pcrs = be32_to_cpu(*((__be32 *) (data + 14))); | 748 | num_pcrs = be32_to_cpu(*((__be32 *) (data + 14))); |
| 701 | for (i = 0; i < num_pcrs; i++) { | 749 | for (i = 0; i < num_pcrs; i++) { |
| 702 | memcpy(data, pcrread, sizeof(pcrread)); | 750 | memcpy(data, pcrread, sizeof(pcrread)); |
| 703 | index = cpu_to_be32(i); | 751 | index = cpu_to_be32(i); |
| 704 | memcpy(data + 10, &index, 4); | 752 | memcpy(data + 10, &index, 4); |
| 705 | rc = transmit_cmd(chip, data, sizeof(data), | 753 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, |
| 706 | "attempting to read a PCR"); | 754 | "attempting to read a PCR"); |
| 707 | if (rc) | 755 | if (rc) |
| 708 | goto out; | 756 | goto out; |
| @@ -712,6 +760,7 @@ ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, | |||
| 712 | str += sprintf(str, "\n"); | 760 | str += sprintf(str, "\n"); |
| 713 | } | 761 | } |
| 714 | out: | 762 | out: |
| 763 | kfree(data); | ||
| 715 | return str - buf; | 764 | return str - buf; |
| 716 | } | 765 | } |
| 717 | EXPORT_SYMBOL_GPL(tpm_show_pcrs); | 766 | EXPORT_SYMBOL_GPL(tpm_show_pcrs); |
| @@ -795,7 +844,7 @@ static const u8 cap_version[] = { | |||
| 795 | ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, | 844 | ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, |
| 796 | char *buf) | 845 | char *buf) |
| 797 | { | 846 | { |
| 798 | u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(cap_version)), 30)]; | 847 | u8 *data; |
| 799 | ssize_t rc; | 848 | ssize_t rc; |
| 800 | char *str = buf; | 849 | char *str = buf; |
| 801 | 850 | ||
| @@ -803,21 +852,27 @@ ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, | |||
| 803 | if (chip == NULL) | 852 | if (chip == NULL) |
| 804 | return -ENODEV; | 853 | return -ENODEV; |
| 805 | 854 | ||
| 855 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | ||
| 856 | if (!data) | ||
| 857 | return -ENOMEM; | ||
| 858 | |||
| 806 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | 859 | memcpy(data, tpm_cap, sizeof(tpm_cap)); |
| 807 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | 860 | data[TPM_CAP_IDX] = TPM_CAP_PROP; |
| 808 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER; | 861 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER; |
| 809 | 862 | ||
| 810 | rc = transmit_cmd(chip, data, sizeof(data), | 863 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, |
| 811 | "attempting to determine the manufacturer"); | 864 | "attempting to determine the manufacturer"); |
| 812 | if (rc) | 865 | if (rc) { |
| 866 | kfree(data); | ||
| 813 | return 0; | 867 | return 0; |
| 868 | } | ||
| 814 | 869 | ||
| 815 | str += sprintf(str, "Manufacturer: 0x%x\n", | 870 | str += sprintf(str, "Manufacturer: 0x%x\n", |
| 816 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); | 871 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); |
| 817 | 872 | ||
| 818 | memcpy(data, cap_version, sizeof(cap_version)); | 873 | memcpy(data, cap_version, sizeof(cap_version)); |
| 819 | data[CAP_VERSION_IDX] = CAP_VERSION_1_1; | 874 | data[CAP_VERSION_IDX] = CAP_VERSION_1_1; |
| 820 | rc = transmit_cmd(chip, data, sizeof(data), | 875 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, |
| 821 | "attempting to determine the 1.1 version"); | 876 | "attempting to determine the 1.1 version"); |
| 822 | if (rc) | 877 | if (rc) |
| 823 | goto out; | 878 | goto out; |
| @@ -828,6 +883,7 @@ ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, | |||
| 828 | (int) data[17]); | 883 | (int) data[17]); |
| 829 | 884 | ||
| 830 | out: | 885 | out: |
| 886 | kfree(data); | ||
| 831 | return str - buf; | 887 | return str - buf; |
| 832 | } | 888 | } |
| 833 | EXPORT_SYMBOL_GPL(tpm_show_caps); | 889 | EXPORT_SYMBOL_GPL(tpm_show_caps); |
| @@ -835,7 +891,7 @@ EXPORT_SYMBOL_GPL(tpm_show_caps); | |||
| 835 | ssize_t tpm_show_caps_1_2(struct device * dev, | 891 | ssize_t tpm_show_caps_1_2(struct device * dev, |
| 836 | struct device_attribute * attr, char *buf) | 892 | struct device_attribute * attr, char *buf) |
| 837 | { | 893 | { |
| 838 | u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(cap_version)), 30)]; | 894 | u8 *data; |
| 839 | ssize_t len; | 895 | ssize_t len; |
| 840 | char *str = buf; | 896 | char *str = buf; |
| 841 | 897 | ||
| @@ -843,15 +899,20 @@ ssize_t tpm_show_caps_1_2(struct device * dev, | |||
| 843 | if (chip == NULL) | 899 | if (chip == NULL) |
| 844 | return -ENODEV; | 900 | return -ENODEV; |
| 845 | 901 | ||
| 902 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | ||
| 903 | if (!data) | ||
| 904 | return -ENOMEM; | ||
| 905 | |||
| 846 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | 906 | memcpy(data, tpm_cap, sizeof(tpm_cap)); |
| 847 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | 907 | data[TPM_CAP_IDX] = TPM_CAP_PROP; |
| 848 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER; | 908 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER; |
| 849 | 909 | ||
| 850 | if ((len = tpm_transmit(chip, data, sizeof(data))) <= | 910 | len = tpm_transmit(chip, data, TPM_INTERNAL_RESULT_SIZE); |
| 851 | TPM_ERROR_SIZE) { | 911 | if (len <= TPM_ERROR_SIZE) { |
| 852 | dev_dbg(chip->dev, "A TPM error (%d) occurred " | 912 | dev_dbg(chip->dev, "A TPM error (%d) occurred " |
| 853 | "attempting to determine the manufacturer\n", | 913 | "attempting to determine the manufacturer\n", |
| 854 | be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)))); | 914 | be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)))); |
| 915 | kfree(data); | ||
| 855 | return 0; | 916 | return 0; |
| 856 | } | 917 | } |
| 857 | 918 | ||
| @@ -861,8 +922,8 @@ ssize_t tpm_show_caps_1_2(struct device * dev, | |||
| 861 | memcpy(data, cap_version, sizeof(cap_version)); | 922 | memcpy(data, cap_version, sizeof(cap_version)); |
| 862 | data[CAP_VERSION_IDX] = CAP_VERSION_1_2; | 923 | data[CAP_VERSION_IDX] = CAP_VERSION_1_2; |
| 863 | 924 | ||
| 864 | if ((len = tpm_transmit(chip, data, sizeof(data))) <= | 925 | len = tpm_transmit(chip, data, TPM_INTERNAL_RESULT_SIZE); |
| 865 | TPM_ERROR_SIZE) { | 926 | if (len <= TPM_ERROR_SIZE) { |
| 866 | dev_err(chip->dev, "A TPM error (%d) occurred " | 927 | dev_err(chip->dev, "A TPM error (%d) occurred " |
| 867 | "attempting to determine the 1.2 version\n", | 928 | "attempting to determine the 1.2 version\n", |
| 868 | be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)))); | 929 | be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)))); |
| @@ -874,6 +935,7 @@ ssize_t tpm_show_caps_1_2(struct device * dev, | |||
| 874 | (int) data[19]); | 935 | (int) data[19]); |
| 875 | 936 | ||
| 876 | out: | 937 | out: |
| 938 | kfree(data); | ||
| 877 | return str - buf; | 939 | return str - buf; |
| 878 | } | 940 | } |
| 879 | EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); | 941 | EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); |
| @@ -966,7 +1028,7 @@ ssize_t tpm_write(struct file *file, const char __user *buf, | |||
| 966 | size_t size, loff_t *off) | 1028 | size_t size, loff_t *off) |
| 967 | { | 1029 | { |
| 968 | struct tpm_chip *chip = file->private_data; | 1030 | struct tpm_chip *chip = file->private_data; |
| 969 | int in_size = size, out_size; | 1031 | size_t in_size = size, out_size; |
| 970 | 1032 | ||
| 971 | /* cannot perform a write until the read has cleared | 1033 | /* cannot perform a write until the read has cleared |
| 972 | either via tpm_read or a user_read_timer timeout */ | 1034 | either via tpm_read or a user_read_timer timeout */ |
| @@ -1001,7 +1063,7 @@ ssize_t tpm_read(struct file *file, char __user *buf, | |||
| 1001 | size_t size, loff_t *off) | 1063 | size_t size, loff_t *off) |
| 1002 | { | 1064 | { |
| 1003 | struct tpm_chip *chip = file->private_data; | 1065 | struct tpm_chip *chip = file->private_data; |
| 1004 | int ret_size; | 1066 | ssize_t ret_size; |
| 1005 | 1067 | ||
| 1006 | del_singleshot_timer_sync(&chip->user_read_timer); | 1068 | del_singleshot_timer_sync(&chip->user_read_timer); |
| 1007 | flush_scheduled_work(); | 1069 | flush_scheduled_work(); |
diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c index 60a2d2630e36..68f052b42ed7 100644 --- a/drivers/char/tpm/tpm_bios.c +++ b/drivers/char/tpm/tpm_bios.c | |||
| @@ -448,7 +448,7 @@ out_free: | |||
| 448 | goto out; | 448 | goto out; |
| 449 | } | 449 | } |
| 450 | 450 | ||
| 451 | const struct file_operations tpm_ascii_bios_measurements_ops = { | 451 | static const struct file_operations tpm_ascii_bios_measurements_ops = { |
| 452 | .open = tpm_ascii_bios_measurements_open, | 452 | .open = tpm_ascii_bios_measurements_open, |
| 453 | .read = seq_read, | 453 | .read = seq_read, |
| 454 | .llseek = seq_lseek, | 454 | .llseek = seq_lseek, |
| @@ -486,7 +486,7 @@ out_free: | |||
| 486 | goto out; | 486 | goto out; |
| 487 | } | 487 | } |
| 488 | 488 | ||
| 489 | const struct file_operations tpm_binary_bios_measurements_ops = { | 489 | static const struct file_operations tpm_binary_bios_measurements_ops = { |
| 490 | .open = tpm_binary_bios_measurements_open, | 490 | .open = tpm_binary_bios_measurements_open, |
| 491 | .read = seq_read, | 491 | .read = seq_read, |
| 492 | .llseek = seq_lseek, | 492 | .llseek = seq_lseek, |
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index c7a977bc03e8..ed1879c0dd8d 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c | |||
| @@ -622,6 +622,7 @@ static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = { | |||
| 622 | {"ATM1200", 0}, /* Atmel */ | 622 | {"ATM1200", 0}, /* Atmel */ |
| 623 | {"IFX0102", 0}, /* Infineon */ | 623 | {"IFX0102", 0}, /* Infineon */ |
| 624 | {"BCM0101", 0}, /* Broadcom */ | 624 | {"BCM0101", 0}, /* Broadcom */ |
| 625 | {"BCM0102", 0}, /* Broadcom */ | ||
| 625 | {"NSC1200", 0}, /* National */ | 626 | {"NSC1200", 0}, /* National */ |
| 626 | {"ICO0102", 0}, /* Intel */ | 627 | {"ICO0102", 0}, /* Intel */ |
| 627 | /* Add new here */ | 628 | /* Add new here */ |
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c index 69c5afe97f19..1718b3c481db 100644 --- a/drivers/char/vme_scc.c +++ b/drivers/char/vme_scc.c | |||
| @@ -183,8 +183,8 @@ static void scc_init_portstructs(void) | |||
| 183 | #ifdef NEW_WRITE_LOCKING | 183 | #ifdef NEW_WRITE_LOCKING |
| 184 | port->gs.port_write_mutex = MUTEX; | 184 | port->gs.port_write_mutex = MUTEX; |
| 185 | #endif | 185 | #endif |
| 186 | init_waitqueue_head(&port->gs.open_wait); | 186 | init_waitqueue_head(&port->gs.port.open_wait); |
| 187 | init_waitqueue_head(&port->gs.close_wait); | 187 | init_waitqueue_head(&port->gs.port.close_wait); |
| 188 | } | 188 | } |
| 189 | } | 189 | } |
| 190 | 190 | ||
| @@ -422,7 +422,7 @@ static irqreturn_t scc_rx_int(int irq, void *data) | |||
| 422 | { | 422 | { |
| 423 | unsigned char ch; | 423 | unsigned char ch; |
| 424 | struct scc_port *port = data; | 424 | struct scc_port *port = data; |
| 425 | struct tty_struct *tty = port->gs.tty; | 425 | struct tty_struct *tty = port->gs.port.tty; |
| 426 | SCC_ACCESS_INIT(port); | 426 | SCC_ACCESS_INIT(port); |
| 427 | 427 | ||
| 428 | ch = SCCread_NB(RX_DATA_REG); | 428 | ch = SCCread_NB(RX_DATA_REG); |
| @@ -453,7 +453,7 @@ static irqreturn_t scc_rx_int(int irq, void *data) | |||
| 453 | static irqreturn_t scc_spcond_int(int irq, void *data) | 453 | static irqreturn_t scc_spcond_int(int irq, void *data) |
| 454 | { | 454 | { |
| 455 | struct scc_port *port = data; | 455 | struct scc_port *port = data; |
| 456 | struct tty_struct *tty = port->gs.tty; | 456 | struct tty_struct *tty = port->gs.port.tty; |
| 457 | unsigned char stat, ch, err; | 457 | unsigned char stat, ch, err; |
| 458 | int int_pending_mask = port->channel == CHANNEL_A ? | 458 | int int_pending_mask = port->channel == CHANNEL_A ? |
| 459 | IPR_A_RX : IPR_B_RX; | 459 | IPR_A_RX : IPR_B_RX; |
| @@ -500,7 +500,7 @@ static irqreturn_t scc_tx_int(int irq, void *data) | |||
| 500 | struct scc_port *port = data; | 500 | struct scc_port *port = data; |
| 501 | SCC_ACCESS_INIT(port); | 501 | SCC_ACCESS_INIT(port); |
| 502 | 502 | ||
| 503 | if (!port->gs.tty) { | 503 | if (!port->gs.port.tty) { |
| 504 | printk(KERN_WARNING "scc_tx_int with NULL tty!\n"); | 504 | printk(KERN_WARNING "scc_tx_int with NULL tty!\n"); |
| 505 | SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); | 505 | SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); |
| 506 | SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); | 506 | SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); |
| @@ -512,8 +512,9 @@ static irqreturn_t scc_tx_int(int irq, void *data) | |||
| 512 | SCCwrite(TX_DATA_REG, port->x_char); | 512 | SCCwrite(TX_DATA_REG, port->x_char); |
| 513 | port->x_char = 0; | 513 | port->x_char = 0; |
| 514 | } | 514 | } |
| 515 | else if ((port->gs.xmit_cnt <= 0) || port->gs.tty->stopped || | 515 | else if ((port->gs.xmit_cnt <= 0) || |
| 516 | port->gs.tty->hw_stopped) | 516 | port->gs.port.tty->stopped || |
| 517 | port->gs.port.tty->hw_stopped) | ||
| 517 | break; | 518 | break; |
| 518 | else { | 519 | else { |
| 519 | SCCwrite(TX_DATA_REG, port->gs.xmit_buf[port->gs.xmit_tail++]); | 520 | SCCwrite(TX_DATA_REG, port->gs.xmit_buf[port->gs.xmit_tail++]); |
| @@ -522,15 +523,15 @@ static irqreturn_t scc_tx_int(int irq, void *data) | |||
| 522 | break; | 523 | break; |
| 523 | } | 524 | } |
| 524 | } | 525 | } |
| 525 | if ((port->gs.xmit_cnt <= 0) || port->gs.tty->stopped || | 526 | if ((port->gs.xmit_cnt <= 0) || port->gs.port.tty->stopped || |
| 526 | port->gs.tty->hw_stopped) { | 527 | port->gs.port.tty->hw_stopped) { |
| 527 | /* disable tx interrupts */ | 528 | /* disable tx interrupts */ |
| 528 | SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); | 529 | SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); |
| 529 | SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); /* disable tx_int on next tx underrun? */ | 530 | SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); /* disable tx_int on next tx underrun? */ |
| 530 | port->gs.flags &= ~GS_TX_INTEN; | 531 | port->gs.port.flags &= ~GS_TX_INTEN; |
| 531 | } | 532 | } |
| 532 | if (port->gs.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) | 533 | if (port->gs.port.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) |
| 533 | tty_wakeup(port->gs.tty); | 534 | tty_wakeup(port->gs.port.tty); |
| 534 | 535 | ||
| 535 | SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); | 536 | SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); |
| 536 | return IRQ_HANDLED; | 537 | return IRQ_HANDLED; |
| @@ -550,14 +551,14 @@ static irqreturn_t scc_stat_int(int irq, void *data) | |||
| 550 | 551 | ||
| 551 | if (changed & SR_DCD) { | 552 | if (changed & SR_DCD) { |
| 552 | port->c_dcd = !!(sr & SR_DCD); | 553 | port->c_dcd = !!(sr & SR_DCD); |
| 553 | if (!(port->gs.flags & ASYNC_CHECK_CD)) | 554 | if (!(port->gs.port.flags & ASYNC_CHECK_CD)) |
| 554 | ; /* Don't report DCD changes */ | 555 | ; /* Don't report DCD changes */ |
| 555 | else if (port->c_dcd) { | 556 | else if (port->c_dcd) { |
| 556 | wake_up_interruptible(&port->gs.open_wait); | 557 | wake_up_interruptible(&port->gs.port.open_wait); |
| 557 | } | 558 | } |
| 558 | else { | 559 | else { |
| 559 | if (port->gs.tty) | 560 | if (port->gs.port.tty) |
| 560 | tty_hangup (port->gs.tty); | 561 | tty_hangup (port->gs.port.tty); |
| 561 | } | 562 | } |
| 562 | } | 563 | } |
| 563 | SCCwrite(COMMAND_REG, CR_EXTSTAT_RESET); | 564 | SCCwrite(COMMAND_REG, CR_EXTSTAT_RESET); |
| @@ -578,7 +579,7 @@ static void scc_disable_tx_interrupts(void *ptr) | |||
| 578 | 579 | ||
| 579 | local_irq_save(flags); | 580 | local_irq_save(flags); |
| 580 | SCCmod(INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); | 581 | SCCmod(INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); |
| 581 | port->gs.flags &= ~GS_TX_INTEN; | 582 | port->gs.port.flags &= ~GS_TX_INTEN; |
| 582 | local_irq_restore(flags); | 583 | local_irq_restore(flags); |
| 583 | } | 584 | } |
| 584 | 585 | ||
| @@ -636,8 +637,8 @@ static void scc_shutdown_port(void *ptr) | |||
| 636 | { | 637 | { |
| 637 | struct scc_port *port = ptr; | 638 | struct scc_port *port = ptr; |
| 638 | 639 | ||
| 639 | port->gs.flags &= ~ GS_ACTIVE; | 640 | port->gs.port.flags &= ~ GS_ACTIVE; |
| 640 | if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) { | 641 | if (port->gs.port.tty && port->gs.port.tty->termios->c_cflag & HUPCL) { |
| 641 | scc_setsignals (port, 0, 0); | 642 | scc_setsignals (port, 0, 0); |
| 642 | } | 643 | } |
| 643 | } | 644 | } |
| @@ -652,14 +653,14 @@ static int scc_set_real_termios (void *ptr) | |||
| 652 | struct scc_port *port = ptr; | 653 | struct scc_port *port = ptr; |
| 653 | SCC_ACCESS_INIT(port); | 654 | SCC_ACCESS_INIT(port); |
| 654 | 655 | ||
| 655 | if (!port->gs.tty || !port->gs.tty->termios) return 0; | 656 | if (!port->gs.port.tty || !port->gs.port.tty->termios) return 0; |
| 656 | 657 | ||
| 657 | channel = port->channel; | 658 | channel = port->channel; |
| 658 | 659 | ||
| 659 | if (channel == CHANNEL_A) | 660 | if (channel == CHANNEL_A) |
| 660 | return 0; /* Settings controlled by boot PROM */ | 661 | return 0; /* Settings controlled by boot PROM */ |
| 661 | 662 | ||
| 662 | cflag = port->gs.tty->termios->c_cflag; | 663 | cflag = port->gs.port.tty->termios->c_cflag; |
| 663 | baud = port->gs.baud; | 664 | baud = port->gs.baud; |
| 664 | chsize = (cflag & CSIZE) >> 4; | 665 | chsize = (cflag & CSIZE) >> 4; |
| 665 | 666 | ||
| @@ -678,9 +679,9 @@ static int scc_set_real_termios (void *ptr) | |||
| 678 | } | 679 | } |
| 679 | 680 | ||
| 680 | if (cflag & CLOCAL) | 681 | if (cflag & CLOCAL) |
| 681 | port->gs.flags &= ~ASYNC_CHECK_CD; | 682 | port->gs.port.flags &= ~ASYNC_CHECK_CD; |
| 682 | else | 683 | else |
| 683 | port->gs.flags |= ASYNC_CHECK_CD; | 684 | port->gs.port.flags |= ASYNC_CHECK_CD; |
| 684 | 685 | ||
| 685 | #ifdef CONFIG_MVME147_SCC | 686 | #ifdef CONFIG_MVME147_SCC |
| 686 | if (MACH_IS_MVME147) | 687 | if (MACH_IS_MVME147) |
| @@ -856,7 +857,7 @@ static int scc_open (struct tty_struct * tty, struct file * filp) | |||
| 856 | { COMMAND_REG, CR_EXTSTAT_RESET }, | 857 | { COMMAND_REG, CR_EXTSTAT_RESET }, |
| 857 | }; | 858 | }; |
| 858 | #endif | 859 | #endif |
| 859 | if (!(port->gs.flags & ASYNC_INITIALIZED)) { | 860 | if (!(port->gs.port.flags & ASYNC_INITIALIZED)) { |
| 860 | local_irq_save(flags); | 861 | local_irq_save(flags); |
| 861 | #if defined(CONFIG_MVME147_SCC) || defined(CONFIG_MVME162_SCC) | 862 | #if defined(CONFIG_MVME147_SCC) || defined(CONFIG_MVME162_SCC) |
| 862 | if (MACH_IS_MVME147 || MACH_IS_MVME16x) { | 863 | if (MACH_IS_MVME147 || MACH_IS_MVME16x) { |
| @@ -880,18 +881,18 @@ static int scc_open (struct tty_struct * tty, struct file * filp) | |||
| 880 | } | 881 | } |
| 881 | 882 | ||
| 882 | tty->driver_data = port; | 883 | tty->driver_data = port; |
| 883 | port->gs.tty = tty; | 884 | port->gs.port.tty = tty; |
| 884 | port->gs.count++; | 885 | port->gs.port.count++; |
| 885 | retval = gs_init_port(&port->gs); | 886 | retval = gs_init_port(&port->gs); |
| 886 | if (retval) { | 887 | if (retval) { |
| 887 | port->gs.count--; | 888 | port->gs.port.count--; |
| 888 | return retval; | 889 | return retval; |
| 889 | } | 890 | } |
| 890 | port->gs.flags |= GS_ACTIVE; | 891 | port->gs.port.flags |= GS_ACTIVE; |
| 891 | retval = gs_block_til_ready(port, filp); | 892 | retval = gs_block_til_ready(port, filp); |
| 892 | 893 | ||
| 893 | if (retval) { | 894 | if (retval) { |
| 894 | port->gs.count--; | 895 | port->gs.port.count--; |
| 895 | return retval; | 896 | return retval; |
| 896 | } | 897 | } |
| 897 | 898 | ||
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index b11943dadefd..681c15f42083 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c | |||
| @@ -99,6 +99,9 @@ struct talitos_private { | |||
| 99 | /* next channel to be assigned next incoming descriptor */ | 99 | /* next channel to be assigned next incoming descriptor */ |
| 100 | atomic_t last_chan; | 100 | atomic_t last_chan; |
| 101 | 101 | ||
| 102 | /* per-channel number of requests pending in channel h/w fifo */ | ||
| 103 | atomic_t *submit_count; | ||
| 104 | |||
| 102 | /* per-channel request fifo */ | 105 | /* per-channel request fifo */ |
| 103 | struct talitos_request **fifo; | 106 | struct talitos_request **fifo; |
| 104 | 107 | ||
| @@ -263,15 +266,15 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc, | |||
| 263 | 266 | ||
| 264 | spin_lock_irqsave(&priv->head_lock[ch], flags); | 267 | spin_lock_irqsave(&priv->head_lock[ch], flags); |
| 265 | 268 | ||
| 266 | head = priv->head[ch]; | 269 | if (!atomic_inc_not_zero(&priv->submit_count[ch])) { |
| 267 | request = &priv->fifo[ch][head]; | 270 | /* h/w fifo is full */ |
| 268 | |||
| 269 | if (request->desc) { | ||
| 270 | /* request queue is full */ | ||
| 271 | spin_unlock_irqrestore(&priv->head_lock[ch], flags); | 271 | spin_unlock_irqrestore(&priv->head_lock[ch], flags); |
| 272 | return -EAGAIN; | 272 | return -EAGAIN; |
| 273 | } | 273 | } |
| 274 | 274 | ||
| 275 | head = priv->head[ch]; | ||
| 276 | request = &priv->fifo[ch][head]; | ||
| 277 | |||
| 275 | /* map descriptor and save caller data */ | 278 | /* map descriptor and save caller data */ |
| 276 | request->dma_desc = dma_map_single(dev, desc, sizeof(*desc), | 279 | request->dma_desc = dma_map_single(dev, desc, sizeof(*desc), |
| 277 | DMA_BIDIRECTIONAL); | 280 | DMA_BIDIRECTIONAL); |
| @@ -335,6 +338,9 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch) | |||
| 335 | priv->tail[ch] = (tail + 1) & (priv->fifo_len - 1); | 338 | priv->tail[ch] = (tail + 1) & (priv->fifo_len - 1); |
| 336 | 339 | ||
| 337 | spin_unlock_irqrestore(&priv->tail_lock[ch], flags); | 340 | spin_unlock_irqrestore(&priv->tail_lock[ch], flags); |
| 341 | |||
| 342 | atomic_dec(&priv->submit_count[ch]); | ||
| 343 | |||
| 338 | saved_req.callback(dev, saved_req.desc, saved_req.context, | 344 | saved_req.callback(dev, saved_req.desc, saved_req.context, |
| 339 | status); | 345 | status); |
| 340 | /* channel may resume processing in single desc error case */ | 346 | /* channel may resume processing in single desc error case */ |
| @@ -842,7 +848,7 @@ static int sg_to_link_tbl(struct scatterlist *sg, int sg_count, | |||
| 842 | 848 | ||
| 843 | /* adjust (decrease) last one (or two) entry's len to cryptlen */ | 849 | /* adjust (decrease) last one (or two) entry's len to cryptlen */ |
| 844 | link_tbl_ptr--; | 850 | link_tbl_ptr--; |
| 845 | while (link_tbl_ptr->len <= (-cryptlen)) { | 851 | while (be16_to_cpu(link_tbl_ptr->len) <= (-cryptlen)) { |
| 846 | /* Empty this entry, and move to previous one */ | 852 | /* Empty this entry, and move to previous one */ |
| 847 | cryptlen += be16_to_cpu(link_tbl_ptr->len); | 853 | cryptlen += be16_to_cpu(link_tbl_ptr->len); |
| 848 | link_tbl_ptr->len = 0; | 854 | link_tbl_ptr->len = 0; |
| @@ -874,7 +880,7 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq, | |||
| 874 | unsigned int cryptlen = areq->cryptlen; | 880 | unsigned int cryptlen = areq->cryptlen; |
| 875 | unsigned int authsize = ctx->authsize; | 881 | unsigned int authsize = ctx->authsize; |
| 876 | unsigned int ivsize; | 882 | unsigned int ivsize; |
| 877 | int sg_count; | 883 | int sg_count, ret; |
| 878 | 884 | ||
| 879 | /* hmac key */ | 885 | /* hmac key */ |
| 880 | map_single_talitos_ptr(dev, &desc->ptr[0], ctx->authkeylen, &ctx->key, | 886 | map_single_talitos_ptr(dev, &desc->ptr[0], ctx->authkeylen, &ctx->key, |
| @@ -978,7 +984,12 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq, | |||
| 978 | map_single_talitos_ptr(dev, &desc->ptr[6], ivsize, ctx->iv, 0, | 984 | map_single_talitos_ptr(dev, &desc->ptr[6], ivsize, ctx->iv, 0, |
| 979 | DMA_FROM_DEVICE); | 985 | DMA_FROM_DEVICE); |
| 980 | 986 | ||
| 981 | return talitos_submit(dev, desc, callback, areq); | 987 | ret = talitos_submit(dev, desc, callback, areq); |
| 988 | if (ret != -EINPROGRESS) { | ||
| 989 | ipsec_esp_unmap(dev, edesc, areq); | ||
| 990 | kfree(edesc); | ||
| 991 | } | ||
| 992 | return ret; | ||
| 982 | } | 993 | } |
| 983 | 994 | ||
| 984 | 995 | ||
| @@ -1009,6 +1020,8 @@ static struct ipsec_esp_edesc *ipsec_esp_edesc_alloc(struct aead_request *areq, | |||
| 1009 | struct talitos_ctx *ctx = crypto_aead_ctx(authenc); | 1020 | struct talitos_ctx *ctx = crypto_aead_ctx(authenc); |
| 1010 | struct ipsec_esp_edesc *edesc; | 1021 | struct ipsec_esp_edesc *edesc; |
| 1011 | int src_nents, dst_nents, alloc_len, dma_len; | 1022 | int src_nents, dst_nents, alloc_len, dma_len; |
| 1023 | gfp_t flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : | ||
| 1024 | GFP_ATOMIC; | ||
| 1012 | 1025 | ||
| 1013 | if (areq->cryptlen + ctx->authsize > TALITOS_MAX_DATA_LEN) { | 1026 | if (areq->cryptlen + ctx->authsize > TALITOS_MAX_DATA_LEN) { |
| 1014 | dev_err(ctx->dev, "cryptlen exceeds h/w max limit\n"); | 1027 | dev_err(ctx->dev, "cryptlen exceeds h/w max limit\n"); |
| @@ -1022,7 +1035,7 @@ static struct ipsec_esp_edesc *ipsec_esp_edesc_alloc(struct aead_request *areq, | |||
| 1022 | dst_nents = src_nents; | 1035 | dst_nents = src_nents; |
| 1023 | } else { | 1036 | } else { |
| 1024 | dst_nents = sg_count(areq->dst, areq->cryptlen + ctx->authsize); | 1037 | dst_nents = sg_count(areq->dst, areq->cryptlen + ctx->authsize); |
| 1025 | dst_nents = (dst_nents == 1) ? 0 : src_nents; | 1038 | dst_nents = (dst_nents == 1) ? 0 : dst_nents; |
| 1026 | } | 1039 | } |
| 1027 | 1040 | ||
| 1028 | /* | 1041 | /* |
| @@ -1040,7 +1053,7 @@ static struct ipsec_esp_edesc *ipsec_esp_edesc_alloc(struct aead_request *areq, | |||
| 1040 | alloc_len += icv_stashing ? ctx->authsize : 0; | 1053 | alloc_len += icv_stashing ? ctx->authsize : 0; |
| 1041 | } | 1054 | } |
| 1042 | 1055 | ||
| 1043 | edesc = kmalloc(alloc_len, GFP_DMA); | 1056 | edesc = kmalloc(alloc_len, GFP_DMA | flags); |
| 1044 | if (!edesc) { | 1057 | if (!edesc) { |
| 1045 | dev_err(ctx->dev, "could not allocate edescriptor\n"); | 1058 | dev_err(ctx->dev, "could not allocate edescriptor\n"); |
| 1046 | return ERR_PTR(-ENOMEM); | 1059 | return ERR_PTR(-ENOMEM); |
| @@ -1337,6 +1350,7 @@ static int __devexit talitos_remove(struct of_device *ofdev) | |||
| 1337 | if (hw_supports(dev, DESC_HDR_SEL0_RNG)) | 1350 | if (hw_supports(dev, DESC_HDR_SEL0_RNG)) |
| 1338 | talitos_unregister_rng(dev); | 1351 | talitos_unregister_rng(dev); |
| 1339 | 1352 | ||
| 1353 | kfree(priv->submit_count); | ||
| 1340 | kfree(priv->tail); | 1354 | kfree(priv->tail); |
| 1341 | kfree(priv->head); | 1355 | kfree(priv->head); |
| 1342 | 1356 | ||
| @@ -1466,9 +1480,6 @@ static int talitos_probe(struct of_device *ofdev, | |||
| 1466 | goto err_out; | 1480 | goto err_out; |
| 1467 | } | 1481 | } |
| 1468 | 1482 | ||
| 1469 | of_node_put(np); | ||
| 1470 | np = NULL; | ||
| 1471 | |||
| 1472 | priv->head_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels, | 1483 | priv->head_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels, |
| 1473 | GFP_KERNEL); | 1484 | GFP_KERNEL); |
| 1474 | priv->tail_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels, | 1485 | priv->tail_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels, |
| @@ -1504,6 +1515,16 @@ static int talitos_probe(struct of_device *ofdev, | |||
| 1504 | } | 1515 | } |
| 1505 | } | 1516 | } |
| 1506 | 1517 | ||
| 1518 | priv->submit_count = kmalloc(sizeof(atomic_t) * priv->num_channels, | ||
| 1519 | GFP_KERNEL); | ||
| 1520 | if (!priv->submit_count) { | ||
| 1521 | dev_err(dev, "failed to allocate fifo submit count space\n"); | ||
| 1522 | err = -ENOMEM; | ||
| 1523 | goto err_out; | ||
| 1524 | } | ||
| 1525 | for (i = 0; i < priv->num_channels; i++) | ||
| 1526 | atomic_set(&priv->submit_count[i], -priv->chfifo_len); | ||
| 1527 | |||
| 1507 | priv->head = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL); | 1528 | priv->head = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL); |
| 1508 | priv->tail = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL); | 1529 | priv->tail = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL); |
| 1509 | if (!priv->head || !priv->tail) { | 1530 | if (!priv->head || !priv->tail) { |
| @@ -1559,8 +1580,6 @@ static int talitos_probe(struct of_device *ofdev, | |||
| 1559 | 1580 | ||
| 1560 | err_out: | 1581 | err_out: |
| 1561 | talitos_remove(ofdev); | 1582 | talitos_remove(ofdev); |
| 1562 | if (np) | ||
| 1563 | of_node_put(np); | ||
| 1564 | 1583 | ||
| 1565 | return err; | 1584 | return err; |
| 1566 | } | 1585 | } |
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig index 76f26710fc16..fa6d6abefd4d 100644 --- a/drivers/firewire/Kconfig +++ b/drivers/firewire/Kconfig | |||
| @@ -16,8 +16,13 @@ config FIREWIRE | |||
| 16 | enable the new stack. | 16 | enable the new stack. |
| 17 | 17 | ||
| 18 | To compile this driver as a module, say M here: the module will be | 18 | To compile this driver as a module, say M here: the module will be |
| 19 | called firewire-core. It functionally replaces ieee1394, raw1394, | 19 | called firewire-core. |
| 20 | and video1394. | 20 | |
| 21 | This module functionally replaces ieee1394, raw1394, and video1394. | ||
| 22 | To access it from application programs, you generally need at least | ||
| 23 | libraw1394 version 2. IIDC/DCAM applications also need libdc1394 | ||
| 24 | version 2. No libraries are required to access storage devices | ||
| 25 | through the firewire-sbp2 driver. | ||
| 21 | 26 | ||
| 22 | config FIREWIRE_OHCI | 27 | config FIREWIRE_OHCI |
| 23 | tristate "OHCI-1394 controllers" | 28 | tristate "OHCI-1394 controllers" |
diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c index da873d795aad..bbd73a406e53 100644 --- a/drivers/firewire/fw-card.c +++ b/drivers/firewire/fw-card.c | |||
| @@ -539,7 +539,7 @@ fw_core_remove_card(struct fw_card *card) | |||
| 539 | wait_for_completion(&card->done); | 539 | wait_for_completion(&card->done); |
| 540 | 540 | ||
| 541 | cancel_delayed_work_sync(&card->work); | 541 | cancel_delayed_work_sync(&card->work); |
| 542 | fw_flush_transactions(card); | 542 | WARN_ON(!list_empty(&card->transaction_list)); |
| 543 | del_timer_sync(&card->flush_timer); | 543 | del_timer_sync(&card->flush_timer); |
| 544 | } | 544 | } |
| 545 | EXPORT_SYMBOL(fw_core_remove_card); | 545 | EXPORT_SYMBOL(fw_core_remove_card); |
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c index c639915fc3cb..bc81d6fcd2fd 100644 --- a/drivers/firewire/fw-cdev.c +++ b/drivers/firewire/fw-cdev.c | |||
| @@ -382,9 +382,9 @@ complete_transaction(struct fw_card *card, int rcode, | |||
| 382 | 382 | ||
| 383 | response->response.type = FW_CDEV_EVENT_RESPONSE; | 383 | response->response.type = FW_CDEV_EVENT_RESPONSE; |
| 384 | response->response.rcode = rcode; | 384 | response->response.rcode = rcode; |
| 385 | queue_event(client, &response->event, | 385 | queue_event(client, &response->event, &response->response, |
| 386 | &response->response, sizeof(response->response), | 386 | sizeof(response->response) + response->response.length, |
| 387 | response->response.data, response->response.length); | 387 | NULL, 0); |
| 388 | } | 388 | } |
| 389 | 389 | ||
| 390 | static int ioctl_send_request(struct client *client, void *buffer) | 390 | static int ioctl_send_request(struct client *client, void *buffer) |
diff --git a/drivers/firewire/fw-iso.c b/drivers/firewire/fw-iso.c index bcbe794a3ea5..e14c03dc0065 100644 --- a/drivers/firewire/fw-iso.c +++ b/drivers/firewire/fw-iso.c | |||
| @@ -50,7 +50,7 @@ fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card, | |||
| 50 | 50 | ||
| 51 | address = dma_map_page(card->device, buffer->pages[i], | 51 | address = dma_map_page(card->device, buffer->pages[i], |
| 52 | 0, PAGE_SIZE, direction); | 52 | 0, PAGE_SIZE, direction); |
| 53 | if (dma_mapping_error(address)) { | 53 | if (dma_mapping_error(card->device, address)) { |
| 54 | __free_page(buffer->pages[i]); | 54 | __free_page(buffer->pages[i]); |
| 55 | goto out_pages; | 55 | goto out_pages; |
| 56 | } | 56 | } |
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 333b12544dd1..251416f2148f 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c | |||
| @@ -171,7 +171,6 @@ struct iso_context { | |||
| 171 | struct fw_ohci { | 171 | struct fw_ohci { |
| 172 | struct fw_card card; | 172 | struct fw_card card; |
| 173 | 173 | ||
| 174 | u32 version; | ||
| 175 | __iomem char *registers; | 174 | __iomem char *registers; |
| 176 | dma_addr_t self_id_bus; | 175 | dma_addr_t self_id_bus; |
| 177 | __le32 *self_id_cpu; | 176 | __le32 *self_id_cpu; |
| @@ -180,6 +179,8 @@ struct fw_ohci { | |||
| 180 | int generation; | 179 | int generation; |
| 181 | int request_generation; /* for timestamping incoming requests */ | 180 | int request_generation; /* for timestamping incoming requests */ |
| 182 | u32 bus_seconds; | 181 | u32 bus_seconds; |
| 182 | |||
| 183 | bool use_dualbuffer; | ||
| 183 | bool old_uninorth; | 184 | bool old_uninorth; |
| 184 | bool bus_reset_packet_quirk; | 185 | bool bus_reset_packet_quirk; |
| 185 | 186 | ||
| @@ -953,7 +954,7 @@ at_context_queue_packet(struct context *ctx, struct fw_packet *packet) | |||
| 953 | payload_bus = | 954 | payload_bus = |
| 954 | dma_map_single(ohci->card.device, packet->payload, | 955 | dma_map_single(ohci->card.device, packet->payload, |
| 955 | packet->payload_length, DMA_TO_DEVICE); | 956 | packet->payload_length, DMA_TO_DEVICE); |
| 956 | if (dma_mapping_error(payload_bus)) { | 957 | if (dma_mapping_error(ohci->card.device, payload_bus)) { |
| 957 | packet->ack = RCODE_SEND_ERROR; | 958 | packet->ack = RCODE_SEND_ERROR; |
| 958 | return -1; | 959 | return -1; |
| 959 | } | 960 | } |
| @@ -1885,7 +1886,7 @@ ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size) | |||
| 1885 | } else { | 1886 | } else { |
| 1886 | mask = &ohci->ir_context_mask; | 1887 | mask = &ohci->ir_context_mask; |
| 1887 | list = ohci->ir_context_list; | 1888 | list = ohci->ir_context_list; |
| 1888 | if (ohci->version >= OHCI_VERSION_1_1) | 1889 | if (ohci->use_dualbuffer) |
| 1889 | callback = handle_ir_dualbuffer_packet; | 1890 | callback = handle_ir_dualbuffer_packet; |
| 1890 | else | 1891 | else |
| 1891 | callback = handle_ir_packet_per_buffer; | 1892 | callback = handle_ir_packet_per_buffer; |
| @@ -1949,7 +1950,7 @@ static int ohci_start_iso(struct fw_iso_context *base, | |||
| 1949 | } else { | 1950 | } else { |
| 1950 | index = ctx - ohci->ir_context_list; | 1951 | index = ctx - ohci->ir_context_list; |
| 1951 | control = IR_CONTEXT_ISOCH_HEADER; | 1952 | control = IR_CONTEXT_ISOCH_HEADER; |
| 1952 | if (ohci->version >= OHCI_VERSION_1_1) | 1953 | if (ohci->use_dualbuffer) |
| 1953 | control |= IR_CONTEXT_DUAL_BUFFER_MODE; | 1954 | control |= IR_CONTEXT_DUAL_BUFFER_MODE; |
| 1954 | match = (tags << 28) | (sync << 8) | ctx->base.channel; | 1955 | match = (tags << 28) | (sync << 8) | ctx->base.channel; |
| 1955 | if (cycle >= 0) { | 1956 | if (cycle >= 0) { |
| @@ -2279,7 +2280,7 @@ ohci_queue_iso(struct fw_iso_context *base, | |||
| 2279 | spin_lock_irqsave(&ctx->context.ohci->lock, flags); | 2280 | spin_lock_irqsave(&ctx->context.ohci->lock, flags); |
| 2280 | if (base->type == FW_ISO_CONTEXT_TRANSMIT) | 2281 | if (base->type == FW_ISO_CONTEXT_TRANSMIT) |
| 2281 | retval = ohci_queue_iso_transmit(base, packet, buffer, payload); | 2282 | retval = ohci_queue_iso_transmit(base, packet, buffer, payload); |
| 2282 | else if (ctx->context.ohci->version >= OHCI_VERSION_1_1) | 2283 | else if (ctx->context.ohci->use_dualbuffer) |
| 2283 | retval = ohci_queue_iso_receive_dualbuffer(base, packet, | 2284 | retval = ohci_queue_iso_receive_dualbuffer(base, packet, |
| 2284 | buffer, payload); | 2285 | buffer, payload); |
| 2285 | else | 2286 | else |
| @@ -2341,7 +2342,7 @@ static int __devinit | |||
| 2341 | pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) | 2342 | pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) |
| 2342 | { | 2343 | { |
| 2343 | struct fw_ohci *ohci; | 2344 | struct fw_ohci *ohci; |
| 2344 | u32 bus_options, max_receive, link_speed; | 2345 | u32 bus_options, max_receive, link_speed, version; |
| 2345 | u64 guid; | 2346 | u64 guid; |
| 2346 | int err; | 2347 | int err; |
| 2347 | size_t size; | 2348 | size_t size; |
| @@ -2366,12 +2367,6 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) | |||
| 2366 | pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0); | 2367 | pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0); |
| 2367 | pci_set_drvdata(dev, ohci); | 2368 | pci_set_drvdata(dev, ohci); |
| 2368 | 2369 | ||
| 2369 | #if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) | ||
| 2370 | ohci->old_uninorth = dev->vendor == PCI_VENDOR_ID_APPLE && | ||
| 2371 | dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW; | ||
| 2372 | #endif | ||
| 2373 | ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI; | ||
| 2374 | |||
| 2375 | spin_lock_init(&ohci->lock); | 2370 | spin_lock_init(&ohci->lock); |
| 2376 | 2371 | ||
| 2377 | tasklet_init(&ohci->bus_reset_tasklet, | 2372 | tasklet_init(&ohci->bus_reset_tasklet, |
| @@ -2390,6 +2385,23 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) | |||
| 2390 | goto fail_iomem; | 2385 | goto fail_iomem; |
| 2391 | } | 2386 | } |
| 2392 | 2387 | ||
| 2388 | version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff; | ||
| 2389 | ohci->use_dualbuffer = version >= OHCI_VERSION_1_1; | ||
| 2390 | |||
| 2391 | /* x86-32 currently doesn't use highmem for dma_alloc_coherent */ | ||
| 2392 | #if !defined(CONFIG_X86_32) | ||
| 2393 | /* dual-buffer mode is broken with descriptor addresses above 2G */ | ||
| 2394 | if (dev->vendor == PCI_VENDOR_ID_TI && | ||
| 2395 | dev->device == PCI_DEVICE_ID_TI_TSB43AB22) | ||
| 2396 | ohci->use_dualbuffer = false; | ||
| 2397 | #endif | ||
| 2398 | |||
| 2399 | #if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) | ||
| 2400 | ohci->old_uninorth = dev->vendor == PCI_VENDOR_ID_APPLE && | ||
| 2401 | dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW; | ||
| 2402 | #endif | ||
| 2403 | ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI; | ||
| 2404 | |||
| 2393 | ar_context_init(&ohci->ar_request_ctx, ohci, | 2405 | ar_context_init(&ohci->ar_request_ctx, ohci, |
| 2394 | OHCI1394_AsReqRcvContextControlSet); | 2406 | OHCI1394_AsReqRcvContextControlSet); |
| 2395 | 2407 | ||
| @@ -2441,9 +2453,8 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) | |||
| 2441 | if (err < 0) | 2453 | if (err < 0) |
| 2442 | goto fail_self_id; | 2454 | goto fail_self_id; |
| 2443 | 2455 | ||
| 2444 | ohci->version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff; | ||
| 2445 | fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n", | 2456 | fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n", |
| 2446 | dev->dev.bus_id, ohci->version >> 16, ohci->version & 0xff); | 2457 | dev->dev.bus_id, version >> 16, version & 0xff); |
| 2447 | return 0; | 2458 | return 0; |
| 2448 | 2459 | ||
| 2449 | fail_self_id: | 2460 | fail_self_id: |
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index 53fc5a641e6d..aaff50ebba1d 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c | |||
| @@ -543,7 +543,7 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, | |||
| 543 | orb->response_bus = | 543 | orb->response_bus = |
| 544 | dma_map_single(device->card->device, &orb->response, | 544 | dma_map_single(device->card->device, &orb->response, |
| 545 | sizeof(orb->response), DMA_FROM_DEVICE); | 545 | sizeof(orb->response), DMA_FROM_DEVICE); |
| 546 | if (dma_mapping_error(orb->response_bus)) | 546 | if (dma_mapping_error(device->card->device, orb->response_bus)) |
| 547 | goto fail_mapping_response; | 547 | goto fail_mapping_response; |
| 548 | 548 | ||
| 549 | orb->request.response.high = 0; | 549 | orb->request.response.high = 0; |
| @@ -577,7 +577,7 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, | |||
| 577 | orb->base.request_bus = | 577 | orb->base.request_bus = |
| 578 | dma_map_single(device->card->device, &orb->request, | 578 | dma_map_single(device->card->device, &orb->request, |
| 579 | sizeof(orb->request), DMA_TO_DEVICE); | 579 | sizeof(orb->request), DMA_TO_DEVICE); |
| 580 | if (dma_mapping_error(orb->base.request_bus)) | 580 | if (dma_mapping_error(device->card->device, orb->base.request_bus)) |
| 581 | goto fail_mapping_request; | 581 | goto fail_mapping_request; |
| 582 | 582 | ||
| 583 | sbp2_send_orb(&orb->base, lu, node_id, generation, | 583 | sbp2_send_orb(&orb->base, lu, node_id, generation, |
| @@ -1424,7 +1424,7 @@ sbp2_map_scatterlist(struct sbp2_command_orb *orb, struct fw_device *device, | |||
| 1424 | orb->page_table_bus = | 1424 | orb->page_table_bus = |
| 1425 | dma_map_single(device->card->device, orb->page_table, | 1425 | dma_map_single(device->card->device, orb->page_table, |
| 1426 | sizeof(orb->page_table), DMA_TO_DEVICE); | 1426 | sizeof(orb->page_table), DMA_TO_DEVICE); |
| 1427 | if (dma_mapping_error(orb->page_table_bus)) | 1427 | if (dma_mapping_error(device->card->device, orb->page_table_bus)) |
| 1428 | goto fail_page_table; | 1428 | goto fail_page_table; |
| 1429 | 1429 | ||
| 1430 | /* | 1430 | /* |
| @@ -1509,7 +1509,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) | |||
| 1509 | orb->base.request_bus = | 1509 | orb->base.request_bus = |
| 1510 | dma_map_single(device->card->device, &orb->request, | 1510 | dma_map_single(device->card->device, &orb->request, |
| 1511 | sizeof(orb->request), DMA_TO_DEVICE); | 1511 | sizeof(orb->request), DMA_TO_DEVICE); |
| 1512 | if (dma_mapping_error(orb->base.request_bus)) | 1512 | if (dma_mapping_error(device->card->device, orb->base.request_bus)) |
| 1513 | goto out; | 1513 | goto out; |
| 1514 | 1514 | ||
| 1515 | sbp2_send_orb(&orb->base, lu, lu->tgt->node_id, lu->generation, | 1515 | sbp2_send_orb(&orb->base, lu, lu->tgt->node_id, lu->generation, |
diff --git a/drivers/firewire/fw-topology.c b/drivers/firewire/fw-topology.c index 213b0ff8f3d6..c1b81077c4a8 100644 --- a/drivers/firewire/fw-topology.c +++ b/drivers/firewire/fw-topology.c | |||
| @@ -510,8 +510,6 @@ fw_core_handle_bus_reset(struct fw_card *card, | |||
| 510 | struct fw_node *local_node; | 510 | struct fw_node *local_node; |
| 511 | unsigned long flags; | 511 | unsigned long flags; |
| 512 | 512 | ||
| 513 | fw_flush_transactions(card); | ||
| 514 | |||
| 515 | spin_lock_irqsave(&card->lock, flags); | 513 | spin_lock_irqsave(&card->lock, flags); |
| 516 | 514 | ||
| 517 | /* | 515 | /* |
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c index 40db80752272..e5d1a0b64fcf 100644 --- a/drivers/firewire/fw-transaction.c +++ b/drivers/firewire/fw-transaction.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
| 23 | #include <linux/kref.h> | 23 | #include <linux/kref.h> |
| 24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
| 25 | #include <linux/mutex.h> | ||
| 25 | #include <linux/init.h> | 26 | #include <linux/init.h> |
| 26 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
| 27 | #include <linux/pci.h> | 28 | #include <linux/pci.h> |
| @@ -151,7 +152,7 @@ transmit_complete_callback(struct fw_packet *packet, | |||
| 151 | 152 | ||
| 152 | static void | 153 | static void |
| 153 | fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, | 154 | fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, |
| 154 | int node_id, int source_id, int generation, int speed, | 155 | int destination_id, int source_id, int generation, int speed, |
| 155 | unsigned long long offset, void *payload, size_t length) | 156 | unsigned long long offset, void *payload, size_t length) |
| 156 | { | 157 | { |
| 157 | int ext_tcode; | 158 | int ext_tcode; |
| @@ -166,7 +167,7 @@ fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, | |||
| 166 | HEADER_RETRY(RETRY_X) | | 167 | HEADER_RETRY(RETRY_X) | |
| 167 | HEADER_TLABEL(tlabel) | | 168 | HEADER_TLABEL(tlabel) | |
| 168 | HEADER_TCODE(tcode) | | 169 | HEADER_TCODE(tcode) | |
| 169 | HEADER_DESTINATION(node_id); | 170 | HEADER_DESTINATION(destination_id); |
| 170 | packet->header[1] = | 171 | packet->header[1] = |
| 171 | HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id); | 172 | HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id); |
| 172 | packet->header[2] = | 173 | packet->header[2] = |
| @@ -252,7 +253,7 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t, | |||
| 252 | fw_transaction_callback_t callback, void *callback_data) | 253 | fw_transaction_callback_t callback, void *callback_data) |
| 253 | { | 254 | { |
| 254 | unsigned long flags; | 255 | unsigned long flags; |
| 255 | int tlabel, source; | 256 | int tlabel; |
| 256 | 257 | ||
| 257 | /* | 258 | /* |
| 258 | * Bump the flush timer up 100ms first of all so we | 259 | * Bump the flush timer up 100ms first of all so we |
| @@ -268,7 +269,6 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t, | |||
| 268 | 269 | ||
| 269 | spin_lock_irqsave(&card->lock, flags); | 270 | spin_lock_irqsave(&card->lock, flags); |
| 270 | 271 | ||
| 271 | source = card->node_id; | ||
| 272 | tlabel = card->current_tlabel; | 272 | tlabel = card->current_tlabel; |
| 273 | if (card->tlabel_mask & (1 << tlabel)) { | 273 | if (card->tlabel_mask & (1 << tlabel)) { |
| 274 | spin_unlock_irqrestore(&card->lock, flags); | 274 | spin_unlock_irqrestore(&card->lock, flags); |
| @@ -279,77 +279,58 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t, | |||
| 279 | card->current_tlabel = (card->current_tlabel + 1) & 0x1f; | 279 | card->current_tlabel = (card->current_tlabel + 1) & 0x1f; |
| 280 | card->tlabel_mask |= (1 << tlabel); | 280 | card->tlabel_mask |= (1 << tlabel); |
| 281 | 281 | ||
| 282 | list_add_tail(&t->link, &card->transaction_list); | ||
| 283 | |||
| 284 | spin_unlock_irqrestore(&card->lock, flags); | ||
| 285 | |||
| 286 | /* Initialize rest of transaction, fill out packet and send it. */ | ||
| 287 | t->node_id = node_id; | 282 | t->node_id = node_id; |
| 288 | t->tlabel = tlabel; | 283 | t->tlabel = tlabel; |
| 289 | t->callback = callback; | 284 | t->callback = callback; |
| 290 | t->callback_data = callback_data; | 285 | t->callback_data = callback_data; |
| 291 | 286 | ||
| 292 | fw_fill_request(&t->packet, tcode, t->tlabel, | 287 | fw_fill_request(&t->packet, tcode, t->tlabel, node_id, card->node_id, |
| 293 | node_id, source, generation, | 288 | generation, speed, offset, payload, length); |
| 294 | speed, offset, payload, length); | ||
| 295 | t->packet.callback = transmit_complete_callback; | 289 | t->packet.callback = transmit_complete_callback; |
| 296 | 290 | ||
| 291 | list_add_tail(&t->link, &card->transaction_list); | ||
| 292 | |||
| 293 | spin_unlock_irqrestore(&card->lock, flags); | ||
| 294 | |||
| 297 | card->driver->send_request(card, &t->packet); | 295 | card->driver->send_request(card, &t->packet); |
| 298 | } | 296 | } |
| 299 | EXPORT_SYMBOL(fw_send_request); | 297 | EXPORT_SYMBOL(fw_send_request); |
| 300 | 298 | ||
| 301 | struct fw_phy_packet { | 299 | static DEFINE_MUTEX(phy_config_mutex); |
| 302 | struct fw_packet packet; | 300 | static DECLARE_COMPLETION(phy_config_done); |
| 303 | struct completion done; | ||
| 304 | struct kref kref; | ||
| 305 | }; | ||
| 306 | |||
| 307 | static void phy_packet_release(struct kref *kref) | ||
| 308 | { | ||
| 309 | struct fw_phy_packet *p = | ||
| 310 | container_of(kref, struct fw_phy_packet, kref); | ||
| 311 | kfree(p); | ||
| 312 | } | ||
| 313 | 301 | ||
| 314 | static void transmit_phy_packet_callback(struct fw_packet *packet, | 302 | static void transmit_phy_packet_callback(struct fw_packet *packet, |
| 315 | struct fw_card *card, int status) | 303 | struct fw_card *card, int status) |
| 316 | { | 304 | { |
| 317 | struct fw_phy_packet *p = | 305 | complete(&phy_config_done); |
| 318 | container_of(packet, struct fw_phy_packet, packet); | ||
| 319 | |||
| 320 | complete(&p->done); | ||
| 321 | kref_put(&p->kref, phy_packet_release); | ||
| 322 | } | 306 | } |
| 323 | 307 | ||
| 308 | static struct fw_packet phy_config_packet = { | ||
| 309 | .header_length = 8, | ||
| 310 | .payload_length = 0, | ||
| 311 | .speed = SCODE_100, | ||
| 312 | .callback = transmit_phy_packet_callback, | ||
| 313 | }; | ||
| 314 | |||
| 324 | void fw_send_phy_config(struct fw_card *card, | 315 | void fw_send_phy_config(struct fw_card *card, |
| 325 | int node_id, int generation, int gap_count) | 316 | int node_id, int generation, int gap_count) |
| 326 | { | 317 | { |
| 327 | struct fw_phy_packet *p; | ||
| 328 | long timeout = DIV_ROUND_UP(HZ, 10); | 318 | long timeout = DIV_ROUND_UP(HZ, 10); |
| 329 | u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG) | | 319 | u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG) | |
| 330 | PHY_CONFIG_ROOT_ID(node_id) | | 320 | PHY_CONFIG_ROOT_ID(node_id) | |
| 331 | PHY_CONFIG_GAP_COUNT(gap_count); | 321 | PHY_CONFIG_GAP_COUNT(gap_count); |
| 332 | 322 | ||
| 333 | p = kmalloc(sizeof(*p), GFP_KERNEL); | 323 | mutex_lock(&phy_config_mutex); |
| 334 | if (p == NULL) | 324 | |
| 335 | return; | 325 | phy_config_packet.header[0] = data; |
| 326 | phy_config_packet.header[1] = ~data; | ||
| 327 | phy_config_packet.generation = generation; | ||
| 328 | INIT_COMPLETION(phy_config_done); | ||
| 329 | |||
| 330 | card->driver->send_request(card, &phy_config_packet); | ||
| 331 | wait_for_completion_timeout(&phy_config_done, timeout); | ||
| 336 | 332 | ||
| 337 | p->packet.header[0] = data; | 333 | mutex_unlock(&phy_config_mutex); |
| 338 | p->packet.header[1] = ~data; | ||
| 339 | p->packet.header_length = 8; | ||
| 340 | p->packet.payload_length = 0; | ||
| 341 | p->packet.speed = SCODE_100; | ||
| 342 | p->packet.generation = generation; | ||
| 343 | p->packet.callback = transmit_phy_packet_callback; | ||
| 344 | init_completion(&p->done); | ||
| 345 | kref_set(&p->kref, 2); | ||
| 346 | |||
| 347 | card->driver->send_request(card, &p->packet); | ||
| 348 | timeout = wait_for_completion_timeout(&p->done, timeout); | ||
| 349 | kref_put(&p->kref, phy_packet_release); | ||
| 350 | |||
| 351 | /* will leak p if the callback is never executed */ | ||
| 352 | WARN_ON(timeout == 0); | ||
| 353 | } | 334 | } |
| 354 | 335 | ||
| 355 | void fw_flush_transactions(struct fw_card *card) | 336 | void fw_flush_transactions(struct fw_card *card) |
diff --git a/drivers/firmware/memmap.c b/drivers/firmware/memmap.c index e23399c7f773..001622eb86f9 100644 --- a/drivers/firmware/memmap.c +++ b/drivers/firmware/memmap.c | |||
| @@ -153,12 +153,14 @@ int __init firmware_map_add_early(resource_size_t start, resource_size_t end, | |||
| 153 | 153 | ||
| 154 | static ssize_t start_show(struct firmware_map_entry *entry, char *buf) | 154 | static ssize_t start_show(struct firmware_map_entry *entry, char *buf) |
| 155 | { | 155 | { |
| 156 | return snprintf(buf, PAGE_SIZE, "0x%llx\n", entry->start); | 156 | return snprintf(buf, PAGE_SIZE, "0x%llx\n", |
| 157 | (unsigned long long)entry->start); | ||
| 157 | } | 158 | } |
| 158 | 159 | ||
| 159 | static ssize_t end_show(struct firmware_map_entry *entry, char *buf) | 160 | static ssize_t end_show(struct firmware_map_entry *entry, char *buf) |
| 160 | { | 161 | { |
| 161 | return snprintf(buf, PAGE_SIZE, "0x%llx\n", entry->end); | 162 | return snprintf(buf, PAGE_SIZE, "0x%llx\n", |
| 163 | (unsigned long long)entry->end); | ||
| 162 | } | 164 | } |
| 163 | 165 | ||
| 164 | static ssize_t type_show(struct firmware_map_entry *entry, char *buf) | 166 | static ssize_t type_show(struct firmware_map_entry *entry, char *buf) |
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 564138714bb5..452c2d866ec5 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c | |||
| @@ -318,7 +318,7 @@ static void drm_cleanup(struct drm_device * dev) | |||
| 318 | DRM_ERROR("Cannot unload module\n"); | 318 | DRM_ERROR("Cannot unload module\n"); |
| 319 | } | 319 | } |
| 320 | 320 | ||
| 321 | int drm_minors_cleanup(int id, void *ptr, void *data) | 321 | static int drm_minors_cleanup(int id, void *ptr, void *data) |
| 322 | { | 322 | { |
| 323 | struct drm_minor *minor = ptr; | 323 | struct drm_minor *minor = ptr; |
| 324 | struct drm_device *dev; | 324 | struct drm_device *dev; |
diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index 9494005d1c9a..e603736682bf 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c | |||
| @@ -43,7 +43,6 @@ | |||
| 43 | #include <linux/cdev.h> | 43 | #include <linux/cdev.h> |
| 44 | #include <linux/idr.h> | 44 | #include <linux/idr.h> |
| 45 | #include <linux/mutex.h> | 45 | #include <linux/mutex.h> |
| 46 | #include <linux/smp_lock.h> | ||
| 47 | 46 | ||
| 48 | #include <asm/uaccess.h> | 47 | #include <asm/uaccess.h> |
| 49 | 48 | ||
| @@ -1154,11 +1153,18 @@ static unsigned int ib_ucm_poll(struct file *filp, | |||
| 1154 | return mask; | 1153 | return mask; |
| 1155 | } | 1154 | } |
| 1156 | 1155 | ||
| 1156 | /* | ||
| 1157 | * ib_ucm_open() does not need the BKL: | ||
| 1158 | * | ||
| 1159 | * - no global state is referred to; | ||
| 1160 | * - there is no ioctl method to race against; | ||
| 1161 | * - no further module initialization is required for open to work | ||
| 1162 | * after the device is registered. | ||
| 1163 | */ | ||
| 1157 | static int ib_ucm_open(struct inode *inode, struct file *filp) | 1164 | static int ib_ucm_open(struct inode *inode, struct file *filp) |
| 1158 | { | 1165 | { |
| 1159 | struct ib_ucm_file *file; | 1166 | struct ib_ucm_file *file; |
| 1160 | 1167 | ||
| 1161 | cycle_kernel_lock(); | ||
| 1162 | file = kmalloc(sizeof(*file), GFP_KERNEL); | 1168 | file = kmalloc(sizeof(*file), GFP_KERNEL); |
| 1163 | if (!file) | 1169 | if (!file) |
| 1164 | return -ENOMEM; | 1170 | return -ENOMEM; |
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 195f97302fe5..b41dd26bbfa1 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c | |||
| @@ -38,7 +38,6 @@ | |||
| 38 | #include <linux/in.h> | 38 | #include <linux/in.h> |
| 39 | #include <linux/in6.h> | 39 | #include <linux/in6.h> |
| 40 | #include <linux/miscdevice.h> | 40 | #include <linux/miscdevice.h> |
| 41 | #include <linux/smp_lock.h> | ||
| 42 | 41 | ||
| 43 | #include <rdma/rdma_user_cm.h> | 42 | #include <rdma/rdma_user_cm.h> |
| 44 | #include <rdma/ib_marshall.h> | 43 | #include <rdma/ib_marshall.h> |
| @@ -1149,6 +1148,14 @@ static unsigned int ucma_poll(struct file *filp, struct poll_table_struct *wait) | |||
| 1149 | return mask; | 1148 | return mask; |
| 1150 | } | 1149 | } |
| 1151 | 1150 | ||
| 1151 | /* | ||
| 1152 | * ucma_open() does not need the BKL: | ||
| 1153 | * | ||
| 1154 | * - no global state is referred to; | ||
| 1155 | * - there is no ioctl method to race against; | ||
| 1156 | * - no further module initialization is required for open to work | ||
| 1157 | * after the device is registered. | ||
| 1158 | */ | ||
| 1152 | static int ucma_open(struct inode *inode, struct file *filp) | 1159 | static int ucma_open(struct inode *inode, struct file *filp) |
| 1153 | { | 1160 | { |
| 1154 | struct ucma_file *file; | 1161 | struct ucma_file *file; |
| @@ -1157,7 +1164,6 @@ static int ucma_open(struct inode *inode, struct file *filp) | |||
| 1157 | if (!file) | 1164 | if (!file) |
| 1158 | return -ENOMEM; | 1165 | return -ENOMEM; |
| 1159 | 1166 | ||
| 1160 | lock_kernel(); | ||
| 1161 | INIT_LIST_HEAD(&file->event_list); | 1167 | INIT_LIST_HEAD(&file->event_list); |
| 1162 | INIT_LIST_HEAD(&file->ctx_list); | 1168 | INIT_LIST_HEAD(&file->ctx_list); |
| 1163 | init_waitqueue_head(&file->poll_wait); | 1169 | init_waitqueue_head(&file->poll_wait); |
| @@ -1165,7 +1171,6 @@ static int ucma_open(struct inode *inode, struct file *filp) | |||
| 1165 | 1171 | ||
| 1166 | filp->private_data = file; | 1172 | filp->private_data = file; |
| 1167 | file->filp = filp; | 1173 | file->filp = filp; |
| 1168 | unlock_kernel(); | ||
| 1169 | return 0; | 1174 | return 0; |
| 1170 | } | 1175 | } |
| 1171 | 1176 | ||
diff --git a/drivers/infiniband/hw/ipath/ipath_sdma.c b/drivers/infiniband/hw/ipath/ipath_sdma.c index eaba03273e4f..284c9bca517e 100644 --- a/drivers/infiniband/hw/ipath/ipath_sdma.c +++ b/drivers/infiniband/hw/ipath/ipath_sdma.c | |||
| @@ -698,7 +698,7 @@ retry: | |||
| 698 | 698 | ||
| 699 | addr = dma_map_single(&dd->pcidev->dev, tx->txreq.map_addr, | 699 | addr = dma_map_single(&dd->pcidev->dev, tx->txreq.map_addr, |
| 700 | tx->map_len, DMA_TO_DEVICE); | 700 | tx->map_len, DMA_TO_DEVICE); |
| 701 | if (dma_mapping_error(addr)) { | 701 | if (dma_mapping_error(&dd->pcidev->dev, addr)) { |
| 702 | ret = -EIO; | 702 | ret = -EIO; |
| 703 | goto unlock; | 703 | goto unlock; |
| 704 | } | 704 | } |
diff --git a/drivers/infiniband/hw/ipath/ipath_user_sdma.c b/drivers/infiniband/hw/ipath/ipath_user_sdma.c index 86e016916cd1..82d9a0b5ca2f 100644 --- a/drivers/infiniband/hw/ipath/ipath_user_sdma.c +++ b/drivers/infiniband/hw/ipath/ipath_user_sdma.c | |||
| @@ -206,7 +206,7 @@ static int ipath_user_sdma_coalesce(const struct ipath_devdata *dd, | |||
| 206 | 206 | ||
| 207 | dma_addr = dma_map_page(&dd->pcidev->dev, page, 0, len, | 207 | dma_addr = dma_map_page(&dd->pcidev->dev, page, 0, len, |
| 208 | DMA_TO_DEVICE); | 208 | DMA_TO_DEVICE); |
| 209 | if (dma_mapping_error(dma_addr)) { | 209 | if (dma_mapping_error(&dd->pcidev->dev, dma_addr)) { |
| 210 | ret = -ENOMEM; | 210 | ret = -ENOMEM; |
| 211 | goto free_unmap; | 211 | goto free_unmap; |
| 212 | } | 212 | } |
| @@ -301,7 +301,7 @@ static int ipath_user_sdma_pin_pages(const struct ipath_devdata *dd, | |||
| 301 | pages[j], 0, flen, DMA_TO_DEVICE); | 301 | pages[j], 0, flen, DMA_TO_DEVICE); |
| 302 | unsigned long fofs = addr & ~PAGE_MASK; | 302 | unsigned long fofs = addr & ~PAGE_MASK; |
| 303 | 303 | ||
| 304 | if (dma_mapping_error(dma_addr)) { | 304 | if (dma_mapping_error(&dd->pcidev->dev, dma_addr)) { |
| 305 | ret = -ENOMEM; | 305 | ret = -ENOMEM; |
| 306 | goto done; | 306 | goto done; |
| 307 | } | 307 | } |
| @@ -508,7 +508,7 @@ static int ipath_user_sdma_queue_pkts(const struct ipath_devdata *dd, | |||
| 508 | if (page) { | 508 | if (page) { |
| 509 | dma_addr = dma_map_page(&dd->pcidev->dev, | 509 | dma_addr = dma_map_page(&dd->pcidev->dev, |
| 510 | page, 0, len, DMA_TO_DEVICE); | 510 | page, 0, len, DMA_TO_DEVICE); |
| 511 | if (dma_mapping_error(dma_addr)) { | 511 | if (dma_mapping_error(&dd->pcidev->dev, dma_addr)) { |
| 512 | ret = -ENOMEM; | 512 | ret = -ENOMEM; |
| 513 | goto free_pbc; | 513 | goto free_pbc; |
| 514 | } | 514 | } |
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index 0b191a4842ce..a1464574bfdd 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. | 2 | * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. |
| 3 | * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. | ||
| 3 | * | 4 | * |
| 4 | * This software is available to you under a choice of one of two | 5 | * This software is available to you under a choice of one of two |
| 5 | * licenses. You may choose to be licensed under the terms of the GNU | 6 | * licenses. You may choose to be licensed under the terms of the GNU |
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 38d6907ab521..a3c2851c0545 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. | 2 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. |
| 3 | * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. | ||
| 3 | * | 4 | * |
| 4 | * This software is available to you under a choice of one of two | 5 | * This software is available to you under a choice of one of two |
| 5 | * licenses. You may choose to be licensed under the terms of the GNU | 6 | * licenses. You may choose to be licensed under the terms of the GNU |
diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index d26a91317d4d..6e2b0dc21b61 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2006, 2007 Cisco Systems. All rights reserved. | 2 | * Copyright (c) 2006, 2007 Cisco Systems. All rights reserved. |
| 3 | * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. | ||
| 3 | * | 4 | * |
| 4 | * This software is available to you under a choice of one of two | 5 | * This software is available to you under a choice of one of two |
| 5 | * licenses. You may choose to be licensed under the terms of the GNU | 6 | * licenses. You may choose to be licensed under the terms of the GNU |
diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c index db2086faa4ed..a4cdb465cd1d 100644 --- a/drivers/infiniband/hw/mlx4/mr.c +++ b/drivers/infiniband/hw/mlx4/mr.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. | 2 | * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. |
| 3 | * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. | ||
| 3 | * | 4 | * |
| 4 | * This software is available to you under a choice of one of two | 5 | * This software is available to you under a choice of one of two |
| 5 | * licenses. You may choose to be licensed under the terms of the GNU | 6 | * licenses. You may choose to be licensed under the terms of the GNU |
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 02a99bc4442e..f7bc7dd8578a 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. | 2 | * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. |
| 3 | * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. | ||
| 3 | * | 4 | * |
| 4 | * This software is available to you under a choice of one of two | 5 | * This software is available to you under a choice of one of two |
| 5 | * licenses. You may choose to be licensed under the terms of the GNU | 6 | * licenses. You may choose to be licensed under the terms of the GNU |
diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c index 12d6bc6f8007..d42565258fb7 100644 --- a/drivers/infiniband/hw/mlx4/srq.c +++ b/drivers/infiniband/hw/mlx4/srq.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. | 2 | * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. |
| 3 | * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. | ||
| 3 | * | 4 | * |
| 4 | * This software is available to you under a choice of one of two | 5 | * This software is available to you under a choice of one of two |
| 5 | * licenses. You may choose to be licensed under the terms of the GNU | 6 | * licenses. You may choose to be licensed under the terms of the GNU |
diff --git a/drivers/infiniband/hw/mlx4/user.h b/drivers/infiniband/hw/mlx4/user.h index e2d11be4525c..13beedeeef9f 100644 --- a/drivers/infiniband/hw/mlx4/user.h +++ b/drivers/infiniband/hw/mlx4/user.h | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. | 2 | * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. |
| 3 | * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. | ||
| 3 | * | 4 | * |
| 4 | * This software is available to you under a choice of one of two | 5 | * This software is available to you under a choice of one of two |
| 5 | * licenses. You may choose to be licensed under the terms of the GNU | 6 | * licenses. You may choose to be licensed under the terms of the GNU |
diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c index 4e36aa7cb3d2..cc6858f0b65b 100644 --- a/drivers/infiniband/hw/mthca/mthca_eq.c +++ b/drivers/infiniband/hw/mthca/mthca_eq.c | |||
| @@ -780,7 +780,7 @@ int mthca_map_eq_icm(struct mthca_dev *dev, u64 icm_virt) | |||
| 780 | return -ENOMEM; | 780 | return -ENOMEM; |
| 781 | dev->eq_table.icm_dma = pci_map_page(dev->pdev, dev->eq_table.icm_page, 0, | 781 | dev->eq_table.icm_dma = pci_map_page(dev->pdev, dev->eq_table.icm_page, 0, |
| 782 | PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); | 782 | PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); |
| 783 | if (pci_dma_mapping_error(dev->eq_table.icm_dma)) { | 783 | if (pci_dma_mapping_error(dev->pdev, dev->eq_table.icm_dma)) { |
| 784 | __free_page(dev->eq_table.icm_page); | 784 | __free_page(dev->eq_table.icm_page); |
| 785 | return -ENOMEM; | 785 | return -ENOMEM; |
| 786 | } | 786 | } |
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index d2884e778098..b0cab64e5e3d 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c | |||
| @@ -276,6 +276,7 @@ static void nes_cqp_rem_ref_callback(struct nes_device *nesdev, struct nes_cqp_r | |||
| 276 | } | 276 | } |
| 277 | nes_free_resource(nesadapter, nesadapter->allocated_qps, nesqp->hwqp.qp_id); | 277 | nes_free_resource(nesadapter, nesadapter->allocated_qps, nesqp->hwqp.qp_id); |
| 278 | 278 | ||
| 279 | nesadapter->qp_table[nesqp->hwqp.qp_id-NES_FIRST_QPN] = NULL; | ||
| 279 | kfree(nesqp->allocated_buffer); | 280 | kfree(nesqp->allocated_buffer); |
| 280 | 281 | ||
| 281 | } | 282 | } |
| @@ -289,7 +290,6 @@ void nes_rem_ref(struct ib_qp *ibqp) | |||
| 289 | struct nes_qp *nesqp; | 290 | struct nes_qp *nesqp; |
| 290 | struct nes_vnic *nesvnic = to_nesvnic(ibqp->device); | 291 | struct nes_vnic *nesvnic = to_nesvnic(ibqp->device); |
| 291 | struct nes_device *nesdev = nesvnic->nesdev; | 292 | struct nes_device *nesdev = nesvnic->nesdev; |
| 292 | struct nes_adapter *nesadapter = nesdev->nesadapter; | ||
| 293 | struct nes_hw_cqp_wqe *cqp_wqe; | 293 | struct nes_hw_cqp_wqe *cqp_wqe; |
| 294 | struct nes_cqp_request *cqp_request; | 294 | struct nes_cqp_request *cqp_request; |
| 295 | u32 opcode; | 295 | u32 opcode; |
| @@ -303,8 +303,6 @@ void nes_rem_ref(struct ib_qp *ibqp) | |||
| 303 | } | 303 | } |
| 304 | 304 | ||
| 305 | if (atomic_dec_and_test(&nesqp->refcount)) { | 305 | if (atomic_dec_and_test(&nesqp->refcount)) { |
| 306 | nesadapter->qp_table[nesqp->hwqp.qp_id-NES_FIRST_QPN] = NULL; | ||
| 307 | |||
| 308 | /* Destroy the QP */ | 306 | /* Destroy the QP */ |
| 309 | cqp_request = nes_get_cqp_request(nesdev); | 307 | cqp_request = nes_get_cqp_request(nesdev); |
| 310 | if (cqp_request == NULL) { | 308 | if (cqp_request == NULL) { |
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 6aa531d5276d..9f0b964b2c99 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c | |||
| @@ -74,36 +74,59 @@ atomic_t cm_nodes_destroyed; | |||
| 74 | atomic_t cm_accel_dropped_pkts; | 74 | atomic_t cm_accel_dropped_pkts; |
| 75 | atomic_t cm_resets_recvd; | 75 | atomic_t cm_resets_recvd; |
| 76 | 76 | ||
| 77 | static inline int mini_cm_accelerated(struct nes_cm_core *, struct nes_cm_node *); | 77 | static inline int mini_cm_accelerated(struct nes_cm_core *, |
| 78 | struct nes_cm_node *); | ||
| 78 | static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *, | 79 | static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *, |
| 79 | struct nes_vnic *, struct nes_cm_info *); | 80 | struct nes_vnic *, struct nes_cm_info *); |
| 80 | static int add_ref_cm_node(struct nes_cm_node *); | ||
| 81 | static int rem_ref_cm_node(struct nes_cm_core *, struct nes_cm_node *); | ||
| 82 | static int mini_cm_del_listen(struct nes_cm_core *, struct nes_cm_listener *); | 81 | static int mini_cm_del_listen(struct nes_cm_core *, struct nes_cm_listener *); |
| 83 | static struct sk_buff *form_cm_frame(struct sk_buff *, struct nes_cm_node *, | ||
| 84 | void *, u32, void *, u32, u8); | ||
| 85 | static struct sk_buff *get_free_pkt(struct nes_cm_node *cm_node); | ||
| 86 | |||
| 87 | static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *, | 82 | static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *, |
| 88 | struct nes_vnic *, | 83 | struct nes_vnic *, u16, void *, struct nes_cm_info *); |
| 89 | struct ietf_mpa_frame *, | 84 | static int mini_cm_close(struct nes_cm_core *, struct nes_cm_node *); |
| 90 | struct nes_cm_info *); | ||
| 91 | static int mini_cm_accept(struct nes_cm_core *, struct ietf_mpa_frame *, | 85 | static int mini_cm_accept(struct nes_cm_core *, struct ietf_mpa_frame *, |
| 92 | struct nes_cm_node *); | 86 | struct nes_cm_node *); |
| 93 | static int mini_cm_reject(struct nes_cm_core *, struct ietf_mpa_frame *, | 87 | static int mini_cm_reject(struct nes_cm_core *, struct ietf_mpa_frame *, |
| 94 | struct nes_cm_node *); | 88 | struct nes_cm_node *); |
| 95 | static int mini_cm_close(struct nes_cm_core *, struct nes_cm_node *); | 89 | static void mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *, |
| 96 | static int mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *, | 90 | struct sk_buff *); |
| 97 | struct sk_buff *); | ||
| 98 | static int mini_cm_dealloc_core(struct nes_cm_core *); | 91 | static int mini_cm_dealloc_core(struct nes_cm_core *); |
| 99 | static int mini_cm_get(struct nes_cm_core *); | 92 | static int mini_cm_get(struct nes_cm_core *); |
| 100 | static int mini_cm_set(struct nes_cm_core *, u32, u32); | 93 | static int mini_cm_set(struct nes_cm_core *, u32, u32); |
| 94 | |||
| 95 | static struct sk_buff *form_cm_frame(struct sk_buff *, struct nes_cm_node *, | ||
| 96 | void *, u32, void *, u32, u8); | ||
| 97 | static struct sk_buff *get_free_pkt(struct nes_cm_node *cm_node); | ||
| 98 | static int add_ref_cm_node(struct nes_cm_node *); | ||
| 99 | static int rem_ref_cm_node(struct nes_cm_core *, struct nes_cm_node *); | ||
| 100 | |||
| 101 | static int nes_cm_disconn_true(struct nes_qp *); | 101 | static int nes_cm_disconn_true(struct nes_qp *); |
| 102 | static int nes_cm_post_event(struct nes_cm_event *event); | 102 | static int nes_cm_post_event(struct nes_cm_event *event); |
| 103 | static int nes_disconnect(struct nes_qp *nesqp, int abrupt); | 103 | static int nes_disconnect(struct nes_qp *nesqp, int abrupt); |
| 104 | static void nes_disconnect_worker(struct work_struct *work); | 104 | static void nes_disconnect_worker(struct work_struct *work); |
| 105 | static int send_ack(struct nes_cm_node *cm_node); | 105 | |
| 106 | static int send_mpa_request(struct nes_cm_node *, struct sk_buff *); | ||
| 107 | static int send_syn(struct nes_cm_node *, u32, struct sk_buff *); | ||
| 108 | static int send_reset(struct nes_cm_node *, struct sk_buff *); | ||
| 109 | static int send_ack(struct nes_cm_node *cm_node, struct sk_buff *skb); | ||
| 106 | static int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb); | 110 | static int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb); |
| 111 | static void process_packet(struct nes_cm_node *, struct sk_buff *, | ||
| 112 | struct nes_cm_core *); | ||
| 113 | |||
| 114 | static void active_open_err(struct nes_cm_node *, struct sk_buff *, int); | ||
| 115 | static void passive_open_err(struct nes_cm_node *, struct sk_buff *, int); | ||
| 116 | static void cleanup_retrans_entry(struct nes_cm_node *); | ||
| 117 | static void handle_rcv_mpa(struct nes_cm_node *, struct sk_buff *, | ||
| 118 | enum nes_cm_event_type); | ||
| 119 | static void free_retrans_entry(struct nes_cm_node *cm_node); | ||
| 120 | static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph, | ||
| 121 | struct sk_buff *skb, int optionsize, int passive); | ||
| 122 | |||
| 123 | /* CM event handler functions */ | ||
| 124 | static void cm_event_connected(struct nes_cm_event *); | ||
| 125 | static void cm_event_connect_error(struct nes_cm_event *); | ||
| 126 | static void cm_event_reset(struct nes_cm_event *); | ||
| 127 | static void cm_event_mpa_req(struct nes_cm_event *); | ||
| 128 | |||
| 129 | static void print_core(struct nes_cm_core *core); | ||
| 107 | 130 | ||
| 108 | /* External CM API Interface */ | 131 | /* External CM API Interface */ |
| 109 | /* instance of function pointers for client API */ | 132 | /* instance of function pointers for client API */ |
| @@ -158,11 +181,11 @@ static struct nes_cm_event *create_event(struct nes_cm_node *cm_node, | |||
| 158 | event->cm_info.loc_port = cm_node->loc_port; | 181 | event->cm_info.loc_port = cm_node->loc_port; |
| 159 | event->cm_info.cm_id = cm_node->cm_id; | 182 | event->cm_info.cm_id = cm_node->cm_id; |
| 160 | 183 | ||
| 161 | nes_debug(NES_DBG_CM, "Created event=%p, type=%u, dst_addr=%08x[%x]," | 184 | nes_debug(NES_DBG_CM, "cm_node=%p Created event=%p, type=%u, " |
| 162 | " src_addr=%08x[%x]\n", | 185 | "dst_addr=%08x[%x], src_addr=%08x[%x]\n", |
| 163 | event, type, | 186 | cm_node, event, type, event->cm_info.loc_addr, |
| 164 | event->cm_info.loc_addr, event->cm_info.loc_port, | 187 | event->cm_info.loc_port, event->cm_info.rem_addr, |
| 165 | event->cm_info.rem_addr, event->cm_info.rem_port); | 188 | event->cm_info.rem_port); |
| 166 | 189 | ||
| 167 | nes_cm_post_event(event); | 190 | nes_cm_post_event(event); |
| 168 | return event; | 191 | return event; |
| @@ -172,14 +195,11 @@ static struct nes_cm_event *create_event(struct nes_cm_node *cm_node, | |||
| 172 | /** | 195 | /** |
| 173 | * send_mpa_request | 196 | * send_mpa_request |
| 174 | */ | 197 | */ |
| 175 | static int send_mpa_request(struct nes_cm_node *cm_node) | 198 | static int send_mpa_request(struct nes_cm_node *cm_node, struct sk_buff *skb) |
| 176 | { | 199 | { |
| 177 | struct sk_buff *skb; | ||
| 178 | int ret; | 200 | int ret; |
| 179 | |||
| 180 | skb = get_free_pkt(cm_node); | ||
| 181 | if (!skb) { | 201 | if (!skb) { |
| 182 | nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n"); | 202 | nes_debug(NES_DBG_CM, "skb set to NULL\n"); |
| 183 | return -1; | 203 | return -1; |
| 184 | } | 204 | } |
| 185 | 205 | ||
| @@ -188,9 +208,8 @@ static int send_mpa_request(struct nes_cm_node *cm_node) | |||
| 188 | cm_node->mpa_frame_size, SET_ACK); | 208 | cm_node->mpa_frame_size, SET_ACK); |
| 189 | 209 | ||
| 190 | ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0); | 210 | ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0); |
| 191 | if (ret < 0) { | 211 | if (ret < 0) |
| 192 | return ret; | 212 | return ret; |
| 193 | } | ||
| 194 | 213 | ||
| 195 | return 0; | 214 | return 0; |
| 196 | } | 215 | } |
| @@ -229,46 +248,12 @@ static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 len) | |||
| 229 | 248 | ||
| 230 | 249 | ||
| 231 | /** | 250 | /** |
| 232 | * handle_exception_pkt - process an exception packet. | ||
| 233 | * We have been in a TSA state, and we have now received SW | ||
| 234 | * TCP/IP traffic should be a FIN request or IP pkt with options | ||
| 235 | */ | ||
| 236 | static int handle_exception_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb) | ||
| 237 | { | ||
| 238 | int ret = 0; | ||
| 239 | struct tcphdr *tcph = tcp_hdr(skb); | ||
| 240 | |||
| 241 | /* first check to see if this a FIN pkt */ | ||
| 242 | if (tcph->fin) { | ||
| 243 | /* we need to ACK the FIN request */ | ||
| 244 | send_ack(cm_node); | ||
| 245 | |||
| 246 | /* check which side we are (client/server) and set next state accordingly */ | ||
| 247 | if (cm_node->tcp_cntxt.client) | ||
| 248 | cm_node->state = NES_CM_STATE_CLOSING; | ||
| 249 | else { | ||
| 250 | /* we are the server side */ | ||
| 251 | cm_node->state = NES_CM_STATE_CLOSE_WAIT; | ||
| 252 | /* since this is a self contained CM we don't wait for */ | ||
| 253 | /* an APP to close us, just send final FIN immediately */ | ||
| 254 | ret = send_fin(cm_node, NULL); | ||
| 255 | cm_node->state = NES_CM_STATE_LAST_ACK; | ||
| 256 | } | ||
| 257 | } else { | ||
| 258 | ret = -EINVAL; | ||
| 259 | } | ||
| 260 | |||
| 261 | return ret; | ||
| 262 | } | ||
| 263 | |||
| 264 | |||
| 265 | /** | ||
| 266 | * form_cm_frame - get a free packet and build empty frame Use | 251 | * form_cm_frame - get a free packet and build empty frame Use |
| 267 | * node info to build. | 252 | * node info to build. |
| 268 | */ | 253 | */ |
| 269 | static struct sk_buff *form_cm_frame(struct sk_buff *skb, struct nes_cm_node *cm_node, | 254 | static struct sk_buff *form_cm_frame(struct sk_buff *skb, |
| 270 | void *options, u32 optionsize, void *data, | 255 | struct nes_cm_node *cm_node, void *options, u32 optionsize, |
| 271 | u32 datasize, u8 flags) | 256 | void *data, u32 datasize, u8 flags) |
| 272 | { | 257 | { |
| 273 | struct tcphdr *tcph; | 258 | struct tcphdr *tcph; |
| 274 | struct iphdr *iph; | 259 | struct iphdr *iph; |
| @@ -332,10 +317,12 @@ static struct sk_buff *form_cm_frame(struct sk_buff *skb, struct nes_cm_node *cm | |||
| 332 | cm_node->tcp_cntxt.loc_seq_num++; | 317 | cm_node->tcp_cntxt.loc_seq_num++; |
| 333 | tcph->syn = 1; | 318 | tcph->syn = 1; |
| 334 | } else | 319 | } else |
| 335 | cm_node->tcp_cntxt.loc_seq_num += datasize; /* data (no headers) */ | 320 | cm_node->tcp_cntxt.loc_seq_num += datasize; |
| 336 | 321 | ||
| 337 | if (flags & SET_FIN) | 322 | if (flags & SET_FIN) { |
| 323 | cm_node->tcp_cntxt.loc_seq_num++; | ||
| 338 | tcph->fin = 1; | 324 | tcph->fin = 1; |
| 325 | } | ||
| 339 | 326 | ||
| 340 | if (flags & SET_RST) | 327 | if (flags & SET_RST) |
| 341 | tcph->rst = 1; | 328 | tcph->rst = 1; |
| @@ -389,7 +376,7 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb, | |||
| 389 | int close_when_complete) | 376 | int close_when_complete) |
| 390 | { | 377 | { |
| 391 | unsigned long flags; | 378 | unsigned long flags; |
| 392 | struct nes_cm_core *cm_core; | 379 | struct nes_cm_core *cm_core = cm_node->cm_core; |
| 393 | struct nes_timer_entry *new_send; | 380 | struct nes_timer_entry *new_send; |
| 394 | int ret = 0; | 381 | int ret = 0; |
| 395 | u32 was_timer_set; | 382 | u32 was_timer_set; |
| @@ -411,7 +398,7 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb, | |||
| 411 | new_send->close_when_complete = close_when_complete; | 398 | new_send->close_when_complete = close_when_complete; |
| 412 | 399 | ||
| 413 | if (type == NES_TIMER_TYPE_CLOSE) { | 400 | if (type == NES_TIMER_TYPE_CLOSE) { |
| 414 | new_send->timetosend += (HZ/2); /* TODO: decide on the correct value here */ | 401 | new_send->timetosend += (HZ/10); |
| 415 | spin_lock_irqsave(&cm_node->recv_list_lock, flags); | 402 | spin_lock_irqsave(&cm_node->recv_list_lock, flags); |
| 416 | list_add_tail(&new_send->list, &cm_node->recv_list); | 403 | list_add_tail(&new_send->list, &cm_node->recv_list); |
| 417 | spin_unlock_irqrestore(&cm_node->recv_list_lock, flags); | 404 | spin_unlock_irqrestore(&cm_node->recv_list_lock, flags); |
| @@ -420,36 +407,28 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb, | |||
| 420 | if (type == NES_TIMER_TYPE_SEND) { | 407 | if (type == NES_TIMER_TYPE_SEND) { |
| 421 | new_send->seq_num = ntohl(tcp_hdr(skb)->seq); | 408 | new_send->seq_num = ntohl(tcp_hdr(skb)->seq); |
| 422 | atomic_inc(&new_send->skb->users); | 409 | atomic_inc(&new_send->skb->users); |
| 410 | spin_lock_irqsave(&cm_node->retrans_list_lock, flags); | ||
| 411 | cm_node->send_entry = new_send; | ||
| 412 | add_ref_cm_node(cm_node); | ||
| 413 | spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); | ||
| 414 | new_send->timetosend = jiffies + NES_RETRY_TIMEOUT; | ||
| 423 | 415 | ||
| 424 | ret = nes_nic_cm_xmit(new_send->skb, cm_node->netdev); | 416 | ret = nes_nic_cm_xmit(new_send->skb, cm_node->netdev); |
| 425 | if (ret != NETDEV_TX_OK) { | 417 | if (ret != NETDEV_TX_OK) { |
| 426 | nes_debug(NES_DBG_CM, "Error sending packet %p (jiffies = %lu)\n", | 418 | nes_debug(NES_DBG_CM, "Error sending packet %p " |
| 427 | new_send, jiffies); | 419 | "(jiffies = %lu)\n", new_send, jiffies); |
| 428 | atomic_dec(&new_send->skb->users); | 420 | atomic_dec(&new_send->skb->users); |
| 429 | new_send->timetosend = jiffies; | 421 | new_send->timetosend = jiffies; |
| 430 | } else { | 422 | } else { |
| 431 | cm_packets_sent++; | 423 | cm_packets_sent++; |
| 432 | if (!send_retrans) { | 424 | if (!send_retrans) { |
| 425 | cleanup_retrans_entry(cm_node); | ||
| 433 | if (close_when_complete) | 426 | if (close_when_complete) |
| 434 | rem_ref_cm_node(cm_node->cm_core, cm_node); | 427 | rem_ref_cm_node(cm_core, cm_node); |
| 435 | dev_kfree_skb_any(new_send->skb); | ||
| 436 | kfree(new_send); | ||
| 437 | return ret; | 428 | return ret; |
| 438 | } | 429 | } |
| 439 | new_send->timetosend = jiffies + NES_RETRY_TIMEOUT; | ||
| 440 | } | 430 | } |
| 441 | spin_lock_irqsave(&cm_node->retrans_list_lock, flags); | ||
| 442 | list_add_tail(&new_send->list, &cm_node->retrans_list); | ||
| 443 | spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); | ||
| 444 | } | ||
| 445 | if (type == NES_TIMER_TYPE_RECV) { | ||
| 446 | new_send->seq_num = ntohl(tcp_hdr(skb)->seq); | ||
| 447 | new_send->timetosend = jiffies; | ||
| 448 | spin_lock_irqsave(&cm_node->recv_list_lock, flags); | ||
| 449 | list_add_tail(&new_send->list, &cm_node->recv_list); | ||
| 450 | spin_unlock_irqrestore(&cm_node->recv_list_lock, flags); | ||
| 451 | } | 431 | } |
| 452 | cm_core = cm_node->cm_core; | ||
| 453 | 432 | ||
| 454 | was_timer_set = timer_pending(&cm_core->tcp_timer); | 433 | was_timer_set = timer_pending(&cm_core->tcp_timer); |
| 455 | 434 | ||
| @@ -476,23 +455,27 @@ static void nes_cm_timer_tick(unsigned long pass) | |||
| 476 | struct list_head *list_node, *list_node_temp; | 455 | struct list_head *list_node, *list_node_temp; |
| 477 | struct nes_cm_core *cm_core = g_cm_core; | 456 | struct nes_cm_core *cm_core = g_cm_core; |
| 478 | struct nes_qp *nesqp; | 457 | struct nes_qp *nesqp; |
| 479 | struct sk_buff *skb; | ||
| 480 | u32 settimer = 0; | 458 | u32 settimer = 0; |
| 481 | int ret = NETDEV_TX_OK; | 459 | int ret = NETDEV_TX_OK; |
| 482 | int node_done; | 460 | enum nes_cm_node_state last_state; |
| 483 | 461 | ||
| 484 | spin_lock_irqsave(&cm_core->ht_lock, flags); | 462 | spin_lock_irqsave(&cm_core->ht_lock, flags); |
| 485 | 463 | ||
| 486 | list_for_each_safe(list_node, list_core_temp, &cm_core->connected_nodes) { | 464 | list_for_each_safe(list_node, list_core_temp, |
| 465 | &cm_core->connected_nodes) { | ||
| 487 | cm_node = container_of(list_node, struct nes_cm_node, list); | 466 | cm_node = container_of(list_node, struct nes_cm_node, list); |
| 488 | add_ref_cm_node(cm_node); | 467 | add_ref_cm_node(cm_node); |
| 489 | spin_unlock_irqrestore(&cm_core->ht_lock, flags); | 468 | spin_unlock_irqrestore(&cm_core->ht_lock, flags); |
| 490 | spin_lock_irqsave(&cm_node->recv_list_lock, flags); | 469 | spin_lock_irqsave(&cm_node->recv_list_lock, flags); |
| 491 | list_for_each_safe(list_core, list_node_temp, &cm_node->recv_list) { | 470 | list_for_each_safe(list_core, list_node_temp, |
| 492 | recv_entry = container_of(list_core, struct nes_timer_entry, list); | 471 | &cm_node->recv_list) { |
| 493 | if ((time_after(recv_entry->timetosend, jiffies)) && | 472 | recv_entry = container_of(list_core, |
| 494 | (recv_entry->type == NES_TIMER_TYPE_CLOSE)) { | 473 | struct nes_timer_entry, list); |
| 495 | if (nexttimeout > recv_entry->timetosend || !settimer) { | 474 | if (!recv_entry) |
| 475 | break; | ||
| 476 | if (time_after(recv_entry->timetosend, jiffies)) { | ||
| 477 | if (nexttimeout > recv_entry->timetosend || | ||
| 478 | !settimer) { | ||
| 496 | nexttimeout = recv_entry->timetosend; | 479 | nexttimeout = recv_entry->timetosend; |
| 497 | settimer = 1; | 480 | settimer = 1; |
| 498 | } | 481 | } |
| @@ -501,157 +484,143 @@ static void nes_cm_timer_tick(unsigned long pass) | |||
| 501 | list_del(&recv_entry->list); | 484 | list_del(&recv_entry->list); |
| 502 | cm_id = cm_node->cm_id; | 485 | cm_id = cm_node->cm_id; |
| 503 | spin_unlock_irqrestore(&cm_node->recv_list_lock, flags); | 486 | spin_unlock_irqrestore(&cm_node->recv_list_lock, flags); |
| 504 | if (recv_entry->type == NES_TIMER_TYPE_CLOSE) { | 487 | nesqp = (struct nes_qp *)recv_entry->skb; |
| 505 | nesqp = (struct nes_qp *)recv_entry->skb; | 488 | spin_lock_irqsave(&nesqp->lock, qplockflags); |
| 506 | spin_lock_irqsave(&nesqp->lock, qplockflags); | 489 | if (nesqp->cm_id) { |
| 507 | if (nesqp->cm_id) { | 490 | nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, " |
| 508 | nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, refcount = %d: " | 491 | "refcount = %d: HIT A " |
| 509 | "****** HIT A NES_TIMER_TYPE_CLOSE" | 492 | "NES_TIMER_TYPE_CLOSE with something " |
| 510 | " with something to do!!! ******\n", | 493 | "to do!!!\n", nesqp->hwqp.qp_id, cm_id, |
| 511 | nesqp->hwqp.qp_id, cm_id, | 494 | atomic_read(&nesqp->refcount)); |
| 512 | atomic_read(&nesqp->refcount)); | 495 | nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; |
| 513 | nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; | 496 | nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT; |
| 514 | nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT; | 497 | nesqp->ibqp_state = IB_QPS_ERR; |
| 515 | nesqp->ibqp_state = IB_QPS_ERR; | 498 | spin_unlock_irqrestore(&nesqp->lock, |
| 516 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); | 499 | qplockflags); |
| 517 | nes_cm_disconn(nesqp); | 500 | nes_cm_disconn(nesqp); |
| 518 | } else { | 501 | } else { |
| 519 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); | 502 | spin_unlock_irqrestore(&nesqp->lock, |
| 520 | nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, refcount = %d:" | 503 | qplockflags); |
| 521 | " ****** HIT A NES_TIMER_TYPE_CLOSE" | 504 | nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, " |
| 522 | " with nothing to do!!! ******\n", | 505 | "refcount = %d: HIT A " |
| 523 | nesqp->hwqp.qp_id, cm_id, | 506 | "NES_TIMER_TYPE_CLOSE with nothing " |
| 524 | atomic_read(&nesqp->refcount)); | 507 | "to do!!!\n", nesqp->hwqp.qp_id, cm_id, |
| 525 | nes_rem_ref(&nesqp->ibqp); | 508 | atomic_read(&nesqp->refcount)); |
| 526 | } | ||
| 527 | if (cm_id) | ||
| 528 | cm_id->rem_ref(cm_id); | ||
| 529 | } | 509 | } |
| 510 | if (cm_id) | ||
| 511 | cm_id->rem_ref(cm_id); | ||
| 512 | |||
| 530 | kfree(recv_entry); | 513 | kfree(recv_entry); |
| 531 | spin_lock_irqsave(&cm_node->recv_list_lock, flags); | 514 | spin_lock_irqsave(&cm_node->recv_list_lock, flags); |
| 532 | } | 515 | } |
| 533 | spin_unlock_irqrestore(&cm_node->recv_list_lock, flags); | 516 | spin_unlock_irqrestore(&cm_node->recv_list_lock, flags); |
| 534 | 517 | ||
| 535 | spin_lock_irqsave(&cm_node->retrans_list_lock, flags); | 518 | spin_lock_irqsave(&cm_node->retrans_list_lock, flags); |
| 536 | node_done = 0; | 519 | do { |
| 537 | list_for_each_safe(list_core, list_node_temp, &cm_node->retrans_list) { | 520 | send_entry = cm_node->send_entry; |
| 538 | if (node_done) { | 521 | if (!send_entry) |
| 539 | break; | 522 | continue; |
| 540 | } | ||
| 541 | send_entry = container_of(list_core, struct nes_timer_entry, list); | ||
| 542 | if (time_after(send_entry->timetosend, jiffies)) { | 523 | if (time_after(send_entry->timetosend, jiffies)) { |
| 543 | if (cm_node->state != NES_CM_STATE_TSA) { | 524 | if (cm_node->state != NES_CM_STATE_TSA) { |
| 544 | if ((nexttimeout > send_entry->timetosend) || !settimer) { | 525 | if ((nexttimeout > |
| 545 | nexttimeout = send_entry->timetosend; | 526 | send_entry->timetosend) || |
| 527 | !settimer) { | ||
| 528 | nexttimeout = | ||
| 529 | send_entry->timetosend; | ||
| 546 | settimer = 1; | 530 | settimer = 1; |
| 531 | continue; | ||
| 547 | } | 532 | } |
| 548 | node_done = 1; | ||
| 549 | continue; | ||
| 550 | } else { | 533 | } else { |
| 551 | list_del(&send_entry->list); | 534 | free_retrans_entry(cm_node); |
| 552 | skb = send_entry->skb; | ||
| 553 | spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); | ||
| 554 | dev_kfree_skb_any(skb); | ||
| 555 | kfree(send_entry); | ||
| 556 | spin_lock_irqsave(&cm_node->retrans_list_lock, flags); | ||
| 557 | continue; | 535 | continue; |
| 558 | } | 536 | } |
| 559 | } | 537 | } |
| 560 | if (send_entry->type == NES_TIMER_NODE_CLEANUP) { | 538 | |
| 561 | list_del(&send_entry->list); | 539 | if ((cm_node->state == NES_CM_STATE_TSA) || |
| 562 | spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); | 540 | (cm_node->state == NES_CM_STATE_CLOSED)) { |
| 563 | kfree(send_entry); | 541 | free_retrans_entry(cm_node); |
| 564 | spin_lock_irqsave(&cm_node->retrans_list_lock, flags); | ||
| 565 | continue; | ||
| 566 | } | ||
| 567 | if ((send_entry->seq_num < cm_node->tcp_cntxt.rem_ack_num) || | ||
| 568 | (cm_node->state == NES_CM_STATE_TSA) || | ||
| 569 | (cm_node->state == NES_CM_STATE_CLOSED)) { | ||
| 570 | skb = send_entry->skb; | ||
| 571 | list_del(&send_entry->list); | ||
| 572 | spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); | ||
| 573 | kfree(send_entry); | ||
| 574 | dev_kfree_skb_any(skb); | ||
| 575 | spin_lock_irqsave(&cm_node->retrans_list_lock, flags); | ||
| 576 | continue; | 542 | continue; |
| 577 | } | 543 | } |
| 578 | 544 | ||
| 579 | if (!send_entry->retranscount || !send_entry->retrycount) { | 545 | if (!send_entry->retranscount || |
| 546 | !send_entry->retrycount) { | ||
| 580 | cm_packets_dropped++; | 547 | cm_packets_dropped++; |
| 581 | skb = send_entry->skb; | 548 | last_state = cm_node->state; |
| 582 | list_del(&send_entry->list); | 549 | cm_node->state = NES_CM_STATE_CLOSED; |
| 583 | spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); | 550 | free_retrans_entry(cm_node); |
| 584 | dev_kfree_skb_any(skb); | 551 | spin_unlock_irqrestore( |
| 585 | kfree(send_entry); | 552 | &cm_node->retrans_list_lock, flags); |
| 586 | if (cm_node->state == NES_CM_STATE_SYN_RCVD) { | 553 | if (last_state == NES_CM_STATE_SYN_RCVD) |
| 587 | /* this node never even generated an indication up to the cm */ | ||
| 588 | rem_ref_cm_node(cm_core, cm_node); | 554 | rem_ref_cm_node(cm_core, cm_node); |
| 589 | } else { | 555 | else |
| 590 | cm_node->state = NES_CM_STATE_CLOSED; | 556 | create_event(cm_node, |
| 591 | create_event(cm_node, NES_CM_EVENT_ABORTED); | 557 | NES_CM_EVENT_ABORTED); |
| 592 | } | 558 | spin_lock_irqsave(&cm_node->retrans_list_lock, |
| 593 | spin_lock_irqsave(&cm_node->retrans_list_lock, flags); | 559 | flags); |
| 594 | continue; | 560 | continue; |
| 595 | } | 561 | } |
| 596 | /* this seems like the correct place, but leave send entry unprotected */ | ||
| 597 | /* spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); */ | ||
| 598 | atomic_inc(&send_entry->skb->users); | 562 | atomic_inc(&send_entry->skb->users); |
| 599 | cm_packets_retrans++; | 563 | cm_packets_retrans++; |
| 600 | nes_debug(NES_DBG_CM, "Retransmitting send_entry %p for node %p," | 564 | nes_debug(NES_DBG_CM, "Retransmitting send_entry %p " |
| 601 | " jiffies = %lu, time to send = %lu, retranscount = %u, " | 565 | "for node %p, jiffies = %lu, time to send = " |
| 602 | "send_entry->seq_num = 0x%08X, cm_node->tcp_cntxt.rem_ack_num = 0x%08X\n", | 566 | "%lu, retranscount = %u, send_entry->seq_num = " |
| 603 | send_entry, cm_node, jiffies, send_entry->timetosend, send_entry->retranscount, | 567 | "0x%08X, cm_node->tcp_cntxt.rem_ack_num = " |
| 604 | send_entry->seq_num, cm_node->tcp_cntxt.rem_ack_num); | 568 | "0x%08X\n", send_entry, cm_node, jiffies, |
| 605 | 569 | send_entry->timetosend, | |
| 606 | spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); | 570 | send_entry->retranscount, |
| 571 | send_entry->seq_num, | ||
| 572 | cm_node->tcp_cntxt.rem_ack_num); | ||
| 573 | |||
| 574 | spin_unlock_irqrestore(&cm_node->retrans_list_lock, | ||
| 575 | flags); | ||
| 607 | ret = nes_nic_cm_xmit(send_entry->skb, cm_node->netdev); | 576 | ret = nes_nic_cm_xmit(send_entry->skb, cm_node->netdev); |
| 577 | spin_lock_irqsave(&cm_node->retrans_list_lock, flags); | ||
| 608 | if (ret != NETDEV_TX_OK) { | 578 | if (ret != NETDEV_TX_OK) { |
| 579 | nes_debug(NES_DBG_CM, "rexmit failed for " | ||
| 580 | "node=%p\n", cm_node); | ||
| 609 | cm_packets_bounced++; | 581 | cm_packets_bounced++; |
| 610 | atomic_dec(&send_entry->skb->users); | 582 | atomic_dec(&send_entry->skb->users); |
| 611 | send_entry->retrycount--; | 583 | send_entry->retrycount--; |
| 612 | nexttimeout = jiffies + NES_SHORT_TIME; | 584 | nexttimeout = jiffies + NES_SHORT_TIME; |
| 613 | settimer = 1; | 585 | settimer = 1; |
| 614 | node_done = 1; | ||
| 615 | spin_lock_irqsave(&cm_node->retrans_list_lock, flags); | ||
| 616 | continue; | 586 | continue; |
| 617 | } else { | 587 | } else { |
| 618 | cm_packets_sent++; | 588 | cm_packets_sent++; |
| 619 | } | 589 | } |
| 620 | spin_lock_irqsave(&cm_node->retrans_list_lock, flags); | 590 | nes_debug(NES_DBG_CM, "Packet Sent: retrans count = " |
| 621 | list_del(&send_entry->list); | 591 | "%u, retry count = %u.\n", |
| 622 | nes_debug(NES_DBG_CM, "Packet Sent: retrans count = %u, retry count = %u.\n", | 592 | send_entry->retranscount, |
| 623 | send_entry->retranscount, send_entry->retrycount); | 593 | send_entry->retrycount); |
| 624 | if (send_entry->send_retrans) { | 594 | if (send_entry->send_retrans) { |
| 625 | send_entry->retranscount--; | 595 | send_entry->retranscount--; |
| 626 | send_entry->timetosend = jiffies + NES_RETRY_TIMEOUT; | 596 | send_entry->timetosend = jiffies + |
| 627 | if (nexttimeout > send_entry->timetosend || !settimer) { | 597 | NES_RETRY_TIMEOUT; |
| 598 | if (nexttimeout > send_entry->timetosend || | ||
| 599 | !settimer) { | ||
| 628 | nexttimeout = send_entry->timetosend; | 600 | nexttimeout = send_entry->timetosend; |
| 629 | settimer = 1; | 601 | settimer = 1; |
| 630 | } | 602 | } |
| 631 | list_add(&send_entry->list, &cm_node->retrans_list); | ||
| 632 | continue; | ||
| 633 | } else { | 603 | } else { |
| 634 | int close_when_complete; | 604 | int close_when_complete; |
| 635 | skb = send_entry->skb; | 605 | close_when_complete = |
| 636 | close_when_complete = send_entry->close_when_complete; | 606 | send_entry->close_when_complete; |
| 637 | spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); | 607 | nes_debug(NES_DBG_CM, "cm_node=%p state=%d\n", |
| 638 | if (close_when_complete) { | 608 | cm_node, cm_node->state); |
| 639 | BUG_ON(atomic_read(&cm_node->ref_count) == 1); | 609 | free_retrans_entry(cm_node); |
| 640 | rem_ref_cm_node(cm_core, cm_node); | 610 | if (close_when_complete) |
| 641 | } | 611 | rem_ref_cm_node(cm_node->cm_core, |
| 642 | dev_kfree_skb_any(skb); | 612 | cm_node); |
| 643 | kfree(send_entry); | ||
| 644 | spin_lock_irqsave(&cm_node->retrans_list_lock, flags); | ||
| 645 | continue; | ||
| 646 | } | 613 | } |
| 647 | } | 614 | } while (0); |
| 648 | spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); | ||
| 649 | |||
| 650 | rem_ref_cm_node(cm_core, cm_node); | ||
| 651 | 615 | ||
| 616 | spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); | ||
| 617 | rem_ref_cm_node(cm_node->cm_core, cm_node); | ||
| 652 | spin_lock_irqsave(&cm_core->ht_lock, flags); | 618 | spin_lock_irqsave(&cm_core->ht_lock, flags); |
| 653 | if (ret != NETDEV_TX_OK) | 619 | if (ret != NETDEV_TX_OK) { |
| 620 | nes_debug(NES_DBG_CM, "rexmit failed for cm_node=%p\n", | ||
| 621 | cm_node); | ||
| 654 | break; | 622 | break; |
| 623 | } | ||
| 655 | } | 624 | } |
| 656 | spin_unlock_irqrestore(&cm_core->ht_lock, flags); | 625 | spin_unlock_irqrestore(&cm_core->ht_lock, flags); |
| 657 | 626 | ||
| @@ -667,14 +636,14 @@ static void nes_cm_timer_tick(unsigned long pass) | |||
| 667 | /** | 636 | /** |
| 668 | * send_syn | 637 | * send_syn |
| 669 | */ | 638 | */ |
| 670 | static int send_syn(struct nes_cm_node *cm_node, u32 sendack) | 639 | static int send_syn(struct nes_cm_node *cm_node, u32 sendack, |
| 640 | struct sk_buff *skb) | ||
| 671 | { | 641 | { |
| 672 | int ret; | 642 | int ret; |
| 673 | int flags = SET_SYN; | 643 | int flags = SET_SYN; |
| 674 | struct sk_buff *skb; | ||
| 675 | char optionsbuffer[sizeof(struct option_mss) + | 644 | char optionsbuffer[sizeof(struct option_mss) + |
| 676 | sizeof(struct option_windowscale) + | 645 | sizeof(struct option_windowscale) + sizeof(struct option_base) + |
| 677 | sizeof(struct option_base) + 1]; | 646 | TCP_OPTIONS_PADDING]; |
| 678 | 647 | ||
| 679 | int optionssize = 0; | 648 | int optionssize = 0; |
| 680 | /* Sending MSS option */ | 649 | /* Sending MSS option */ |
| @@ -695,8 +664,7 @@ static int send_syn(struct nes_cm_node *cm_node, u32 sendack) | |||
| 695 | options->as_windowscale.shiftcount = cm_node->tcp_cntxt.rcv_wscale; | 664 | options->as_windowscale.shiftcount = cm_node->tcp_cntxt.rcv_wscale; |
| 696 | optionssize += sizeof(struct option_windowscale); | 665 | optionssize += sizeof(struct option_windowscale); |
| 697 | 666 | ||
| 698 | if (sendack && !(NES_DRV_OPT_SUPRESS_OPTION_BC & nes_drv_opt) | 667 | if (sendack && !(NES_DRV_OPT_SUPRESS_OPTION_BC & nes_drv_opt)) { |
| 699 | ) { | ||
| 700 | options = (union all_known_options *)&optionsbuffer[optionssize]; | 668 | options = (union all_known_options *)&optionsbuffer[optionssize]; |
| 701 | options->as_base.optionnum = OPTION_NUMBER_WRITE0; | 669 | options->as_base.optionnum = OPTION_NUMBER_WRITE0; |
| 702 | options->as_base.length = sizeof(struct option_base); | 670 | options->as_base.length = sizeof(struct option_base); |
| @@ -714,7 +682,8 @@ static int send_syn(struct nes_cm_node *cm_node, u32 sendack) | |||
| 714 | options->as_end = OPTION_NUMBER_END; | 682 | options->as_end = OPTION_NUMBER_END; |
| 715 | optionssize += 1; | 683 | optionssize += 1; |
| 716 | 684 | ||
| 717 | skb = get_free_pkt(cm_node); | 685 | if (!skb) |
| 686 | skb = get_free_pkt(cm_node); | ||
| 718 | if (!skb) { | 687 | if (!skb) { |
| 719 | nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n"); | 688 | nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n"); |
| 720 | return -1; | 689 | return -1; |
| @@ -733,18 +702,18 @@ static int send_syn(struct nes_cm_node *cm_node, u32 sendack) | |||
| 733 | /** | 702 | /** |
| 734 | * send_reset | 703 | * send_reset |
| 735 | */ | 704 | */ |
| 736 | static int send_reset(struct nes_cm_node *cm_node) | 705 | static int send_reset(struct nes_cm_node *cm_node, struct sk_buff *skb) |
| 737 | { | 706 | { |
| 738 | int ret; | 707 | int ret; |
| 739 | struct sk_buff *skb = get_free_pkt(cm_node); | ||
| 740 | int flags = SET_RST | SET_ACK; | 708 | int flags = SET_RST | SET_ACK; |
| 741 | 709 | ||
| 710 | if (!skb) | ||
| 711 | skb = get_free_pkt(cm_node); | ||
| 742 | if (!skb) { | 712 | if (!skb) { |
| 743 | nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n"); | 713 | nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n"); |
| 744 | return -1; | 714 | return -1; |
| 745 | } | 715 | } |
| 746 | 716 | ||
| 747 | add_ref_cm_node(cm_node); | ||
| 748 | form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, flags); | 717 | form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, flags); |
| 749 | ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 0, 1); | 718 | ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 0, 1); |
| 750 | 719 | ||
| @@ -755,10 +724,12 @@ static int send_reset(struct nes_cm_node *cm_node) | |||
| 755 | /** | 724 | /** |
| 756 | * send_ack | 725 | * send_ack |
| 757 | */ | 726 | */ |
| 758 | static int send_ack(struct nes_cm_node *cm_node) | 727 | static int send_ack(struct nes_cm_node *cm_node, struct sk_buff *skb) |
| 759 | { | 728 | { |
| 760 | int ret; | 729 | int ret; |
| 761 | struct sk_buff *skb = get_free_pkt(cm_node); | 730 | |
| 731 | if (!skb) | ||
| 732 | skb = get_free_pkt(cm_node); | ||
| 762 | 733 | ||
| 763 | if (!skb) { | 734 | if (!skb) { |
| 764 | nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n"); | 735 | nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n"); |
| @@ -922,7 +893,8 @@ static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node | |||
| 922 | if (!cm_node || !cm_core) | 893 | if (!cm_node || !cm_core) |
| 923 | return -EINVAL; | 894 | return -EINVAL; |
| 924 | 895 | ||
| 925 | nes_debug(NES_DBG_CM, "Adding Node to Active Connection HT\n"); | 896 | nes_debug(NES_DBG_CM, "Adding Node %p to Active Connection HT\n", |
| 897 | cm_node); | ||
| 926 | 898 | ||
| 927 | /* first, make an index into our hash table */ | 899 | /* first, make an index into our hash table */ |
| 928 | hashkey = make_hashkey(cm_node->loc_port, cm_node->loc_addr, | 900 | hashkey = make_hashkey(cm_node->loc_port, cm_node->loc_addr, |
| @@ -946,10 +918,35 @@ static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node | |||
| 946 | * mini_cm_dec_refcnt_listen | 918 | * mini_cm_dec_refcnt_listen |
| 947 | */ | 919 | */ |
| 948 | static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core, | 920 | static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core, |
| 949 | struct nes_cm_listener *listener, int free_hanging_nodes) | 921 | struct nes_cm_listener *listener, int free_hanging_nodes) |
| 950 | { | 922 | { |
| 951 | int ret = 1; | 923 | int ret = 1; |
| 952 | unsigned long flags; | 924 | unsigned long flags; |
| 925 | struct list_head *list_pos = NULL; | ||
| 926 | struct list_head *list_temp = NULL; | ||
| 927 | struct nes_cm_node *cm_node = NULL; | ||
| 928 | |||
| 929 | nes_debug(NES_DBG_CM, "attempting listener= %p free_nodes= %d, " | ||
| 930 | "refcnt=%d\n", listener, free_hanging_nodes, | ||
| 931 | atomic_read(&listener->ref_count)); | ||
| 932 | /* free non-accelerated child nodes for this listener */ | ||
| 933 | if (free_hanging_nodes) { | ||
| 934 | spin_lock_irqsave(&cm_core->ht_lock, flags); | ||
| 935 | list_for_each_safe(list_pos, list_temp, | ||
| 936 | &g_cm_core->connected_nodes) { | ||
| 937 | cm_node = container_of(list_pos, struct nes_cm_node, | ||
| 938 | list); | ||
| 939 | if ((cm_node->listener == listener) && | ||
| 940 | (!cm_node->accelerated)) { | ||
| 941 | cleanup_retrans_entry(cm_node); | ||
| 942 | spin_unlock_irqrestore(&cm_core->ht_lock, | ||
| 943 | flags); | ||
| 944 | send_reset(cm_node, NULL); | ||
| 945 | spin_lock_irqsave(&cm_core->ht_lock, flags); | ||
| 946 | } | ||
| 947 | } | ||
| 948 | spin_unlock_irqrestore(&cm_core->ht_lock, flags); | ||
| 949 | } | ||
| 953 | spin_lock_irqsave(&cm_core->listen_list_lock, flags); | 950 | spin_lock_irqsave(&cm_core->listen_list_lock, flags); |
| 954 | if (!atomic_dec_return(&listener->ref_count)) { | 951 | if (!atomic_dec_return(&listener->ref_count)) { |
| 955 | list_del(&listener->list); | 952 | list_del(&listener->list); |
| @@ -1067,18 +1064,18 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core, | |||
| 1067 | cm_node->loc_port = cm_info->loc_port; | 1064 | cm_node->loc_port = cm_info->loc_port; |
| 1068 | cm_node->rem_port = cm_info->rem_port; | 1065 | cm_node->rem_port = cm_info->rem_port; |
| 1069 | cm_node->send_write0 = send_first; | 1066 | cm_node->send_write0 = send_first; |
| 1070 | nes_debug(NES_DBG_CM, "Make node addresses : loc = " NIPQUAD_FMT ":%x, rem = " NIPQUAD_FMT ":%x\n", | 1067 | nes_debug(NES_DBG_CM, "Make node addresses : loc = " NIPQUAD_FMT |
| 1071 | HIPQUAD(cm_node->loc_addr), cm_node->loc_port, | 1068 | ":%x, rem = " NIPQUAD_FMT ":%x\n", |
| 1072 | HIPQUAD(cm_node->rem_addr), cm_node->rem_port); | 1069 | HIPQUAD(cm_node->loc_addr), cm_node->loc_port, |
| 1070 | HIPQUAD(cm_node->rem_addr), cm_node->rem_port); | ||
| 1073 | cm_node->listener = listener; | 1071 | cm_node->listener = listener; |
| 1074 | cm_node->netdev = nesvnic->netdev; | 1072 | cm_node->netdev = nesvnic->netdev; |
| 1075 | cm_node->cm_id = cm_info->cm_id; | 1073 | cm_node->cm_id = cm_info->cm_id; |
| 1076 | memcpy(cm_node->loc_mac, nesvnic->netdev->dev_addr, ETH_ALEN); | 1074 | memcpy(cm_node->loc_mac, nesvnic->netdev->dev_addr, ETH_ALEN); |
| 1077 | 1075 | ||
| 1078 | nes_debug(NES_DBG_CM, "listener=%p, cm_id=%p\n", | 1076 | nes_debug(NES_DBG_CM, "listener=%p, cm_id=%p\n", cm_node->listener, |
| 1079 | cm_node->listener, cm_node->cm_id); | 1077 | cm_node->cm_id); |
| 1080 | 1078 | ||
| 1081 | INIT_LIST_HEAD(&cm_node->retrans_list); | ||
| 1082 | spin_lock_init(&cm_node->retrans_list_lock); | 1079 | spin_lock_init(&cm_node->retrans_list_lock); |
| 1083 | INIT_LIST_HEAD(&cm_node->recv_list); | 1080 | INIT_LIST_HEAD(&cm_node->recv_list); |
| 1084 | spin_lock_init(&cm_node->recv_list_lock); | 1081 | spin_lock_init(&cm_node->recv_list_lock); |
| @@ -1142,10 +1139,9 @@ static int add_ref_cm_node(struct nes_cm_node *cm_node) | |||
| 1142 | * rem_ref_cm_node - destroy an instance of a cm node | 1139 | * rem_ref_cm_node - destroy an instance of a cm node |
| 1143 | */ | 1140 | */ |
| 1144 | static int rem_ref_cm_node(struct nes_cm_core *cm_core, | 1141 | static int rem_ref_cm_node(struct nes_cm_core *cm_core, |
| 1145 | struct nes_cm_node *cm_node) | 1142 | struct nes_cm_node *cm_node) |
| 1146 | { | 1143 | { |
| 1147 | unsigned long flags, qplockflags; | 1144 | unsigned long flags, qplockflags; |
| 1148 | struct nes_timer_entry *send_entry; | ||
| 1149 | struct nes_timer_entry *recv_entry; | 1145 | struct nes_timer_entry *recv_entry; |
| 1150 | struct iw_cm_id *cm_id; | 1146 | struct iw_cm_id *cm_id; |
| 1151 | struct list_head *list_core, *list_node_temp; | 1147 | struct list_head *list_core, *list_node_temp; |
| @@ -1169,48 +1165,33 @@ static int rem_ref_cm_node(struct nes_cm_core *cm_core, | |||
| 1169 | atomic_dec(&cm_node->listener->pend_accepts_cnt); | 1165 | atomic_dec(&cm_node->listener->pend_accepts_cnt); |
| 1170 | BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0); | 1166 | BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0); |
| 1171 | } | 1167 | } |
| 1172 | 1168 | BUG_ON(cm_node->send_entry); | |
| 1173 | spin_lock_irqsave(&cm_node->retrans_list_lock, flags); | ||
| 1174 | list_for_each_safe(list_core, list_node_temp, &cm_node->retrans_list) { | ||
| 1175 | send_entry = container_of(list_core, struct nes_timer_entry, list); | ||
| 1176 | list_del(&send_entry->list); | ||
| 1177 | spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); | ||
| 1178 | dev_kfree_skb_any(send_entry->skb); | ||
| 1179 | kfree(send_entry); | ||
| 1180 | spin_lock_irqsave(&cm_node->retrans_list_lock, flags); | ||
| 1181 | continue; | ||
| 1182 | } | ||
| 1183 | spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); | ||
| 1184 | |||
| 1185 | spin_lock_irqsave(&cm_node->recv_list_lock, flags); | 1169 | spin_lock_irqsave(&cm_node->recv_list_lock, flags); |
| 1186 | list_for_each_safe(list_core, list_node_temp, &cm_node->recv_list) { | 1170 | list_for_each_safe(list_core, list_node_temp, &cm_node->recv_list) { |
| 1187 | recv_entry = container_of(list_core, struct nes_timer_entry, list); | 1171 | recv_entry = container_of(list_core, struct nes_timer_entry, |
| 1172 | list); | ||
| 1188 | list_del(&recv_entry->list); | 1173 | list_del(&recv_entry->list); |
| 1189 | cm_id = cm_node->cm_id; | 1174 | cm_id = cm_node->cm_id; |
| 1190 | spin_unlock_irqrestore(&cm_node->recv_list_lock, flags); | 1175 | spin_unlock_irqrestore(&cm_node->recv_list_lock, flags); |
| 1191 | if (recv_entry->type == NES_TIMER_TYPE_CLOSE) { | 1176 | nesqp = (struct nes_qp *)recv_entry->skb; |
| 1192 | nesqp = (struct nes_qp *)recv_entry->skb; | 1177 | spin_lock_irqsave(&nesqp->lock, qplockflags); |
| 1193 | spin_lock_irqsave(&nesqp->lock, qplockflags); | 1178 | if (nesqp->cm_id) { |
| 1194 | if (nesqp->cm_id) { | 1179 | nes_debug(NES_DBG_CM, "QP%u: cm_id = %p: HIT A " |
| 1195 | nes_debug(NES_DBG_CM, "QP%u: cm_id = %p: ****** HIT A NES_TIMER_TYPE_CLOSE" | 1180 | "NES_TIMER_TYPE_CLOSE with something to do!\n", |
| 1196 | " with something to do!!! ******\n", | 1181 | nesqp->hwqp.qp_id, cm_id); |
| 1197 | nesqp->hwqp.qp_id, cm_id); | 1182 | nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; |
| 1198 | nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; | 1183 | nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT; |
| 1199 | nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT; | 1184 | nesqp->ibqp_state = IB_QPS_ERR; |
| 1200 | nesqp->ibqp_state = IB_QPS_ERR; | 1185 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); |
| 1201 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); | 1186 | nes_cm_disconn(nesqp); |
| 1202 | nes_cm_disconn(nesqp); | 1187 | } else { |
| 1203 | } else { | 1188 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); |
| 1204 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); | 1189 | nes_debug(NES_DBG_CM, "QP%u: cm_id = %p: HIT A " |
| 1205 | nes_debug(NES_DBG_CM, "QP%u: cm_id = %p: ****** HIT A NES_TIMER_TYPE_CLOSE" | 1190 | "NES_TIMER_TYPE_CLOSE with nothing to do!\n", |
| 1206 | " with nothing to do!!! ******\n", | 1191 | nesqp->hwqp.qp_id, cm_id); |
| 1207 | nesqp->hwqp.qp_id, cm_id); | ||
| 1208 | nes_rem_ref(&nesqp->ibqp); | ||
| 1209 | } | ||
| 1210 | cm_id->rem_ref(cm_id); | ||
| 1211 | } else if (recv_entry->type == NES_TIMER_TYPE_RECV) { | ||
| 1212 | dev_kfree_skb_any(recv_entry->skb); | ||
| 1213 | } | 1192 | } |
| 1193 | cm_id->rem_ref(cm_id); | ||
| 1194 | |||
| 1214 | kfree(recv_entry); | 1195 | kfree(recv_entry); |
| 1215 | spin_lock_irqsave(&cm_node->recv_list_lock, flags); | 1196 | spin_lock_irqsave(&cm_node->recv_list_lock, flags); |
| 1216 | } | 1197 | } |
| @@ -1221,23 +1202,31 @@ static int rem_ref_cm_node(struct nes_cm_core *cm_core, | |||
| 1221 | } else { | 1202 | } else { |
| 1222 | if (cm_node->apbvt_set && cm_node->nesvnic) { | 1203 | if (cm_node->apbvt_set && cm_node->nesvnic) { |
| 1223 | nes_manage_apbvt(cm_node->nesvnic, cm_node->loc_port, | 1204 | nes_manage_apbvt(cm_node->nesvnic, cm_node->loc_port, |
| 1224 | PCI_FUNC(cm_node->nesvnic->nesdev->pcidev->devfn), | 1205 | PCI_FUNC( |
| 1225 | NES_MANAGE_APBVT_DEL); | 1206 | cm_node->nesvnic->nesdev->pcidev->devfn), |
| 1207 | NES_MANAGE_APBVT_DEL); | ||
| 1226 | } | 1208 | } |
| 1227 | } | 1209 | } |
| 1228 | 1210 | ||
| 1229 | kfree(cm_node); | ||
| 1230 | atomic_dec(&cm_core->node_cnt); | 1211 | atomic_dec(&cm_core->node_cnt); |
| 1231 | atomic_inc(&cm_nodes_destroyed); | 1212 | atomic_inc(&cm_nodes_destroyed); |
| 1213 | nesqp = cm_node->nesqp; | ||
| 1214 | if (nesqp) { | ||
| 1215 | nesqp->cm_node = NULL; | ||
| 1216 | nes_rem_ref(&nesqp->ibqp); | ||
| 1217 | cm_node->nesqp = NULL; | ||
| 1218 | } | ||
| 1232 | 1219 | ||
| 1220 | cm_node->freed = 1; | ||
| 1221 | kfree(cm_node); | ||
| 1233 | return 0; | 1222 | return 0; |
| 1234 | } | 1223 | } |
| 1235 | 1224 | ||
| 1236 | |||
| 1237 | /** | 1225 | /** |
| 1238 | * process_options | 1226 | * process_options |
| 1239 | */ | 1227 | */ |
| 1240 | static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc, u32 optionsize, u32 syn_packet) | 1228 | static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc, |
| 1229 | u32 optionsize, u32 syn_packet) | ||
| 1241 | { | 1230 | { |
| 1242 | u32 tmp; | 1231 | u32 tmp; |
| 1243 | u32 offset = 0; | 1232 | u32 offset = 0; |
| @@ -1247,35 +1236,37 @@ static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc, u32 opti | |||
| 1247 | while (offset < optionsize) { | 1236 | while (offset < optionsize) { |
| 1248 | all_options = (union all_known_options *)(optionsloc + offset); | 1237 | all_options = (union all_known_options *)(optionsloc + offset); |
| 1249 | switch (all_options->as_base.optionnum) { | 1238 | switch (all_options->as_base.optionnum) { |
| 1250 | case OPTION_NUMBER_END: | 1239 | case OPTION_NUMBER_END: |
| 1251 | offset = optionsize; | 1240 | offset = optionsize; |
| 1252 | break; | 1241 | break; |
| 1253 | case OPTION_NUMBER_NONE: | 1242 | case OPTION_NUMBER_NONE: |
| 1254 | offset += 1; | 1243 | offset += 1; |
| 1255 | continue; | 1244 | continue; |
| 1256 | case OPTION_NUMBER_MSS: | 1245 | case OPTION_NUMBER_MSS: |
| 1257 | nes_debug(NES_DBG_CM, "%s: MSS Length: %d Offset: %d Size: %d\n", | 1246 | nes_debug(NES_DBG_CM, "%s: MSS Length: %d Offset: %d " |
| 1258 | __func__, | 1247 | "Size: %d\n", __func__, |
| 1259 | all_options->as_mss.length, offset, optionsize); | 1248 | all_options->as_mss.length, offset, optionsize); |
| 1260 | got_mss_option = 1; | 1249 | got_mss_option = 1; |
| 1261 | if (all_options->as_mss.length != 4) { | 1250 | if (all_options->as_mss.length != 4) { |
| 1262 | return 1; | 1251 | return 1; |
| 1263 | } else { | 1252 | } else { |
| 1264 | tmp = ntohs(all_options->as_mss.mss); | 1253 | tmp = ntohs(all_options->as_mss.mss); |
| 1265 | if (tmp > 0 && tmp < cm_node->tcp_cntxt.mss) | 1254 | if (tmp > 0 && tmp < |
| 1266 | cm_node->tcp_cntxt.mss = tmp; | 1255 | cm_node->tcp_cntxt.mss) |
| 1267 | } | 1256 | cm_node->tcp_cntxt.mss = tmp; |
| 1268 | break; | 1257 | } |
| 1269 | case OPTION_NUMBER_WINDOW_SCALE: | 1258 | break; |
| 1270 | cm_node->tcp_cntxt.snd_wscale = all_options->as_windowscale.shiftcount; | 1259 | case OPTION_NUMBER_WINDOW_SCALE: |
| 1271 | break; | 1260 | cm_node->tcp_cntxt.snd_wscale = |
| 1272 | case OPTION_NUMBER_WRITE0: | 1261 | all_options->as_windowscale.shiftcount; |
| 1273 | cm_node->send_write0 = 1; | 1262 | break; |
| 1274 | break; | 1263 | case OPTION_NUMBER_WRITE0: |
| 1275 | default: | 1264 | cm_node->send_write0 = 1; |
| 1276 | nes_debug(NES_DBG_CM, "TCP Option not understood: %x\n", | 1265 | break; |
| 1277 | all_options->as_base.optionnum); | 1266 | default: |
| 1278 | break; | 1267 | nes_debug(NES_DBG_CM, "TCP Option not understood: %x\n", |
| 1268 | all_options->as_base.optionnum); | ||
| 1269 | break; | ||
| 1279 | } | 1270 | } |
| 1280 | offset += all_options->as_base.length; | 1271 | offset += all_options->as_base.length; |
| 1281 | } | 1272 | } |
| @@ -1284,300 +1275,491 @@ static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc, u32 opti | |||
| 1284 | return 0; | 1275 | return 0; |
| 1285 | } | 1276 | } |
| 1286 | 1277 | ||
| 1278 | static void drop_packet(struct sk_buff *skb) | ||
| 1279 | { | ||
| 1280 | atomic_inc(&cm_accel_dropped_pkts); | ||
| 1281 | dev_kfree_skb_any(skb); | ||
| 1282 | } | ||
| 1287 | 1283 | ||
| 1288 | /** | 1284 | static void handle_fin_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, |
| 1289 | * process_packet | 1285 | struct tcphdr *tcph) |
| 1290 | */ | ||
| 1291 | static int process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb, | ||
| 1292 | struct nes_cm_core *cm_core) | ||
| 1293 | { | 1286 | { |
| 1294 | int optionsize; | 1287 | atomic_inc(&cm_resets_recvd); |
| 1295 | int datasize; | 1288 | nes_debug(NES_DBG_CM, "Received FIN, cm_node = %p, state = %u. " |
| 1296 | int ret = 0; | 1289 | "refcnt=%d\n", cm_node, cm_node->state, |
| 1297 | struct tcphdr *tcph = tcp_hdr(skb); | 1290 | atomic_read(&cm_node->ref_count)); |
| 1298 | u32 inc_sequence; | 1291 | cm_node->tcp_cntxt.rcv_nxt++; |
| 1299 | if (cm_node->state == NES_CM_STATE_SYN_SENT && tcph->syn) { | 1292 | cleanup_retrans_entry(cm_node); |
| 1300 | inc_sequence = ntohl(tcph->seq); | 1293 | switch (cm_node->state) { |
| 1301 | cm_node->tcp_cntxt.rcv_nxt = inc_sequence; | 1294 | case NES_CM_STATE_SYN_RCVD: |
| 1295 | case NES_CM_STATE_SYN_SENT: | ||
| 1296 | case NES_CM_STATE_ESTABLISHED: | ||
| 1297 | case NES_CM_STATE_MPAREQ_SENT: | ||
| 1298 | cm_node->state = NES_CM_STATE_LAST_ACK; | ||
| 1299 | send_fin(cm_node, skb); | ||
| 1300 | break; | ||
| 1301 | case NES_CM_STATE_FIN_WAIT1: | ||
| 1302 | cm_node->state = NES_CM_STATE_CLOSING; | ||
| 1303 | send_ack(cm_node, skb); | ||
| 1304 | break; | ||
| 1305 | case NES_CM_STATE_FIN_WAIT2: | ||
| 1306 | cm_node->state = NES_CM_STATE_TIME_WAIT; | ||
| 1307 | send_ack(cm_node, skb); | ||
| 1308 | cm_node->state = NES_CM_STATE_CLOSED; | ||
| 1309 | break; | ||
| 1310 | case NES_CM_STATE_TSA: | ||
| 1311 | default: | ||
| 1312 | nes_debug(NES_DBG_CM, "Error Rcvd FIN for node-%p state = %d\n", | ||
| 1313 | cm_node, cm_node->state); | ||
| 1314 | drop_packet(skb); | ||
| 1315 | break; | ||
| 1302 | } | 1316 | } |
| 1317 | } | ||
| 1303 | 1318 | ||
| 1304 | if ((!tcph) || (cm_node->state == NES_CM_STATE_TSA)) { | ||
| 1305 | BUG_ON(!tcph); | ||
| 1306 | atomic_inc(&cm_accel_dropped_pkts); | ||
| 1307 | return -1; | ||
| 1308 | } | ||
| 1309 | 1319 | ||
| 1310 | if (tcph->rst) { | 1320 | static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, |
| 1311 | atomic_inc(&cm_resets_recvd); | 1321 | struct tcphdr *tcph) |
| 1312 | nes_debug(NES_DBG_CM, "Received Reset, cm_node = %p, state = %u. refcnt=%d\n", | 1322 | { |
| 1313 | cm_node, cm_node->state, atomic_read(&cm_node->ref_count)); | ||
| 1314 | switch (cm_node->state) { | ||
| 1315 | case NES_CM_STATE_LISTENING: | ||
| 1316 | rem_ref_cm_node(cm_core, cm_node); | ||
| 1317 | break; | ||
| 1318 | case NES_CM_STATE_TSA: | ||
| 1319 | case NES_CM_STATE_CLOSED: | ||
| 1320 | break; | ||
| 1321 | case NES_CM_STATE_SYN_RCVD: | ||
| 1322 | nes_debug(NES_DBG_CM, "Received a reset for local 0x%08X:%04X," | ||
| 1323 | " remote 0x%08X:%04X, node state = %u\n", | ||
| 1324 | cm_node->loc_addr, cm_node->loc_port, | ||
| 1325 | cm_node->rem_addr, cm_node->rem_port, | ||
| 1326 | cm_node->state); | ||
| 1327 | rem_ref_cm_node(cm_core, cm_node); | ||
| 1328 | break; | ||
| 1329 | case NES_CM_STATE_ONE_SIDE_ESTABLISHED: | ||
| 1330 | case NES_CM_STATE_ESTABLISHED: | ||
| 1331 | case NES_CM_STATE_MPAREQ_SENT: | ||
| 1332 | default: | ||
| 1333 | nes_debug(NES_DBG_CM, "Received a reset for local 0x%08X:%04X," | ||
| 1334 | " remote 0x%08X:%04X, node state = %u refcnt=%d\n", | ||
| 1335 | cm_node->loc_addr, cm_node->loc_port, | ||
| 1336 | cm_node->rem_addr, cm_node->rem_port, | ||
| 1337 | cm_node->state, atomic_read(&cm_node->ref_count)); | ||
| 1338 | /* create event */ | ||
| 1339 | cm_node->state = NES_CM_STATE_CLOSED; | ||
| 1340 | 1323 | ||
| 1341 | create_event(cm_node, NES_CM_EVENT_ABORTED); | 1324 | int reset = 0; /* whether to send reset in case of err.. */ |
| 1342 | break; | 1325 | atomic_inc(&cm_resets_recvd); |
| 1326 | nes_debug(NES_DBG_CM, "Received Reset, cm_node = %p, state = %u." | ||
| 1327 | " refcnt=%d\n", cm_node, cm_node->state, | ||
| 1328 | atomic_read(&cm_node->ref_count)); | ||
| 1329 | cleanup_retrans_entry(cm_node); | ||
| 1330 | switch (cm_node->state) { | ||
| 1331 | case NES_CM_STATE_SYN_SENT: | ||
| 1332 | case NES_CM_STATE_MPAREQ_SENT: | ||
| 1333 | nes_debug(NES_DBG_CM, "%s[%u] create abort for cm_node=%p " | ||
| 1334 | "listener=%p state=%d\n", __func__, __LINE__, cm_node, | ||
| 1335 | cm_node->listener, cm_node->state); | ||
| 1336 | active_open_err(cm_node, skb, reset); | ||
| 1337 | break; | ||
| 1338 | /* For PASSIVE open states, remove the cm_node event */ | ||
| 1339 | case NES_CM_STATE_ESTABLISHED: | ||
| 1340 | case NES_CM_STATE_SYN_RCVD: | ||
| 1341 | case NES_CM_STATE_LISTENING: | ||
| 1342 | nes_debug(NES_DBG_CM, "Bad state %s[%u]\n", __func__, __LINE__); | ||
| 1343 | passive_open_err(cm_node, skb, reset); | ||
| 1344 | break; | ||
| 1345 | case NES_CM_STATE_TSA: | ||
| 1346 | default: | ||
| 1347 | break; | ||
| 1348 | } | ||
| 1349 | } | ||
| 1343 | 1350 | ||
| 1351 | static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb, | ||
| 1352 | enum nes_cm_event_type type) | ||
| 1353 | { | ||
| 1354 | |||
| 1355 | int ret; | ||
| 1356 | int datasize = skb->len; | ||
| 1357 | u8 *dataloc = skb->data; | ||
| 1358 | ret = parse_mpa(cm_node, dataloc, datasize); | ||
| 1359 | if (ret < 0) { | ||
| 1360 | nes_debug(NES_DBG_CM, "didn't like MPA Request\n"); | ||
| 1361 | if (type == NES_CM_EVENT_CONNECTED) { | ||
| 1362 | nes_debug(NES_DBG_CM, "%s[%u] create abort for " | ||
| 1363 | "cm_node=%p listener=%p state=%d\n", __func__, | ||
| 1364 | __LINE__, cm_node, cm_node->listener, | ||
| 1365 | cm_node->state); | ||
| 1366 | active_open_err(cm_node, skb, 1); | ||
| 1367 | } else { | ||
| 1368 | passive_open_err(cm_node, skb, 1); | ||
| 1344 | } | 1369 | } |
| 1345 | return -1; | 1370 | } else { |
| 1371 | cleanup_retrans_entry(cm_node); | ||
| 1372 | dev_kfree_skb_any(skb); | ||
| 1373 | if (type == NES_CM_EVENT_CONNECTED) | ||
| 1374 | cm_node->state = NES_CM_STATE_TSA; | ||
| 1375 | create_event(cm_node, type); | ||
| 1376 | |||
| 1377 | } | ||
| 1378 | return ; | ||
| 1379 | } | ||
| 1380 | |||
| 1381 | static void indicate_pkt_err(struct nes_cm_node *cm_node, struct sk_buff *skb) | ||
| 1382 | { | ||
| 1383 | switch (cm_node->state) { | ||
| 1384 | case NES_CM_STATE_SYN_SENT: | ||
| 1385 | case NES_CM_STATE_MPAREQ_SENT: | ||
| 1386 | nes_debug(NES_DBG_CM, "%s[%u] create abort for cm_node=%p " | ||
| 1387 | "listener=%p state=%d\n", __func__, __LINE__, cm_node, | ||
| 1388 | cm_node->listener, cm_node->state); | ||
| 1389 | active_open_err(cm_node, skb, 1); | ||
| 1390 | break; | ||
| 1391 | case NES_CM_STATE_ESTABLISHED: | ||
| 1392 | case NES_CM_STATE_SYN_RCVD: | ||
| 1393 | passive_open_err(cm_node, skb, 1); | ||
| 1394 | break; | ||
| 1395 | case NES_CM_STATE_TSA: | ||
| 1396 | default: | ||
| 1397 | drop_packet(skb); | ||
| 1346 | } | 1398 | } |
| 1399 | } | ||
| 1400 | |||
| 1401 | static int check_syn(struct nes_cm_node *cm_node, struct tcphdr *tcph, | ||
| 1402 | struct sk_buff *skb) | ||
| 1403 | { | ||
| 1404 | int err; | ||
| 1405 | |||
| 1406 | err = ((ntohl(tcph->ack_seq) == cm_node->tcp_cntxt.loc_seq_num))? 0 : 1; | ||
| 1407 | if (err) | ||
| 1408 | active_open_err(cm_node, skb, 1); | ||
| 1409 | |||
| 1410 | return err; | ||
| 1411 | } | ||
| 1412 | |||
| 1413 | static int check_seq(struct nes_cm_node *cm_node, struct tcphdr *tcph, | ||
| 1414 | struct sk_buff *skb) | ||
| 1415 | { | ||
| 1416 | int err = 0; | ||
| 1417 | u32 seq; | ||
| 1418 | u32 ack_seq; | ||
| 1419 | u32 loc_seq_num = cm_node->tcp_cntxt.loc_seq_num; | ||
| 1420 | u32 rcv_nxt = cm_node->tcp_cntxt.rcv_nxt; | ||
| 1421 | u32 rcv_wnd; | ||
| 1422 | seq = ntohl(tcph->seq); | ||
| 1423 | ack_seq = ntohl(tcph->ack_seq); | ||
| 1424 | rcv_wnd = cm_node->tcp_cntxt.rcv_wnd; | ||
| 1425 | if (ack_seq != loc_seq_num) | ||
| 1426 | err = 1; | ||
| 1427 | else if ((seq + rcv_wnd) < rcv_nxt) | ||
| 1428 | err = 1; | ||
| 1429 | if (err) { | ||
| 1430 | nes_debug(NES_DBG_CM, "%s[%u] create abort for cm_node=%p " | ||
| 1431 | "listener=%p state=%d\n", __func__, __LINE__, cm_node, | ||
| 1432 | cm_node->listener, cm_node->state); | ||
| 1433 | indicate_pkt_err(cm_node, skb); | ||
| 1434 | nes_debug(NES_DBG_CM, "seq ERROR cm_node =%p seq=0x%08X " | ||
| 1435 | "rcv_nxt=0x%08X rcv_wnd=0x%x\n", cm_node, seq, rcv_nxt, | ||
| 1436 | rcv_wnd); | ||
| 1437 | } | ||
| 1438 | return err; | ||
| 1439 | } | ||
| 1440 | |||
| 1441 | /* | ||
| 1442 | * handle_syn_pkt() is for Passive node. The syn packet is received when a node | ||
| 1443 | * is created with a listener or it may comein as rexmitted packet which in | ||
| 1444 | * that case will be just dropped. | ||
| 1445 | */ | ||
| 1446 | |||
| 1447 | static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, | ||
| 1448 | struct tcphdr *tcph) | ||
| 1449 | { | ||
| 1450 | int ret; | ||
| 1451 | u32 inc_sequence; | ||
| 1452 | int optionsize; | ||
| 1347 | 1453 | ||
| 1348 | optionsize = (tcph->doff << 2) - sizeof(struct tcphdr); | 1454 | optionsize = (tcph->doff << 2) - sizeof(struct tcphdr); |
| 1455 | skb_pull(skb, tcph->doff << 2); | ||
| 1456 | inc_sequence = ntohl(tcph->seq); | ||
| 1349 | 1457 | ||
| 1350 | skb_pull(skb, ip_hdr(skb)->ihl << 2); | 1458 | switch (cm_node->state) { |
| 1459 | case NES_CM_STATE_SYN_SENT: | ||
| 1460 | case NES_CM_STATE_MPAREQ_SENT: | ||
| 1461 | /* Rcvd syn on active open connection*/ | ||
| 1462 | active_open_err(cm_node, skb, 1); | ||
| 1463 | break; | ||
| 1464 | case NES_CM_STATE_LISTENING: | ||
| 1465 | /* Passive OPEN */ | ||
| 1466 | cm_node->accept_pend = 1; | ||
| 1467 | atomic_inc(&cm_node->listener->pend_accepts_cnt); | ||
| 1468 | if (atomic_read(&cm_node->listener->pend_accepts_cnt) > | ||
| 1469 | cm_node->listener->backlog) { | ||
| 1470 | nes_debug(NES_DBG_CM, "drop syn due to backlog " | ||
| 1471 | "pressure \n"); | ||
| 1472 | cm_backlog_drops++; | ||
| 1473 | passive_open_err(cm_node, skb, 0); | ||
| 1474 | break; | ||
| 1475 | } | ||
| 1476 | ret = handle_tcp_options(cm_node, tcph, skb, optionsize, | ||
| 1477 | 1); | ||
| 1478 | if (ret) { | ||
| 1479 | passive_open_err(cm_node, skb, 0); | ||
| 1480 | /* drop pkt */ | ||
| 1481 | break; | ||
| 1482 | } | ||
| 1483 | cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1; | ||
| 1484 | BUG_ON(cm_node->send_entry); | ||
| 1485 | cm_node->state = NES_CM_STATE_SYN_RCVD; | ||
| 1486 | send_syn(cm_node, 1, skb); | ||
| 1487 | break; | ||
| 1488 | case NES_CM_STATE_TSA: | ||
| 1489 | case NES_CM_STATE_ESTABLISHED: | ||
| 1490 | case NES_CM_STATE_FIN_WAIT1: | ||
| 1491 | case NES_CM_STATE_FIN_WAIT2: | ||
| 1492 | case NES_CM_STATE_MPAREQ_RCVD: | ||
| 1493 | case NES_CM_STATE_LAST_ACK: | ||
| 1494 | case NES_CM_STATE_CLOSING: | ||
| 1495 | case NES_CM_STATE_UNKNOWN: | ||
| 1496 | case NES_CM_STATE_CLOSED: | ||
| 1497 | default: | ||
| 1498 | drop_packet(skb); | ||
| 1499 | break; | ||
| 1500 | } | ||
| 1501 | } | ||
| 1502 | |||
| 1503 | static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, | ||
| 1504 | struct tcphdr *tcph) | ||
| 1505 | { | ||
| 1506 | |||
| 1507 | int ret; | ||
| 1508 | u32 inc_sequence; | ||
| 1509 | int optionsize; | ||
| 1510 | |||
| 1511 | optionsize = (tcph->doff << 2) - sizeof(struct tcphdr); | ||
| 1351 | skb_pull(skb, tcph->doff << 2); | 1512 | skb_pull(skb, tcph->doff << 2); |
| 1513 | inc_sequence = ntohl(tcph->seq); | ||
| 1514 | switch (cm_node->state) { | ||
| 1515 | case NES_CM_STATE_SYN_SENT: | ||
| 1516 | /* active open */ | ||
| 1517 | if (check_syn(cm_node, tcph, skb)) | ||
| 1518 | return; | ||
| 1519 | cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq); | ||
| 1520 | /* setup options */ | ||
| 1521 | ret = handle_tcp_options(cm_node, tcph, skb, optionsize, 0); | ||
| 1522 | if (ret) { | ||
| 1523 | nes_debug(NES_DBG_CM, "cm_node=%p tcp_options failed\n", | ||
| 1524 | cm_node); | ||
| 1525 | break; | ||
| 1526 | } | ||
| 1527 | cleanup_retrans_entry(cm_node); | ||
| 1528 | cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1; | ||
| 1529 | send_mpa_request(cm_node, skb); | ||
| 1530 | cm_node->state = NES_CM_STATE_MPAREQ_SENT; | ||
| 1531 | break; | ||
| 1532 | case NES_CM_STATE_MPAREQ_RCVD: | ||
| 1533 | /* passive open, so should not be here */ | ||
| 1534 | passive_open_err(cm_node, skb, 1); | ||
| 1535 | break; | ||
| 1536 | case NES_CM_STATE_ESTABLISHED: | ||
| 1537 | case NES_CM_STATE_FIN_WAIT1: | ||
| 1538 | case NES_CM_STATE_FIN_WAIT2: | ||
| 1539 | case NES_CM_STATE_LAST_ACK: | ||
| 1540 | case NES_CM_STATE_TSA: | ||
| 1541 | case NES_CM_STATE_CLOSING: | ||
| 1542 | case NES_CM_STATE_UNKNOWN: | ||
| 1543 | case NES_CM_STATE_CLOSED: | ||
| 1544 | case NES_CM_STATE_MPAREQ_SENT: | ||
| 1545 | default: | ||
| 1546 | drop_packet(skb); | ||
| 1547 | break; | ||
| 1548 | } | ||
| 1549 | } | ||
| 1352 | 1550 | ||
| 1353 | datasize = skb->len; | 1551 | static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, |
| 1552 | struct tcphdr *tcph) | ||
| 1553 | { | ||
| 1554 | int datasize = 0; | ||
| 1555 | u32 inc_sequence; | ||
| 1556 | u32 rem_seq_ack; | ||
| 1557 | u32 rem_seq; | ||
| 1558 | if (check_seq(cm_node, tcph, skb)) | ||
| 1559 | return; | ||
| 1560 | |||
| 1561 | skb_pull(skb, tcph->doff << 2); | ||
| 1354 | inc_sequence = ntohl(tcph->seq); | 1562 | inc_sequence = ntohl(tcph->seq); |
| 1355 | nes_debug(NES_DBG_CM, "datasize = %u, sequence = 0x%08X, ack_seq = 0x%08X," | 1563 | rem_seq = ntohl(tcph->seq); |
| 1356 | " rcv_nxt = 0x%08X Flags: %s %s.\n", | 1564 | rem_seq_ack = ntohl(tcph->ack_seq); |
| 1357 | datasize, inc_sequence, ntohl(tcph->ack_seq), | 1565 | datasize = skb->len; |
| 1358 | cm_node->tcp_cntxt.rcv_nxt, (tcph->syn ? "SYN":""), | 1566 | |
| 1359 | (tcph->ack ? "ACK":"")); | 1567 | switch (cm_node->state) { |
| 1360 | 1568 | case NES_CM_STATE_SYN_RCVD: | |
| 1361 | if (!tcph->syn && (inc_sequence != cm_node->tcp_cntxt.rcv_nxt) | 1569 | /* Passive OPEN */ |
| 1362 | ) { | 1570 | cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq); |
| 1363 | nes_debug(NES_DBG_CM, "dropping packet, datasize = %u, sequence = 0x%08X," | 1571 | cm_node->state = NES_CM_STATE_ESTABLISHED; |
| 1364 | " ack_seq = 0x%08X, rcv_nxt = 0x%08X Flags: %s.\n", | 1572 | if (datasize) { |
| 1365 | datasize, inc_sequence, ntohl(tcph->ack_seq), | 1573 | cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize; |
| 1366 | cm_node->tcp_cntxt.rcv_nxt, (tcph->ack ? "ACK":"")); | 1574 | cm_node->state = NES_CM_STATE_MPAREQ_RCVD; |
| 1367 | if (cm_node->state == NES_CM_STATE_LISTENING) { | 1575 | handle_rcv_mpa(cm_node, skb, NES_CM_EVENT_MPA_REQ); |
| 1368 | rem_ref_cm_node(cm_core, cm_node); | 1576 | } else { /* rcvd ACK only */ |
| 1577 | dev_kfree_skb_any(skb); | ||
| 1578 | cleanup_retrans_entry(cm_node); | ||
| 1579 | } | ||
| 1580 | break; | ||
| 1581 | case NES_CM_STATE_ESTABLISHED: | ||
| 1582 | /* Passive OPEN */ | ||
| 1583 | /* We expect mpa frame to be received only */ | ||
| 1584 | if (datasize) { | ||
| 1585 | cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize; | ||
| 1586 | cm_node->state = NES_CM_STATE_MPAREQ_RCVD; | ||
| 1587 | handle_rcv_mpa(cm_node, skb, | ||
| 1588 | NES_CM_EVENT_MPA_REQ); | ||
| 1589 | } else | ||
| 1590 | drop_packet(skb); | ||
| 1591 | break; | ||
| 1592 | case NES_CM_STATE_MPAREQ_SENT: | ||
| 1593 | cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq); | ||
| 1594 | if (datasize) { | ||
| 1595 | cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize; | ||
| 1596 | handle_rcv_mpa(cm_node, skb, NES_CM_EVENT_CONNECTED); | ||
| 1597 | } else { /* Could be just an ack pkt.. */ | ||
| 1598 | cleanup_retrans_entry(cm_node); | ||
| 1599 | dev_kfree_skb_any(skb); | ||
| 1369 | } | 1600 | } |
| 1370 | return -1; | 1601 | break; |
| 1602 | case NES_CM_STATE_FIN_WAIT1: | ||
| 1603 | case NES_CM_STATE_SYN_SENT: | ||
| 1604 | case NES_CM_STATE_FIN_WAIT2: | ||
| 1605 | case NES_CM_STATE_TSA: | ||
| 1606 | case NES_CM_STATE_CLOSED: | ||
| 1607 | case NES_CM_STATE_MPAREQ_RCVD: | ||
| 1608 | case NES_CM_STATE_LAST_ACK: | ||
| 1609 | case NES_CM_STATE_CLOSING: | ||
| 1610 | case NES_CM_STATE_UNKNOWN: | ||
| 1611 | default: | ||
| 1612 | drop_packet(skb); | ||
| 1613 | break; | ||
| 1371 | } | 1614 | } |
| 1615 | } | ||
| 1372 | 1616 | ||
| 1373 | cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize; | ||
| 1374 | 1617 | ||
| 1375 | 1618 | ||
| 1619 | static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph, | ||
| 1620 | struct sk_buff *skb, int optionsize, int passive) | ||
| 1621 | { | ||
| 1622 | u8 *optionsloc = (u8 *)&tcph[1]; | ||
| 1376 | if (optionsize) { | 1623 | if (optionsize) { |
| 1377 | u8 *optionsloc = (u8 *)&tcph[1]; | 1624 | if (process_options(cm_node, optionsloc, optionsize, |
| 1378 | if (process_options(cm_node, optionsloc, optionsize, (u32)tcph->syn)) { | 1625 | (u32)tcph->syn)) { |
| 1379 | nes_debug(NES_DBG_CM, "%s: Node %p, Sending RESET\n", __func__, cm_node); | 1626 | nes_debug(NES_DBG_CM, "%s: Node %p, Sending RESET\n", |
| 1380 | send_reset(cm_node); | 1627 | __func__, cm_node); |
| 1381 | if (cm_node->state != NES_CM_STATE_SYN_SENT) | 1628 | if (passive) |
| 1382 | rem_ref_cm_node(cm_core, cm_node); | 1629 | passive_open_err(cm_node, skb, 0); |
| 1383 | return 0; | 1630 | else |
| 1631 | active_open_err(cm_node, skb, 0); | ||
| 1632 | return 1; | ||
| 1384 | } | 1633 | } |
| 1385 | } else if (tcph->syn) | 1634 | } |
| 1386 | cm_node->tcp_cntxt.mss = NES_CM_DEFAULT_MSS; | ||
| 1387 | 1635 | ||
| 1388 | cm_node->tcp_cntxt.snd_wnd = ntohs(tcph->window) << | 1636 | cm_node->tcp_cntxt.snd_wnd = ntohs(tcph->window) << |
| 1389 | cm_node->tcp_cntxt.snd_wscale; | 1637 | cm_node->tcp_cntxt.snd_wscale; |
| 1390 | 1638 | ||
| 1391 | if (cm_node->tcp_cntxt.snd_wnd > cm_node->tcp_cntxt.max_snd_wnd) { | 1639 | if (cm_node->tcp_cntxt.snd_wnd > cm_node->tcp_cntxt.max_snd_wnd) |
| 1392 | cm_node->tcp_cntxt.max_snd_wnd = cm_node->tcp_cntxt.snd_wnd; | 1640 | cm_node->tcp_cntxt.max_snd_wnd = cm_node->tcp_cntxt.snd_wnd; |
| 1393 | } | 1641 | return 0; |
| 1642 | } | ||
| 1394 | 1643 | ||
| 1395 | if (tcph->ack) { | 1644 | /* |
| 1396 | cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq); | 1645 | * active_open_err() will send reset() if flag set.. |
| 1397 | switch (cm_node->state) { | 1646 | * It will also send ABORT event. |
| 1398 | case NES_CM_STATE_SYN_RCVD: | 1647 | */ |
| 1399 | case NES_CM_STATE_SYN_SENT: | ||
| 1400 | /* read and stash current sequence number */ | ||
| 1401 | if (cm_node->tcp_cntxt.rem_ack_num != cm_node->tcp_cntxt.loc_seq_num) { | ||
| 1402 | nes_debug(NES_DBG_CM, "ERROR - cm_node->tcp_cntxt.rem_ack_num !=" | ||
| 1403 | " cm_node->tcp_cntxt.loc_seq_num\n"); | ||
| 1404 | send_reset(cm_node); | ||
| 1405 | return 0; | ||
| 1406 | } | ||
| 1407 | if (cm_node->state == NES_CM_STATE_SYN_SENT) | ||
| 1408 | cm_node->state = NES_CM_STATE_ONE_SIDE_ESTABLISHED; | ||
| 1409 | else { | ||
| 1410 | cm_node->state = NES_CM_STATE_ESTABLISHED; | ||
| 1411 | } | ||
| 1412 | break; | ||
| 1413 | case NES_CM_STATE_LAST_ACK: | ||
| 1414 | cm_node->state = NES_CM_STATE_CLOSED; | ||
| 1415 | break; | ||
| 1416 | case NES_CM_STATE_FIN_WAIT1: | ||
| 1417 | cm_node->state = NES_CM_STATE_FIN_WAIT2; | ||
| 1418 | break; | ||
| 1419 | case NES_CM_STATE_CLOSING: | ||
| 1420 | cm_node->state = NES_CM_STATE_TIME_WAIT; | ||
| 1421 | /* need to schedule this to happen in 2MSL timeouts */ | ||
| 1422 | cm_node->state = NES_CM_STATE_CLOSED; | ||
| 1423 | break; | ||
| 1424 | case NES_CM_STATE_ONE_SIDE_ESTABLISHED: | ||
| 1425 | case NES_CM_STATE_ESTABLISHED: | ||
| 1426 | case NES_CM_STATE_MPAREQ_SENT: | ||
| 1427 | case NES_CM_STATE_CLOSE_WAIT: | ||
| 1428 | case NES_CM_STATE_TIME_WAIT: | ||
| 1429 | case NES_CM_STATE_CLOSED: | ||
| 1430 | break; | ||
| 1431 | case NES_CM_STATE_LISTENING: | ||
| 1432 | nes_debug(NES_DBG_CM, "Received an ACK on a listening port (SYN %d)\n", tcph->syn); | ||
| 1433 | cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq); | ||
| 1434 | send_reset(cm_node); | ||
| 1435 | /* send_reset bumps refcount, this should have been a new node */ | ||
| 1436 | rem_ref_cm_node(cm_core, cm_node); | ||
| 1437 | return -1; | ||
| 1438 | break; | ||
| 1439 | case NES_CM_STATE_TSA: | ||
| 1440 | nes_debug(NES_DBG_CM, "Received a packet with the ack bit set while in TSA state\n"); | ||
| 1441 | break; | ||
| 1442 | case NES_CM_STATE_UNKNOWN: | ||
| 1443 | case NES_CM_STATE_INITED: | ||
| 1444 | case NES_CM_STATE_ACCEPTING: | ||
| 1445 | case NES_CM_STATE_FIN_WAIT2: | ||
| 1446 | default: | ||
| 1447 | nes_debug(NES_DBG_CM, "Received ack from unknown state: %x\n", | ||
| 1448 | cm_node->state); | ||
| 1449 | send_reset(cm_node); | ||
| 1450 | break; | ||
| 1451 | } | ||
| 1452 | } | ||
| 1453 | 1648 | ||
| 1454 | if (tcph->syn) { | 1649 | static void active_open_err(struct nes_cm_node *cm_node, struct sk_buff *skb, |
| 1455 | if (cm_node->state == NES_CM_STATE_LISTENING) { | 1650 | int reset) |
| 1456 | /* do not exceed backlog */ | 1651 | { |
| 1457 | atomic_inc(&cm_node->listener->pend_accepts_cnt); | 1652 | cleanup_retrans_entry(cm_node); |
| 1458 | if (atomic_read(&cm_node->listener->pend_accepts_cnt) > | 1653 | if (reset) { |
| 1459 | cm_node->listener->backlog) { | 1654 | nes_debug(NES_DBG_CM, "ERROR active err called for cm_node=%p, " |
| 1460 | nes_debug(NES_DBG_CM, "drop syn due to backlog pressure \n"); | 1655 | "state=%d\n", cm_node, cm_node->state); |
| 1461 | cm_backlog_drops++; | 1656 | add_ref_cm_node(cm_node); |
| 1462 | atomic_dec(&cm_node->listener->pend_accepts_cnt); | 1657 | send_reset(cm_node, skb); |
| 1463 | rem_ref_cm_node(cm_core, cm_node); | 1658 | } else |
| 1464 | return 0; | 1659 | dev_kfree_skb_any(skb); |
| 1465 | } | ||
| 1466 | cm_node->accept_pend = 1; | ||
| 1467 | 1660 | ||
| 1468 | } | 1661 | cm_node->state = NES_CM_STATE_CLOSED; |
| 1469 | if (datasize == 0) | 1662 | create_event(cm_node, NES_CM_EVENT_ABORTED); |
| 1470 | cm_node->tcp_cntxt.rcv_nxt ++; | 1663 | } |
| 1471 | 1664 | ||
| 1472 | if (cm_node->state == NES_CM_STATE_LISTENING) { | 1665 | /* |
| 1473 | cm_node->state = NES_CM_STATE_SYN_RCVD; | 1666 | * passive_open_err() will either do a reset() or will free up the skb and |
| 1474 | send_syn(cm_node, 1); | 1667 | * remove the cm_node. |
| 1475 | } | 1668 | */ |
| 1476 | if (cm_node->state == NES_CM_STATE_ONE_SIDE_ESTABLISHED) { | ||
| 1477 | cm_node->state = NES_CM_STATE_ESTABLISHED; | ||
| 1478 | /* send final handshake ACK */ | ||
| 1479 | ret = send_ack(cm_node); | ||
| 1480 | if (ret < 0) | ||
| 1481 | return ret; | ||
| 1482 | 1669 | ||
| 1483 | cm_node->state = NES_CM_STATE_MPAREQ_SENT; | 1670 | static void passive_open_err(struct nes_cm_node *cm_node, struct sk_buff *skb, |
| 1484 | ret = send_mpa_request(cm_node); | 1671 | int reset) |
| 1485 | if (ret < 0) | 1672 | { |
| 1486 | return ret; | 1673 | cleanup_retrans_entry(cm_node); |
| 1487 | } | 1674 | cm_node->state = NES_CM_STATE_CLOSED; |
| 1675 | if (reset) { | ||
| 1676 | nes_debug(NES_DBG_CM, "passive_open_err sending RST for " | ||
| 1677 | "cm_node=%p state =%d\n", cm_node, cm_node->state); | ||
| 1678 | send_reset(cm_node, skb); | ||
| 1679 | } else { | ||
| 1680 | dev_kfree_skb_any(skb); | ||
| 1681 | rem_ref_cm_node(cm_node->cm_core, cm_node); | ||
| 1488 | } | 1682 | } |
| 1683 | } | ||
| 1489 | 1684 | ||
| 1490 | if (tcph->fin) { | 1685 | /* |
| 1491 | cm_node->tcp_cntxt.rcv_nxt++; | 1686 | * free_retrans_entry() routines assumes that the retrans_list_lock has |
| 1492 | switch (cm_node->state) { | 1687 | * been acquired before calling. |
| 1493 | case NES_CM_STATE_SYN_RCVD: | 1688 | */ |
| 1494 | case NES_CM_STATE_SYN_SENT: | 1689 | static void free_retrans_entry(struct nes_cm_node *cm_node) |
| 1495 | case NES_CM_STATE_ONE_SIDE_ESTABLISHED: | 1690 | { |
| 1496 | case NES_CM_STATE_ESTABLISHED: | 1691 | struct nes_timer_entry *send_entry; |
| 1497 | case NES_CM_STATE_ACCEPTING: | 1692 | send_entry = cm_node->send_entry; |
| 1498 | case NES_CM_STATE_MPAREQ_SENT: | 1693 | if (send_entry) { |
| 1499 | cm_node->state = NES_CM_STATE_CLOSE_WAIT; | 1694 | cm_node->send_entry = NULL; |
| 1500 | cm_node->state = NES_CM_STATE_LAST_ACK; | 1695 | dev_kfree_skb_any(send_entry->skb); |
| 1501 | ret = send_fin(cm_node, NULL); | 1696 | kfree(send_entry); |
| 1502 | break; | 1697 | rem_ref_cm_node(cm_node->cm_core, cm_node); |
| 1503 | case NES_CM_STATE_FIN_WAIT1: | ||
| 1504 | cm_node->state = NES_CM_STATE_CLOSING; | ||
| 1505 | ret = send_ack(cm_node); | ||
| 1506 | break; | ||
| 1507 | case NES_CM_STATE_FIN_WAIT2: | ||
| 1508 | cm_node->state = NES_CM_STATE_TIME_WAIT; | ||
| 1509 | cm_node->tcp_cntxt.loc_seq_num ++; | ||
| 1510 | ret = send_ack(cm_node); | ||
| 1511 | /* need to schedule this to happen in 2MSL timeouts */ | ||
| 1512 | cm_node->state = NES_CM_STATE_CLOSED; | ||
| 1513 | break; | ||
| 1514 | case NES_CM_STATE_CLOSE_WAIT: | ||
| 1515 | case NES_CM_STATE_LAST_ACK: | ||
| 1516 | case NES_CM_STATE_CLOSING: | ||
| 1517 | case NES_CM_STATE_TSA: | ||
| 1518 | default: | ||
| 1519 | nes_debug(NES_DBG_CM, "Received a fin while in %x state\n", | ||
| 1520 | cm_node->state); | ||
| 1521 | ret = -EINVAL; | ||
| 1522 | break; | ||
| 1523 | } | ||
| 1524 | } | 1698 | } |
| 1699 | } | ||
| 1525 | 1700 | ||
| 1526 | if (datasize) { | 1701 | static void cleanup_retrans_entry(struct nes_cm_node *cm_node) |
| 1527 | u8 *dataloc = skb->data; | 1702 | { |
| 1528 | /* figure out what state we are in and handle transition to next state */ | 1703 | unsigned long flags; |
| 1529 | switch (cm_node->state) { | ||
| 1530 | case NES_CM_STATE_LISTENING: | ||
| 1531 | case NES_CM_STATE_SYN_RCVD: | ||
| 1532 | case NES_CM_STATE_SYN_SENT: | ||
| 1533 | case NES_CM_STATE_FIN_WAIT1: | ||
| 1534 | case NES_CM_STATE_FIN_WAIT2: | ||
| 1535 | case NES_CM_STATE_CLOSE_WAIT: | ||
| 1536 | case NES_CM_STATE_LAST_ACK: | ||
| 1537 | case NES_CM_STATE_CLOSING: | ||
| 1538 | break; | ||
| 1539 | case NES_CM_STATE_MPAREQ_SENT: | ||
| 1540 | /* recv the mpa res frame, ret=frame len (incl priv data) */ | ||
| 1541 | ret = parse_mpa(cm_node, dataloc, datasize); | ||
| 1542 | if (ret < 0) | ||
| 1543 | break; | ||
| 1544 | /* set the req frame payload len in skb */ | ||
| 1545 | /* we are done handling this state, set node to a TSA state */ | ||
| 1546 | cm_node->state = NES_CM_STATE_TSA; | ||
| 1547 | send_ack(cm_node); | ||
| 1548 | create_event(cm_node, NES_CM_EVENT_CONNECTED); | ||
| 1549 | break; | ||
| 1550 | |||
| 1551 | case NES_CM_STATE_ESTABLISHED: | ||
| 1552 | /* we are expecting an MPA req frame */ | ||
| 1553 | ret = parse_mpa(cm_node, dataloc, datasize); | ||
| 1554 | if (ret < 0) { | ||
| 1555 | break; | ||
| 1556 | } | ||
| 1557 | cm_node->state = NES_CM_STATE_TSA; | ||
| 1558 | send_ack(cm_node); | ||
| 1559 | /* we got a valid MPA request, create an event */ | ||
| 1560 | create_event(cm_node, NES_CM_EVENT_MPA_REQ); | ||
| 1561 | break; | ||
| 1562 | case NES_CM_STATE_TSA: | ||
| 1563 | handle_exception_pkt(cm_node, skb); | ||
| 1564 | break; | ||
| 1565 | case NES_CM_STATE_UNKNOWN: | ||
| 1566 | case NES_CM_STATE_INITED: | ||
| 1567 | default: | ||
| 1568 | ret = -1; | ||
| 1569 | } | ||
| 1570 | } | ||
| 1571 | 1704 | ||
| 1572 | return ret; | 1705 | spin_lock_irqsave(&cm_node->retrans_list_lock, flags); |
| 1706 | free_retrans_entry(cm_node); | ||
| 1707 | spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); | ||
| 1573 | } | 1708 | } |
| 1574 | 1709 | ||
| 1710 | /** | ||
| 1711 | * process_packet | ||
| 1712 | * Returns skb if to be freed, else it will return NULL if already used.. | ||
| 1713 | */ | ||
| 1714 | static void process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb, | ||
| 1715 | struct nes_cm_core *cm_core) | ||
| 1716 | { | ||
| 1717 | enum nes_tcpip_pkt_type pkt_type = NES_PKT_TYPE_UNKNOWN; | ||
| 1718 | struct tcphdr *tcph = tcp_hdr(skb); | ||
| 1719 | skb_pull(skb, ip_hdr(skb)->ihl << 2); | ||
| 1720 | |||
| 1721 | nes_debug(NES_DBG_CM, "process_packet: cm_node=%p state =%d syn=%d " | ||
| 1722 | "ack=%d rst=%d fin=%d\n", cm_node, cm_node->state, tcph->syn, | ||
| 1723 | tcph->ack, tcph->rst, tcph->fin); | ||
| 1724 | |||
| 1725 | if (tcph->rst) | ||
| 1726 | pkt_type = NES_PKT_TYPE_RST; | ||
| 1727 | else if (tcph->syn) { | ||
| 1728 | pkt_type = NES_PKT_TYPE_SYN; | ||
| 1729 | if (tcph->ack) | ||
| 1730 | pkt_type = NES_PKT_TYPE_SYNACK; | ||
| 1731 | } else if (tcph->fin) | ||
| 1732 | pkt_type = NES_PKT_TYPE_FIN; | ||
| 1733 | else if (tcph->ack) | ||
| 1734 | pkt_type = NES_PKT_TYPE_ACK; | ||
| 1735 | |||
| 1736 | switch (pkt_type) { | ||
| 1737 | case NES_PKT_TYPE_SYN: | ||
| 1738 | handle_syn_pkt(cm_node, skb, tcph); | ||
| 1739 | break; | ||
| 1740 | case NES_PKT_TYPE_SYNACK: | ||
| 1741 | handle_synack_pkt(cm_node, skb, tcph); | ||
| 1742 | break; | ||
| 1743 | case NES_PKT_TYPE_ACK: | ||
| 1744 | handle_ack_pkt(cm_node, skb, tcph); | ||
| 1745 | break; | ||
| 1746 | case NES_PKT_TYPE_RST: | ||
| 1747 | handle_rst_pkt(cm_node, skb, tcph); | ||
| 1748 | break; | ||
| 1749 | case NES_PKT_TYPE_FIN: | ||
| 1750 | handle_fin_pkt(cm_node, skb, tcph); | ||
| 1751 | break; | ||
| 1752 | default: | ||
| 1753 | drop_packet(skb); | ||
| 1754 | break; | ||
| 1755 | } | ||
| 1756 | } | ||
| 1575 | 1757 | ||
| 1576 | /** | 1758 | /** |
| 1577 | * mini_cm_listen - create a listen node with params | 1759 | * mini_cm_listen - create a listen node with params |
| 1578 | */ | 1760 | */ |
| 1579 | static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core, | 1761 | static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core, |
| 1580 | struct nes_vnic *nesvnic, struct nes_cm_info *cm_info) | 1762 | struct nes_vnic *nesvnic, struct nes_cm_info *cm_info) |
| 1581 | { | 1763 | { |
| 1582 | struct nes_cm_listener *listener; | 1764 | struct nes_cm_listener *listener; |
| 1583 | unsigned long flags; | 1765 | unsigned long flags; |
| @@ -1644,37 +1826,36 @@ static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core, | |||
| 1644 | /** | 1826 | /** |
| 1645 | * mini_cm_connect - make a connection node with params | 1827 | * mini_cm_connect - make a connection node with params |
| 1646 | */ | 1828 | */ |
| 1647 | static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core, | 1829 | struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core, |
| 1648 | struct nes_vnic *nesvnic, | 1830 | struct nes_vnic *nesvnic, u16 private_data_len, |
| 1649 | struct ietf_mpa_frame *mpa_frame, | 1831 | void *private_data, struct nes_cm_info *cm_info) |
| 1650 | struct nes_cm_info *cm_info) | ||
| 1651 | { | 1832 | { |
| 1652 | int ret = 0; | 1833 | int ret = 0; |
| 1653 | struct nes_cm_node *cm_node; | 1834 | struct nes_cm_node *cm_node; |
| 1654 | struct nes_cm_listener *loopbackremotelistener; | 1835 | struct nes_cm_listener *loopbackremotelistener; |
| 1655 | struct nes_cm_node *loopbackremotenode; | 1836 | struct nes_cm_node *loopbackremotenode; |
| 1656 | struct nes_cm_info loopback_cm_info; | 1837 | struct nes_cm_info loopback_cm_info; |
| 1657 | 1838 | u16 mpa_frame_size = sizeof(struct ietf_mpa_frame) + private_data_len; | |
| 1658 | u16 mpa_frame_size = sizeof(struct ietf_mpa_frame) + | 1839 | struct ietf_mpa_frame *mpa_frame = NULL; |
| 1659 | ntohs(mpa_frame->priv_data_len); | ||
| 1660 | |||
| 1661 | cm_info->loc_addr = htonl(cm_info->loc_addr); | ||
| 1662 | cm_info->rem_addr = htonl(cm_info->rem_addr); | ||
| 1663 | cm_info->loc_port = htons(cm_info->loc_port); | ||
| 1664 | cm_info->rem_port = htons(cm_info->rem_port); | ||
| 1665 | 1840 | ||
| 1666 | /* create a CM connection node */ | 1841 | /* create a CM connection node */ |
| 1667 | cm_node = make_cm_node(cm_core, nesvnic, cm_info, NULL); | 1842 | cm_node = make_cm_node(cm_core, nesvnic, cm_info, NULL); |
| 1668 | if (!cm_node) | 1843 | if (!cm_node) |
| 1669 | return NULL; | 1844 | return NULL; |
| 1845 | mpa_frame = &cm_node->mpa_frame; | ||
| 1846 | strcpy(mpa_frame->key, IEFT_MPA_KEY_REQ); | ||
| 1847 | mpa_frame->flags = IETF_MPA_FLAGS_CRC; | ||
| 1848 | mpa_frame->rev = IETF_MPA_VERSION; | ||
| 1849 | mpa_frame->priv_data_len = htons(private_data_len); | ||
| 1670 | 1850 | ||
| 1671 | /* set our node side to client (active) side */ | 1851 | /* set our node side to client (active) side */ |
| 1672 | cm_node->tcp_cntxt.client = 1; | 1852 | cm_node->tcp_cntxt.client = 1; |
| 1673 | cm_node->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE; | 1853 | cm_node->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE; |
| 1674 | 1854 | ||
| 1675 | if (cm_info->loc_addr == cm_info->rem_addr) { | 1855 | if (cm_info->loc_addr == cm_info->rem_addr) { |
| 1676 | loopbackremotelistener = find_listener(cm_core, cm_node->rem_addr, | 1856 | loopbackremotelistener = find_listener(cm_core, |
| 1677 | cm_node->rem_port, NES_CM_LISTENER_ACTIVE_STATE); | 1857 | ntohl(nesvnic->local_ipaddr), cm_node->rem_port, |
| 1858 | NES_CM_LISTENER_ACTIVE_STATE); | ||
| 1678 | if (loopbackremotelistener == NULL) { | 1859 | if (loopbackremotelistener == NULL) { |
| 1679 | create_event(cm_node, NES_CM_EVENT_ABORTED); | 1860 | create_event(cm_node, NES_CM_EVENT_ABORTED); |
| 1680 | } else { | 1861 | } else { |
| @@ -1683,26 +1864,35 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core, | |||
| 1683 | loopback_cm_info.loc_port = cm_info->rem_port; | 1864 | loopback_cm_info.loc_port = cm_info->rem_port; |
| 1684 | loopback_cm_info.rem_port = cm_info->loc_port; | 1865 | loopback_cm_info.rem_port = cm_info->loc_port; |
| 1685 | loopback_cm_info.cm_id = loopbackremotelistener->cm_id; | 1866 | loopback_cm_info.cm_id = loopbackremotelistener->cm_id; |
| 1686 | loopbackremotenode = make_cm_node(cm_core, nesvnic, &loopback_cm_info, | 1867 | loopbackremotenode = make_cm_node(cm_core, nesvnic, |
| 1687 | loopbackremotelistener); | 1868 | &loopback_cm_info, loopbackremotelistener); |
| 1688 | loopbackremotenode->loopbackpartner = cm_node; | 1869 | loopbackremotenode->loopbackpartner = cm_node; |
| 1689 | loopbackremotenode->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE; | 1870 | loopbackremotenode->tcp_cntxt.rcv_wscale = |
| 1871 | NES_CM_DEFAULT_RCV_WND_SCALE; | ||
| 1690 | cm_node->loopbackpartner = loopbackremotenode; | 1872 | cm_node->loopbackpartner = loopbackremotenode; |
| 1691 | memcpy(loopbackremotenode->mpa_frame_buf, &mpa_frame->priv_data, | 1873 | memcpy(loopbackremotenode->mpa_frame_buf, private_data, |
| 1692 | mpa_frame_size); | 1874 | private_data_len); |
| 1693 | loopbackremotenode->mpa_frame_size = mpa_frame_size - | 1875 | loopbackremotenode->mpa_frame_size = private_data_len; |
| 1694 | sizeof(struct ietf_mpa_frame); | ||
| 1695 | 1876 | ||
| 1696 | /* we are done handling this state, set node to a TSA state */ | 1877 | /* we are done handling this state. */ |
| 1878 | /* set node to a TSA state */ | ||
| 1697 | cm_node->state = NES_CM_STATE_TSA; | 1879 | cm_node->state = NES_CM_STATE_TSA; |
| 1698 | cm_node->tcp_cntxt.rcv_nxt = loopbackremotenode->tcp_cntxt.loc_seq_num; | 1880 | cm_node->tcp_cntxt.rcv_nxt = |
| 1699 | loopbackremotenode->tcp_cntxt.rcv_nxt = cm_node->tcp_cntxt.loc_seq_num; | 1881 | loopbackremotenode->tcp_cntxt.loc_seq_num; |
| 1700 | cm_node->tcp_cntxt.max_snd_wnd = loopbackremotenode->tcp_cntxt.rcv_wnd; | 1882 | loopbackremotenode->tcp_cntxt.rcv_nxt = |
| 1701 | loopbackremotenode->tcp_cntxt.max_snd_wnd = cm_node->tcp_cntxt.rcv_wnd; | 1883 | cm_node->tcp_cntxt.loc_seq_num; |
| 1702 | cm_node->tcp_cntxt.snd_wnd = loopbackremotenode->tcp_cntxt.rcv_wnd; | 1884 | cm_node->tcp_cntxt.max_snd_wnd = |
| 1703 | loopbackremotenode->tcp_cntxt.snd_wnd = cm_node->tcp_cntxt.rcv_wnd; | 1885 | loopbackremotenode->tcp_cntxt.rcv_wnd; |
| 1704 | cm_node->tcp_cntxt.snd_wscale = loopbackremotenode->tcp_cntxt.rcv_wscale; | 1886 | loopbackremotenode->tcp_cntxt.max_snd_wnd = |
| 1705 | loopbackremotenode->tcp_cntxt.snd_wscale = cm_node->tcp_cntxt.rcv_wscale; | 1887 | cm_node->tcp_cntxt.rcv_wnd; |
| 1888 | cm_node->tcp_cntxt.snd_wnd = | ||
| 1889 | loopbackremotenode->tcp_cntxt.rcv_wnd; | ||
| 1890 | loopbackremotenode->tcp_cntxt.snd_wnd = | ||
| 1891 | cm_node->tcp_cntxt.rcv_wnd; | ||
| 1892 | cm_node->tcp_cntxt.snd_wscale = | ||
| 1893 | loopbackremotenode->tcp_cntxt.rcv_wscale; | ||
| 1894 | loopbackremotenode->tcp_cntxt.snd_wscale = | ||
| 1895 | cm_node->tcp_cntxt.rcv_wscale; | ||
| 1706 | 1896 | ||
| 1707 | create_event(loopbackremotenode, NES_CM_EVENT_MPA_REQ); | 1897 | create_event(loopbackremotenode, NES_CM_EVENT_MPA_REQ); |
| 1708 | } | 1898 | } |
| @@ -1712,16 +1902,29 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core, | |||
| 1712 | /* set our node side to client (active) side */ | 1902 | /* set our node side to client (active) side */ |
| 1713 | cm_node->tcp_cntxt.client = 1; | 1903 | cm_node->tcp_cntxt.client = 1; |
| 1714 | /* init our MPA frame ptr */ | 1904 | /* init our MPA frame ptr */ |
| 1715 | memcpy(&cm_node->mpa_frame, mpa_frame, mpa_frame_size); | 1905 | memcpy(mpa_frame->priv_data, private_data, private_data_len); |
| 1906 | |||
| 1716 | cm_node->mpa_frame_size = mpa_frame_size; | 1907 | cm_node->mpa_frame_size = mpa_frame_size; |
| 1717 | 1908 | ||
| 1718 | /* send a syn and goto syn sent state */ | 1909 | /* send a syn and goto syn sent state */ |
| 1719 | cm_node->state = NES_CM_STATE_SYN_SENT; | 1910 | cm_node->state = NES_CM_STATE_SYN_SENT; |
| 1720 | ret = send_syn(cm_node, 0); | 1911 | ret = send_syn(cm_node, 0, NULL); |
| 1912 | |||
| 1913 | if (ret) { | ||
| 1914 | /* error in sending the syn free up the cm_node struct */ | ||
| 1915 | nes_debug(NES_DBG_CM, "Api - connect() FAILED: dest " | ||
| 1916 | "addr=0x%08X, port=0x%04x, cm_node=%p, cm_id = %p.\n", | ||
| 1917 | cm_node->rem_addr, cm_node->rem_port, cm_node, | ||
| 1918 | cm_node->cm_id); | ||
| 1919 | rem_ref_cm_node(cm_node->cm_core, cm_node); | ||
| 1920 | cm_node = NULL; | ||
| 1921 | } | ||
| 1721 | 1922 | ||
| 1722 | nes_debug(NES_DBG_CM, "Api - connect(): dest addr=0x%08X, port=0x%04x," | 1923 | if (cm_node) |
| 1723 | " cm_node=%p, cm_id = %p.\n", | 1924 | nes_debug(NES_DBG_CM, "Api - connect(): dest addr=0x%08X," |
| 1724 | cm_node->rem_addr, cm_node->rem_port, cm_node, cm_node->cm_id); | 1925 | "port=0x%04x, cm_node=%p, cm_id = %p.\n", |
| 1926 | cm_node->rem_addr, cm_node->rem_port, cm_node, | ||
| 1927 | cm_node->cm_id); | ||
| 1725 | 1928 | ||
| 1726 | return cm_node; | 1929 | return cm_node; |
| 1727 | } | 1930 | } |
| @@ -1731,8 +1934,8 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core, | |||
| 1731 | * mini_cm_accept - accept a connection | 1934 | * mini_cm_accept - accept a connection |
| 1732 | * This function is never called | 1935 | * This function is never called |
| 1733 | */ | 1936 | */ |
| 1734 | static int mini_cm_accept(struct nes_cm_core *cm_core, struct ietf_mpa_frame *mpa_frame, | 1937 | static int mini_cm_accept(struct nes_cm_core *cm_core, |
| 1735 | struct nes_cm_node *cm_node) | 1938 | struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node) |
| 1736 | { | 1939 | { |
| 1737 | return 0; | 1940 | return 0; |
| 1738 | } | 1941 | } |
| @@ -1742,32 +1945,26 @@ static int mini_cm_accept(struct nes_cm_core *cm_core, struct ietf_mpa_frame *mp | |||
| 1742 | * mini_cm_reject - reject and teardown a connection | 1945 | * mini_cm_reject - reject and teardown a connection |
| 1743 | */ | 1946 | */ |
| 1744 | static int mini_cm_reject(struct nes_cm_core *cm_core, | 1947 | static int mini_cm_reject(struct nes_cm_core *cm_core, |
| 1745 | struct ietf_mpa_frame *mpa_frame, | 1948 | struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node) |
| 1746 | struct nes_cm_node *cm_node) | ||
| 1747 | { | 1949 | { |
| 1748 | int ret = 0; | 1950 | int ret = 0; |
| 1749 | struct sk_buff *skb; | ||
| 1750 | u16 mpa_frame_size = sizeof(struct ietf_mpa_frame) + | ||
| 1751 | ntohs(mpa_frame->priv_data_len); | ||
| 1752 | 1951 | ||
| 1753 | skb = get_free_pkt(cm_node); | 1952 | nes_debug(NES_DBG_CM, "%s cm_node=%p type=%d state=%d\n", |
| 1754 | if (!skb) { | 1953 | __func__, cm_node, cm_node->tcp_cntxt.client, cm_node->state); |
| 1755 | nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n"); | ||
| 1756 | return -1; | ||
| 1757 | } | ||
| 1758 | |||
| 1759 | /* send an MPA Request frame */ | ||
| 1760 | form_cm_frame(skb, cm_node, NULL, 0, mpa_frame, mpa_frame_size, SET_ACK | SET_FIN); | ||
| 1761 | ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0); | ||
| 1762 | 1954 | ||
| 1955 | if (cm_node->tcp_cntxt.client) | ||
| 1956 | return ret; | ||
| 1957 | cleanup_retrans_entry(cm_node); | ||
| 1763 | cm_node->state = NES_CM_STATE_CLOSED; | 1958 | cm_node->state = NES_CM_STATE_CLOSED; |
| 1764 | ret = send_fin(cm_node, NULL); | 1959 | ret = send_fin(cm_node, NULL); |
| 1765 | 1960 | ||
| 1766 | if (ret < 0) { | 1961 | if (cm_node->accept_pend) { |
| 1767 | printk(KERN_INFO PFX "failed to send MPA Reply (reject)\n"); | 1962 | BUG_ON(!cm_node->listener); |
| 1768 | return ret; | 1963 | atomic_dec(&cm_node->listener->pend_accepts_cnt); |
| 1964 | BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0); | ||
| 1769 | } | 1965 | } |
| 1770 | 1966 | ||
| 1967 | ret = send_reset(cm_node, NULL); | ||
| 1771 | return ret; | 1968 | return ret; |
| 1772 | } | 1969 | } |
| 1773 | 1970 | ||
| @@ -1783,35 +1980,39 @@ static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_nod | |||
| 1783 | return -EINVAL; | 1980 | return -EINVAL; |
| 1784 | 1981 | ||
| 1785 | switch (cm_node->state) { | 1982 | switch (cm_node->state) { |
| 1786 | /* if passed in node is null, create a reference key node for node search */ | 1983 | case NES_CM_STATE_SYN_RCVD: |
| 1787 | /* check if we found an owner node for this pkt */ | 1984 | case NES_CM_STATE_SYN_SENT: |
| 1788 | case NES_CM_STATE_SYN_RCVD: | 1985 | case NES_CM_STATE_ONE_SIDE_ESTABLISHED: |
| 1789 | case NES_CM_STATE_SYN_SENT: | 1986 | case NES_CM_STATE_ESTABLISHED: |
| 1790 | case NES_CM_STATE_ONE_SIDE_ESTABLISHED: | 1987 | case NES_CM_STATE_ACCEPTING: |
| 1791 | case NES_CM_STATE_ESTABLISHED: | 1988 | case NES_CM_STATE_MPAREQ_SENT: |
| 1792 | case NES_CM_STATE_ACCEPTING: | 1989 | case NES_CM_STATE_MPAREQ_RCVD: |
| 1793 | case NES_CM_STATE_MPAREQ_SENT: | 1990 | cleanup_retrans_entry(cm_node); |
| 1794 | cm_node->state = NES_CM_STATE_FIN_WAIT1; | 1991 | send_reset(cm_node, NULL); |
| 1795 | send_fin(cm_node, NULL); | 1992 | break; |
| 1796 | break; | 1993 | case NES_CM_STATE_CLOSE_WAIT: |
| 1797 | case NES_CM_STATE_CLOSE_WAIT: | 1994 | cm_node->state = NES_CM_STATE_LAST_ACK; |
| 1798 | cm_node->state = NES_CM_STATE_LAST_ACK; | 1995 | send_fin(cm_node, NULL); |
| 1799 | send_fin(cm_node, NULL); | 1996 | break; |
| 1800 | break; | 1997 | case NES_CM_STATE_FIN_WAIT1: |
| 1801 | case NES_CM_STATE_FIN_WAIT1: | 1998 | case NES_CM_STATE_FIN_WAIT2: |
| 1802 | case NES_CM_STATE_FIN_WAIT2: | 1999 | case NES_CM_STATE_LAST_ACK: |
| 1803 | case NES_CM_STATE_LAST_ACK: | 2000 | case NES_CM_STATE_TIME_WAIT: |
| 1804 | case NES_CM_STATE_TIME_WAIT: | 2001 | case NES_CM_STATE_CLOSING: |
| 1805 | case NES_CM_STATE_CLOSING: | 2002 | ret = -1; |
| 1806 | ret = -1; | 2003 | break; |
| 1807 | break; | 2004 | case NES_CM_STATE_LISTENING: |
| 1808 | case NES_CM_STATE_LISTENING: | 2005 | case NES_CM_STATE_UNKNOWN: |
| 1809 | case NES_CM_STATE_UNKNOWN: | 2006 | case NES_CM_STATE_INITED: |
| 1810 | case NES_CM_STATE_INITED: | 2007 | case NES_CM_STATE_CLOSED: |
| 1811 | case NES_CM_STATE_CLOSED: | 2008 | ret = rem_ref_cm_node(cm_core, cm_node); |
| 1812 | case NES_CM_STATE_TSA: | 2009 | break; |
| 1813 | ret = rem_ref_cm_node(cm_core, cm_node); | 2010 | case NES_CM_STATE_TSA: |
| 1814 | break; | 2011 | if (cm_node->send_entry) |
| 2012 | printk(KERN_ERR "ERROR Close got called from STATE_TSA " | ||
| 2013 | "send_entry=%p\n", cm_node->send_entry); | ||
| 2014 | ret = rem_ref_cm_node(cm_core, cm_node); | ||
| 2015 | break; | ||
| 1815 | } | 2016 | } |
| 1816 | cm_node->cm_id = NULL; | 2017 | cm_node->cm_id = NULL; |
| 1817 | return ret; | 2018 | return ret; |
| @@ -1822,25 +2023,30 @@ static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_nod | |||
| 1822 | * recv_pkt - recv an ETHERNET packet, and process it through CM | 2023 | * recv_pkt - recv an ETHERNET packet, and process it through CM |
| 1823 | * node state machine | 2024 | * node state machine |
| 1824 | */ | 2025 | */ |
| 1825 | static int mini_cm_recv_pkt(struct nes_cm_core *cm_core, struct nes_vnic *nesvnic, | 2026 | static void mini_cm_recv_pkt(struct nes_cm_core *cm_core, |
| 1826 | struct sk_buff *skb) | 2027 | struct nes_vnic *nesvnic, struct sk_buff *skb) |
| 1827 | { | 2028 | { |
| 1828 | struct nes_cm_node *cm_node = NULL; | 2029 | struct nes_cm_node *cm_node = NULL; |
| 1829 | struct nes_cm_listener *listener = NULL; | 2030 | struct nes_cm_listener *listener = NULL; |
| 1830 | struct iphdr *iph; | 2031 | struct iphdr *iph; |
| 1831 | struct tcphdr *tcph; | 2032 | struct tcphdr *tcph; |
| 1832 | struct nes_cm_info nfo; | 2033 | struct nes_cm_info nfo; |
| 1833 | int ret = 0; | ||
| 1834 | 2034 | ||
| 1835 | if (!skb || skb->len < sizeof(struct iphdr) + sizeof(struct tcphdr)) { | 2035 | if (!skb) |
| 1836 | ret = -EINVAL; | 2036 | return; |
| 1837 | goto out; | 2037 | if (skb->len < sizeof(struct iphdr) + sizeof(struct tcphdr)) { |
| 2038 | dev_kfree_skb_any(skb); | ||
| 2039 | return; | ||
| 1838 | } | 2040 | } |
| 1839 | 2041 | ||
| 1840 | iph = (struct iphdr *)skb->data; | 2042 | iph = (struct iphdr *)skb->data; |
| 1841 | tcph = (struct tcphdr *)(skb->data + sizeof(struct iphdr)); | 2043 | tcph = (struct tcphdr *)(skb->data + sizeof(struct iphdr)); |
| 1842 | skb_reset_network_header(skb); | 2044 | skb_reset_network_header(skb); |
| 1843 | skb_set_transport_header(skb, sizeof(*tcph)); | 2045 | skb_set_transport_header(skb, sizeof(*tcph)); |
| 2046 | if (!tcph) { | ||
| 2047 | dev_kfree_skb_any(skb); | ||
| 2048 | return; | ||
| 2049 | } | ||
| 1844 | skb->len = ntohs(iph->tot_len); | 2050 | skb->len = ntohs(iph->tot_len); |
| 1845 | 2051 | ||
| 1846 | nfo.loc_addr = ntohl(iph->daddr); | 2052 | nfo.loc_addr = ntohl(iph->daddr); |
| @@ -1853,61 +2059,60 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core, struct nes_vnic *nesvni | |||
| 1853 | NIPQUAD(iph->daddr), tcph->dest, | 2059 | NIPQUAD(iph->daddr), tcph->dest, |
| 1854 | NIPQUAD(iph->saddr), tcph->source); | 2060 | NIPQUAD(iph->saddr), tcph->source); |
| 1855 | 2061 | ||
| 1856 | /* note: this call is going to increment cm_node ref count */ | 2062 | do { |
| 1857 | cm_node = find_node(cm_core, | 2063 | cm_node = find_node(cm_core, |
| 1858 | nfo.rem_port, nfo.rem_addr, | 2064 | nfo.rem_port, nfo.rem_addr, |
| 1859 | nfo.loc_port, nfo.loc_addr); | 2065 | nfo.loc_port, nfo.loc_addr); |
| 1860 | 2066 | ||
| 1861 | if (!cm_node) { | ||
| 1862 | listener = find_listener(cm_core, nfo.loc_addr, nfo.loc_port, | ||
| 1863 | NES_CM_LISTENER_ACTIVE_STATE); | ||
| 1864 | if (listener) { | ||
| 1865 | nfo.cm_id = listener->cm_id; | ||
| 1866 | nfo.conn_type = listener->conn_type; | ||
| 1867 | } else { | ||
| 1868 | nfo.cm_id = NULL; | ||
| 1869 | nfo.conn_type = 0; | ||
| 1870 | } | ||
| 1871 | |||
| 1872 | cm_node = make_cm_node(cm_core, nesvnic, &nfo, listener); | ||
| 1873 | if (!cm_node) { | 2067 | if (!cm_node) { |
| 1874 | nes_debug(NES_DBG_CM, "Unable to allocate node\n"); | 2068 | /* Only type of packet accepted are for */ |
| 2069 | /* the PASSIVE open (syn only) */ | ||
| 2070 | if ((!tcph->syn) || (tcph->ack)) { | ||
| 2071 | cm_packets_dropped++; | ||
| 2072 | break; | ||
| 2073 | } | ||
| 2074 | listener = find_listener(cm_core, nfo.loc_addr, | ||
| 2075 | nfo.loc_port, | ||
| 2076 | NES_CM_LISTENER_ACTIVE_STATE); | ||
| 1875 | if (listener) { | 2077 | if (listener) { |
| 1876 | nes_debug(NES_DBG_CM, "unable to allocate node and decrementing listener refcount\n"); | 2078 | nfo.cm_id = listener->cm_id; |
| 2079 | nfo.conn_type = listener->conn_type; | ||
| 2080 | } else { | ||
| 2081 | nes_debug(NES_DBG_CM, "Unable to find listener " | ||
| 2082 | "for the pkt\n"); | ||
| 2083 | cm_packets_dropped++; | ||
| 2084 | dev_kfree_skb_any(skb); | ||
| 2085 | break; | ||
| 2086 | } | ||
| 2087 | |||
| 2088 | cm_node = make_cm_node(cm_core, nesvnic, &nfo, | ||
| 2089 | listener); | ||
| 2090 | if (!cm_node) { | ||
| 2091 | nes_debug(NES_DBG_CM, "Unable to allocate " | ||
| 2092 | "node\n"); | ||
| 2093 | cm_packets_dropped++; | ||
| 1877 | atomic_dec(&listener->ref_count); | 2094 | atomic_dec(&listener->ref_count); |
| 2095 | dev_kfree_skb_any(skb); | ||
| 2096 | break; | ||
| 1878 | } | 2097 | } |
| 1879 | ret = -1; | 2098 | if (!tcph->rst && !tcph->fin) { |
| 1880 | goto out; | 2099 | cm_node->state = NES_CM_STATE_LISTENING; |
| 1881 | } | 2100 | } else { |
| 1882 | if (!listener) { | 2101 | cm_packets_dropped++; |
| 1883 | nes_debug(NES_DBG_CM, "Packet found for unknown port %x refcnt=%d\n", | 2102 | rem_ref_cm_node(cm_core, cm_node); |
| 1884 | nfo.loc_port, atomic_read(&cm_node->ref_count)); | 2103 | dev_kfree_skb_any(skb); |
| 1885 | if (!tcph->rst) { | 2104 | break; |
| 1886 | nes_debug(NES_DBG_CM, "Packet found for unknown port=%d" | ||
| 1887 | " rem_port=%d refcnt=%d\n", | ||
| 1888 | nfo.loc_port, nfo.rem_port, atomic_read(&cm_node->ref_count)); | ||
| 1889 | |||
| 1890 | cm_node->tcp_cntxt.rcv_nxt = ntohl(tcph->seq); | ||
| 1891 | cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq); | ||
| 1892 | send_reset(cm_node); | ||
| 1893 | } | 2105 | } |
| 2106 | add_ref_cm_node(cm_node); | ||
| 2107 | } else if (cm_node->state == NES_CM_STATE_TSA) { | ||
| 1894 | rem_ref_cm_node(cm_core, cm_node); | 2108 | rem_ref_cm_node(cm_core, cm_node); |
| 1895 | ret = -1; | 2109 | atomic_inc(&cm_accel_dropped_pkts); |
| 1896 | goto out; | 2110 | dev_kfree_skb_any(skb); |
| 2111 | break; | ||
| 1897 | } | 2112 | } |
| 1898 | add_ref_cm_node(cm_node); | 2113 | process_packet(cm_node, skb, cm_core); |
| 1899 | cm_node->state = NES_CM_STATE_LISTENING; | 2114 | rem_ref_cm_node(cm_core, cm_node); |
| 1900 | } | 2115 | } while (0); |
| 1901 | |||
| 1902 | nes_debug(NES_DBG_CM, "Processing Packet for node %p, data = (%p):\n", | ||
| 1903 | cm_node, skb->data); | ||
| 1904 | process_packet(cm_node, skb, cm_core); | ||
| 1905 | |||
| 1906 | rem_ref_cm_node(cm_core, cm_node); | ||
| 1907 | out: | ||
| 1908 | if (skb) | ||
| 1909 | dev_kfree_skb_any(skb); | ||
| 1910 | return ret; | ||
| 1911 | } | 2116 | } |
| 1912 | 2117 | ||
| 1913 | 2118 | ||
| @@ -2107,15 +2312,12 @@ int nes_cm_disconn(struct nes_qp *nesqp) | |||
| 2107 | if (nesqp->disconn_pending == 0) { | 2312 | if (nesqp->disconn_pending == 0) { |
| 2108 | nesqp->disconn_pending++; | 2313 | nesqp->disconn_pending++; |
| 2109 | spin_unlock_irqrestore(&nesqp->lock, flags); | 2314 | spin_unlock_irqrestore(&nesqp->lock, flags); |
| 2110 | /* nes_add_ref(&nesqp->ibqp); */ | ||
| 2111 | /* init our disconnect work element, to */ | 2315 | /* init our disconnect work element, to */ |
| 2112 | INIT_WORK(&nesqp->disconn_work, nes_disconnect_worker); | 2316 | INIT_WORK(&nesqp->disconn_work, nes_disconnect_worker); |
| 2113 | 2317 | ||
| 2114 | queue_work(g_cm_core->disconn_wq, &nesqp->disconn_work); | 2318 | queue_work(g_cm_core->disconn_wq, &nesqp->disconn_work); |
| 2115 | } else { | 2319 | } else |
| 2116 | spin_unlock_irqrestore(&nesqp->lock, flags); | 2320 | spin_unlock_irqrestore(&nesqp->lock, flags); |
| 2117 | nes_rem_ref(&nesqp->ibqp); | ||
| 2118 | } | ||
| 2119 | 2321 | ||
| 2120 | return 0; | 2322 | return 0; |
| 2121 | } | 2323 | } |
| @@ -2161,7 +2363,6 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) | |||
| 2161 | nes_debug(NES_DBG_CM, "QP%u disconnect_worker cmid is NULL\n", | 2363 | nes_debug(NES_DBG_CM, "QP%u disconnect_worker cmid is NULL\n", |
| 2162 | nesqp->hwqp.qp_id); | 2364 | nesqp->hwqp.qp_id); |
| 2163 | spin_unlock_irqrestore(&nesqp->lock, flags); | 2365 | spin_unlock_irqrestore(&nesqp->lock, flags); |
| 2164 | nes_rem_ref(&nesqp->ibqp); | ||
| 2165 | return -1; | 2366 | return -1; |
| 2166 | } | 2367 | } |
| 2167 | 2368 | ||
| @@ -2182,30 +2383,31 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) | |||
| 2182 | atomic_inc(&cm_disconnects); | 2383 | atomic_inc(&cm_disconnects); |
| 2183 | cm_event.event = IW_CM_EVENT_DISCONNECT; | 2384 | cm_event.event = IW_CM_EVENT_DISCONNECT; |
| 2184 | if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) { | 2385 | if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) { |
| 2185 | issued_disconnect_reset = 1; | ||
| 2186 | cm_event.status = IW_CM_EVENT_STATUS_RESET; | 2386 | cm_event.status = IW_CM_EVENT_STATUS_RESET; |
| 2187 | nes_debug(NES_DBG_CM, "Generating a CM Disconnect Event (status reset) for " | 2387 | nes_debug(NES_DBG_CM, "Generating a CM " |
| 2188 | " QP%u, cm_id = %p. \n", | 2388 | "Disconnect Event (status reset) for " |
| 2189 | nesqp->hwqp.qp_id, cm_id); | 2389 | "QP%u, cm_id = %p. \n", |
| 2190 | } else { | 2390 | nesqp->hwqp.qp_id, cm_id); |
| 2391 | } else | ||
| 2191 | cm_event.status = IW_CM_EVENT_STATUS_OK; | 2392 | cm_event.status = IW_CM_EVENT_STATUS_OK; |
| 2192 | } | ||
| 2193 | 2393 | ||
| 2194 | cm_event.local_addr = cm_id->local_addr; | 2394 | cm_event.local_addr = cm_id->local_addr; |
| 2195 | cm_event.remote_addr = cm_id->remote_addr; | 2395 | cm_event.remote_addr = cm_id->remote_addr; |
| 2196 | cm_event.private_data = NULL; | 2396 | cm_event.private_data = NULL; |
| 2197 | cm_event.private_data_len = 0; | 2397 | cm_event.private_data_len = 0; |
| 2198 | 2398 | ||
| 2199 | nes_debug(NES_DBG_CM, "Generating a CM Disconnect Event for " | 2399 | nes_debug(NES_DBG_CM, "Generating a CM Disconnect Event" |
| 2200 | " QP%u, SQ Head = %u, SQ Tail = %u. cm_id = %p, refcount = %u.\n", | 2400 | " for QP%u, SQ Head = %u, SQ Tail = %u. " |
| 2201 | nesqp->hwqp.qp_id, | 2401 | "cm_id = %p, refcount = %u.\n", |
| 2202 | nesqp->hwqp.sq_head, nesqp->hwqp.sq_tail, cm_id, | 2402 | nesqp->hwqp.qp_id, nesqp->hwqp.sq_head, |
| 2203 | atomic_read(&nesqp->refcount)); | 2403 | nesqp->hwqp.sq_tail, cm_id, |
| 2404 | atomic_read(&nesqp->refcount)); | ||
| 2204 | 2405 | ||
| 2205 | spin_unlock_irqrestore(&nesqp->lock, flags); | 2406 | spin_unlock_irqrestore(&nesqp->lock, flags); |
| 2206 | ret = cm_id->event_handler(cm_id, &cm_event); | 2407 | ret = cm_id->event_handler(cm_id, &cm_event); |
| 2207 | if (ret) | 2408 | if (ret) |
| 2208 | nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret); | 2409 | nes_debug(NES_DBG_CM, "OFA CM event_handler " |
| 2410 | "returned, ret=%d\n", ret); | ||
| 2209 | spin_lock_irqsave(&nesqp->lock, flags); | 2411 | spin_lock_irqsave(&nesqp->lock, flags); |
| 2210 | } | 2412 | } |
| 2211 | 2413 | ||
| @@ -2247,31 +2449,24 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) | |||
| 2247 | if (nesqp->flush_issued == 0) { | 2449 | if (nesqp->flush_issued == 0) { |
| 2248 | nesqp->flush_issued = 1; | 2450 | nesqp->flush_issued = 1; |
| 2249 | spin_unlock_irqrestore(&nesqp->lock, flags); | 2451 | spin_unlock_irqrestore(&nesqp->lock, flags); |
| 2250 | flush_wqes(nesvnic->nesdev, nesqp, NES_CQP_FLUSH_RQ, 1); | 2452 | flush_wqes(nesvnic->nesdev, nesqp, |
| 2251 | } else { | 2453 | NES_CQP_FLUSH_RQ, 1); |
| 2454 | } else | ||
| 2252 | spin_unlock_irqrestore(&nesqp->lock, flags); | 2455 | spin_unlock_irqrestore(&nesqp->lock, flags); |
| 2253 | } | ||
| 2254 | |||
| 2255 | /* This reference is from either ModifyQP or the AE processing, | ||
| 2256 | there is still a race here with modifyqp */ | ||
| 2257 | nes_rem_ref(&nesqp->ibqp); | ||
| 2258 | |||
| 2259 | } else { | 2456 | } else { |
| 2260 | cm_id = nesqp->cm_id; | 2457 | cm_id = nesqp->cm_id; |
| 2261 | spin_unlock_irqrestore(&nesqp->lock, flags); | 2458 | spin_unlock_irqrestore(&nesqp->lock, flags); |
| 2262 | /* check to see if the inbound reset beat the outbound reset */ | 2459 | /* check to see if the inbound reset beat the outbound reset */ |
| 2263 | if ((!cm_id) && (last_ae==NES_AEQE_AEID_RESET_SENT)) { | 2460 | if ((!cm_id) && (last_ae==NES_AEQE_AEID_RESET_SENT)) { |
| 2264 | nes_debug(NES_DBG_CM, "QP%u: Decing refcount due to inbound reset" | 2461 | nes_debug(NES_DBG_CM, "QP%u: Decing refcount " |
| 2265 | " beating the outbound reset.\n", | 2462 | "due to inbound reset beating the " |
| 2266 | nesqp->hwqp.qp_id); | 2463 | "outbound reset.\n", nesqp->hwqp.qp_id); |
| 2267 | nes_rem_ref(&nesqp->ibqp); | ||
| 2268 | } | 2464 | } |
| 2269 | } | 2465 | } |
| 2270 | } else { | 2466 | } else { |
| 2271 | nesqp->disconn_pending = 0; | 2467 | nesqp->disconn_pending = 0; |
| 2272 | spin_unlock_irqrestore(&nesqp->lock, flags); | 2468 | spin_unlock_irqrestore(&nesqp->lock, flags); |
| 2273 | } | 2469 | } |
| 2274 | nes_rem_ref(&nesqp->ibqp); | ||
| 2275 | 2470 | ||
| 2276 | return 0; | 2471 | return 0; |
| 2277 | } | 2472 | } |
| @@ -2349,71 +2544,82 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) | |||
| 2349 | nesdev = nesvnic->nesdev; | 2544 | nesdev = nesvnic->nesdev; |
| 2350 | adapter = nesdev->nesadapter; | 2545 | adapter = nesdev->nesadapter; |
| 2351 | 2546 | ||
| 2352 | nes_debug(NES_DBG_CM, "nesvnic=%p, netdev=%p, %s\n", | ||
| 2353 | nesvnic, nesvnic->netdev, nesvnic->netdev->name); | ||
| 2354 | |||
| 2355 | /* since this is from a listen, we were able to put node handle into cm_id */ | ||
| 2356 | cm_node = (struct nes_cm_node *)cm_id->provider_data; | 2547 | cm_node = (struct nes_cm_node *)cm_id->provider_data; |
| 2548 | nes_debug(NES_DBG_CM, "nes_accept: cm_node= %p nesvnic=%p, netdev=%p," | ||
| 2549 | "%s\n", cm_node, nesvnic, nesvnic->netdev, | ||
| 2550 | nesvnic->netdev->name); | ||
| 2357 | 2551 | ||
| 2358 | /* associate the node with the QP */ | 2552 | /* associate the node with the QP */ |
| 2359 | nesqp->cm_node = (void *)cm_node; | 2553 | nesqp->cm_node = (void *)cm_node; |
| 2554 | cm_node->nesqp = nesqp; | ||
| 2555 | nes_add_ref(&nesqp->ibqp); | ||
| 2360 | 2556 | ||
| 2361 | nes_debug(NES_DBG_CM, "QP%u, cm_node=%p, jiffies = %lu\n", | 2557 | nes_debug(NES_DBG_CM, "QP%u, cm_node=%p, jiffies = %lu listener = %p\n", |
| 2362 | nesqp->hwqp.qp_id, cm_node, jiffies); | 2558 | nesqp->hwqp.qp_id, cm_node, jiffies, cm_node->listener); |
| 2363 | atomic_inc(&cm_accepts); | 2559 | atomic_inc(&cm_accepts); |
| 2364 | 2560 | ||
| 2365 | nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n", | 2561 | nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n", |
| 2366 | atomic_read(&nesvnic->netdev->refcnt)); | 2562 | atomic_read(&nesvnic->netdev->refcnt)); |
| 2367 | 2563 | ||
| 2368 | /* allocate the ietf frame and space for private data */ | 2564 | /* allocate the ietf frame and space for private data */ |
| 2369 | nesqp->ietf_frame = pci_alloc_consistent(nesdev->pcidev, | 2565 | nesqp->ietf_frame = pci_alloc_consistent(nesdev->pcidev, |
| 2370 | sizeof(struct ietf_mpa_frame) + conn_param->private_data_len, | 2566 | sizeof(struct ietf_mpa_frame) + conn_param->private_data_len, |
| 2371 | &nesqp->ietf_frame_pbase); | 2567 | &nesqp->ietf_frame_pbase); |
| 2372 | |||
| 2373 | if (!nesqp->ietf_frame) { | ||
| 2374 | nes_debug(NES_DBG_CM, "Unable to allocate memory for private data\n"); | ||
| 2375 | return -ENOMEM; | ||
| 2376 | } | ||
| 2377 | 2568 | ||
| 2569 | if (!nesqp->ietf_frame) { | ||
| 2570 | nes_debug(NES_DBG_CM, "Unable to allocate memory for private " | ||
| 2571 | "data\n"); | ||
| 2572 | return -ENOMEM; | ||
| 2573 | } | ||
| 2378 | 2574 | ||
| 2379 | /* setup the MPA frame */ | ||
| 2380 | nesqp->private_data_len = conn_param->private_data_len; | ||
| 2381 | memcpy(nesqp->ietf_frame->key, IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE); | ||
| 2382 | 2575 | ||
| 2383 | memcpy(nesqp->ietf_frame->priv_data, conn_param->private_data, | 2576 | /* setup the MPA frame */ |
| 2384 | conn_param->private_data_len); | 2577 | nesqp->private_data_len = conn_param->private_data_len; |
| 2578 | memcpy(nesqp->ietf_frame->key, IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE); | ||
| 2385 | 2579 | ||
| 2386 | nesqp->ietf_frame->priv_data_len = cpu_to_be16(conn_param->private_data_len); | 2580 | memcpy(nesqp->ietf_frame->priv_data, conn_param->private_data, |
| 2387 | nesqp->ietf_frame->rev = mpa_version; | 2581 | conn_param->private_data_len); |
| 2388 | nesqp->ietf_frame->flags = IETF_MPA_FLAGS_CRC; | ||
| 2389 | 2582 | ||
| 2390 | /* setup our first outgoing iWarp send WQE (the IETF frame response) */ | 2583 | nesqp->ietf_frame->priv_data_len = |
| 2391 | wqe = &nesqp->hwqp.sq_vbase[0]; | 2584 | cpu_to_be16(conn_param->private_data_len); |
| 2585 | nesqp->ietf_frame->rev = mpa_version; | ||
| 2586 | nesqp->ietf_frame->flags = IETF_MPA_FLAGS_CRC; | ||
| 2392 | 2587 | ||
| 2393 | if (cm_id->remote_addr.sin_addr.s_addr != cm_id->local_addr.sin_addr.s_addr) { | 2588 | /* setup our first outgoing iWarp send WQE (the IETF frame response) */ |
| 2394 | u64temp = (unsigned long)nesqp; | 2589 | wqe = &nesqp->hwqp.sq_vbase[0]; |
| 2395 | u64temp |= NES_SW_CONTEXT_ALIGN>>1; | 2590 | |
| 2396 | set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX, | 2591 | if (cm_id->remote_addr.sin_addr.s_addr != |
| 2397 | u64temp); | 2592 | cm_id->local_addr.sin_addr.s_addr) { |
| 2398 | wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] = | 2593 | u64temp = (unsigned long)nesqp; |
| 2399 | cpu_to_le32(NES_IWARP_SQ_WQE_STREAMING | NES_IWARP_SQ_WQE_WRPDU); | 2594 | u64temp |= NES_SW_CONTEXT_ALIGN>>1; |
| 2400 | wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] = | 2595 | set_wqe_64bit_value(wqe->wqe_words, |
| 2401 | cpu_to_le32(conn_param->private_data_len + sizeof(struct ietf_mpa_frame)); | 2596 | NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX, |
| 2402 | wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] = | 2597 | u64temp); |
| 2403 | cpu_to_le32((u32)nesqp->ietf_frame_pbase); | 2598 | wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] = |
| 2404 | wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] = | 2599 | cpu_to_le32(NES_IWARP_SQ_WQE_STREAMING | |
| 2405 | cpu_to_le32((u32)((u64)nesqp->ietf_frame_pbase >> 32)); | 2600 | NES_IWARP_SQ_WQE_WRPDU); |
| 2406 | wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] = | 2601 | wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] = |
| 2407 | cpu_to_le32(conn_param->private_data_len + sizeof(struct ietf_mpa_frame)); | 2602 | cpu_to_le32(conn_param->private_data_len + |
| 2408 | wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0; | 2603 | sizeof(struct ietf_mpa_frame)); |
| 2409 | 2604 | wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] = | |
| 2410 | nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32( | 2605 | cpu_to_le32((u32)nesqp->ietf_frame_pbase); |
| 2411 | NES_QPCONTEXT_ORDIRD_LSMM_PRESENT | NES_QPCONTEXT_ORDIRD_WRPDU); | 2606 | wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] = |
| 2412 | } else { | 2607 | cpu_to_le32((u32)((u64)nesqp->ietf_frame_pbase >> 32)); |
| 2413 | nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((NES_QPCONTEXT_ORDIRD_LSMM_PRESENT | | 2608 | wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] = |
| 2414 | NES_QPCONTEXT_ORDIRD_WRPDU | NES_QPCONTEXT_ORDIRD_ALSMM)); | 2609 | cpu_to_le32(conn_param->private_data_len + |
| 2415 | } | 2610 | sizeof(struct ietf_mpa_frame)); |
| 2416 | nesqp->skip_lsmm = 1; | 2611 | wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0; |
| 2612 | |||
| 2613 | nesqp->nesqp_context->ird_ord_sizes |= | ||
| 2614 | cpu_to_le32(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT | | ||
| 2615 | NES_QPCONTEXT_ORDIRD_WRPDU); | ||
| 2616 | } else { | ||
| 2617 | nesqp->nesqp_context->ird_ord_sizes |= | ||
| 2618 | cpu_to_le32((NES_QPCONTEXT_ORDIRD_LSMM_PRESENT | | ||
| 2619 | NES_QPCONTEXT_ORDIRD_WRPDU | | ||
| 2620 | NES_QPCONTEXT_ORDIRD_ALSMM)); | ||
| 2621 | } | ||
| 2622 | nesqp->skip_lsmm = 1; | ||
| 2417 | 2623 | ||
| 2418 | 2624 | ||
| 2419 | /* Cache the cm_id in the qp */ | 2625 | /* Cache the cm_id in the qp */ |
| @@ -2424,55 +2630,75 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) | |||
| 2424 | cm_id->provider_data = nesqp; | 2630 | cm_id->provider_data = nesqp; |
| 2425 | nesqp->active_conn = 0; | 2631 | nesqp->active_conn = 0; |
| 2426 | 2632 | ||
| 2633 | if (cm_node->state == NES_CM_STATE_TSA) | ||
| 2634 | nes_debug(NES_DBG_CM, "Already state = TSA for cm_node=%p\n", | ||
| 2635 | cm_node); | ||
| 2636 | |||
| 2427 | nes_cm_init_tsa_conn(nesqp, cm_node); | 2637 | nes_cm_init_tsa_conn(nesqp, cm_node); |
| 2428 | 2638 | ||
| 2429 | nesqp->nesqp_context->tcpPorts[0] = cpu_to_le16(ntohs(cm_id->local_addr.sin_port)); | 2639 | nesqp->nesqp_context->tcpPorts[0] = |
| 2430 | nesqp->nesqp_context->tcpPorts[1] = cpu_to_le16(ntohs(cm_id->remote_addr.sin_port)); | 2640 | cpu_to_le16(ntohs(cm_id->local_addr.sin_port)); |
| 2431 | nesqp->nesqp_context->ip0 = cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr)); | 2641 | nesqp->nesqp_context->tcpPorts[1] = |
| 2642 | cpu_to_le16(ntohs(cm_id->remote_addr.sin_port)); | ||
| 2643 | |||
| 2644 | if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr)) | ||
| 2645 | nesqp->nesqp_context->ip0 = | ||
| 2646 | cpu_to_le32(ntohl(nesvnic->local_ipaddr)); | ||
| 2647 | else | ||
| 2648 | nesqp->nesqp_context->ip0 = | ||
| 2649 | cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr)); | ||
| 2432 | 2650 | ||
| 2433 | nesqp->nesqp_context->misc2 |= cpu_to_le32( | 2651 | nesqp->nesqp_context->misc2 |= cpu_to_le32( |
| 2434 | (u32)PCI_FUNC(nesdev->pcidev->devfn) << NES_QPCONTEXT_MISC2_SRC_IP_SHIFT); | 2652 | (u32)PCI_FUNC(nesdev->pcidev->devfn) << |
| 2653 | NES_QPCONTEXT_MISC2_SRC_IP_SHIFT); | ||
| 2435 | 2654 | ||
| 2436 | nesqp->nesqp_context->arp_index_vlan |= cpu_to_le32( | 2655 | nesqp->nesqp_context->arp_index_vlan |= |
| 2437 | nes_arp_table(nesdev, le32_to_cpu(nesqp->nesqp_context->ip0), NULL, | 2656 | cpu_to_le32(nes_arp_table(nesdev, |
| 2657 | le32_to_cpu(nesqp->nesqp_context->ip0), NULL, | ||
| 2438 | NES_ARP_RESOLVE) << 16); | 2658 | NES_ARP_RESOLVE) << 16); |
| 2439 | 2659 | ||
| 2440 | nesqp->nesqp_context->ts_val_delta = cpu_to_le32( | 2660 | nesqp->nesqp_context->ts_val_delta = cpu_to_le32( |
| 2441 | jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW)); | 2661 | jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW)); |
| 2442 | 2662 | ||
| 2443 | nesqp->nesqp_context->ird_index = cpu_to_le32(nesqp->hwqp.qp_id); | 2663 | nesqp->nesqp_context->ird_index = cpu_to_le32(nesqp->hwqp.qp_id); |
| 2444 | 2664 | ||
| 2445 | nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32( | 2665 | nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32( |
| 2446 | ((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT)); | 2666 | ((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT)); |
| 2447 | nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((u32)conn_param->ord); | 2667 | nesqp->nesqp_context->ird_ord_sizes |= |
| 2668 | cpu_to_le32((u32)conn_param->ord); | ||
| 2448 | 2669 | ||
| 2449 | memset(&nes_quad, 0, sizeof(nes_quad)); | 2670 | memset(&nes_quad, 0, sizeof(nes_quad)); |
| 2450 | nes_quad.DstIpAdrIndex = cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24); | 2671 | nes_quad.DstIpAdrIndex = |
| 2451 | nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr; | 2672 | cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24); |
| 2452 | nes_quad.TcpPorts[0] = cm_id->remote_addr.sin_port; | 2673 | if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr)) |
| 2453 | nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port; | 2674 | nes_quad.SrcIpadr = nesvnic->local_ipaddr; |
| 2675 | else | ||
| 2676 | nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr; | ||
| 2677 | nes_quad.TcpPorts[0] = cm_id->remote_addr.sin_port; | ||
| 2678 | nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port; | ||
| 2454 | 2679 | ||
| 2455 | /* Produce hash key */ | 2680 | /* Produce hash key */ |
| 2456 | crc_value = get_crc_value(&nes_quad); | 2681 | crc_value = get_crc_value(&nes_quad); |
| 2457 | nesqp->hte_index = cpu_to_be32(crc_value ^ 0xffffffff); | 2682 | nesqp->hte_index = cpu_to_be32(crc_value ^ 0xffffffff); |
| 2458 | nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, CRC = 0x%08X\n", | 2683 | nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, CRC = 0x%08X\n", |
| 2459 | nesqp->hte_index, nesqp->hte_index & adapter->hte_index_mask); | 2684 | nesqp->hte_index, nesqp->hte_index & adapter->hte_index_mask); |
| 2460 | 2685 | ||
| 2461 | nesqp->hte_index &= adapter->hte_index_mask; | 2686 | nesqp->hte_index &= adapter->hte_index_mask; |
| 2462 | nesqp->nesqp_context->hte_index = cpu_to_le32(nesqp->hte_index); | 2687 | nesqp->nesqp_context->hte_index = cpu_to_le32(nesqp->hte_index); |
| 2463 | 2688 | ||
| 2464 | cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node); | 2689 | cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node); |
| 2465 | 2690 | ||
| 2466 | nes_debug(NES_DBG_CM, "QP%u, Destination IP = 0x%08X:0x%04X, local = 0x%08X:0x%04X," | 2691 | nes_debug(NES_DBG_CM, "QP%u, Destination IP = 0x%08X:0x%04X, local = " |
| 2467 | " rcv_nxt=0x%08X, snd_nxt=0x%08X, mpa + private data length=%zu.\n", | 2692 | "0x%08X:0x%04X, rcv_nxt=0x%08X, snd_nxt=0x%08X, mpa + " |
| 2468 | nesqp->hwqp.qp_id, | 2693 | "private data length=%zu.\n", nesqp->hwqp.qp_id, |
| 2469 | ntohl(cm_id->remote_addr.sin_addr.s_addr), | 2694 | ntohl(cm_id->remote_addr.sin_addr.s_addr), |
| 2470 | ntohs(cm_id->remote_addr.sin_port), | 2695 | ntohs(cm_id->remote_addr.sin_port), |
| 2471 | ntohl(cm_id->local_addr.sin_addr.s_addr), | 2696 | ntohl(cm_id->local_addr.sin_addr.s_addr), |
| 2472 | ntohs(cm_id->local_addr.sin_port), | 2697 | ntohs(cm_id->local_addr.sin_port), |
| 2473 | le32_to_cpu(nesqp->nesqp_context->rcv_nxt), | 2698 | le32_to_cpu(nesqp->nesqp_context->rcv_nxt), |
| 2474 | le32_to_cpu(nesqp->nesqp_context->snd_nxt), | 2699 | le32_to_cpu(nesqp->nesqp_context->snd_nxt), |
| 2475 | conn_param->private_data_len+sizeof(struct ietf_mpa_frame)); | 2700 | conn_param->private_data_len + |
| 2701 | sizeof(struct ietf_mpa_frame)); | ||
| 2476 | 2702 | ||
| 2477 | attr.qp_state = IB_QPS_RTS; | 2703 | attr.qp_state = IB_QPS_RTS; |
| 2478 | nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL); | 2704 | nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL); |
| @@ -2489,15 +2715,16 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) | |||
| 2489 | cm_event.private_data_len = 0; | 2715 | cm_event.private_data_len = 0; |
| 2490 | ret = cm_id->event_handler(cm_id, &cm_event); | 2716 | ret = cm_id->event_handler(cm_id, &cm_event); |
| 2491 | if (cm_node->loopbackpartner) { | 2717 | if (cm_node->loopbackpartner) { |
| 2492 | cm_node->loopbackpartner->mpa_frame_size = nesqp->private_data_len; | 2718 | cm_node->loopbackpartner->mpa_frame_size = |
| 2719 | nesqp->private_data_len; | ||
| 2493 | /* copy entire MPA frame to our cm_node's frame */ | 2720 | /* copy entire MPA frame to our cm_node's frame */ |
| 2494 | memcpy(cm_node->loopbackpartner->mpa_frame_buf, nesqp->ietf_frame->priv_data, | 2721 | memcpy(cm_node->loopbackpartner->mpa_frame_buf, |
| 2495 | nesqp->private_data_len); | 2722 | nesqp->ietf_frame->priv_data, nesqp->private_data_len); |
| 2496 | create_event(cm_node->loopbackpartner, NES_CM_EVENT_CONNECTED); | 2723 | create_event(cm_node->loopbackpartner, NES_CM_EVENT_CONNECTED); |
| 2497 | } | 2724 | } |
| 2498 | if (ret) | 2725 | if (ret) |
| 2499 | printk("%s[%u] OFA CM event_handler returned, ret=%d\n", | 2726 | printk(KERN_ERR "%s[%u] OFA CM event_handler returned, " |
| 2500 | __func__, __LINE__, ret); | 2727 | "ret=%d\n", __func__, __LINE__, ret); |
| 2501 | 2728 | ||
| 2502 | return 0; | 2729 | return 0; |
| 2503 | } | 2730 | } |
| @@ -2555,74 +2782,61 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) | |||
| 2555 | if (!nesdev) | 2782 | if (!nesdev) |
| 2556 | return -EINVAL; | 2783 | return -EINVAL; |
| 2557 | 2784 | ||
| 2558 | atomic_inc(&cm_connects); | 2785 | nes_debug(NES_DBG_CM, "QP%u, current IP = 0x%08X, Destination IP = " |
| 2559 | 2786 | "0x%08X:0x%04X, local = 0x%08X:0x%04X.\n", nesqp->hwqp.qp_id, | |
| 2560 | nesqp->ietf_frame = kzalloc(sizeof(struct ietf_mpa_frame) + | 2787 | ntohl(nesvnic->local_ipaddr), |
| 2561 | conn_param->private_data_len, GFP_KERNEL); | 2788 | ntohl(cm_id->remote_addr.sin_addr.s_addr), |
| 2562 | if (!nesqp->ietf_frame) | 2789 | ntohs(cm_id->remote_addr.sin_port), |
| 2563 | return -ENOMEM; | 2790 | ntohl(cm_id->local_addr.sin_addr.s_addr), |
| 2791 | ntohs(cm_id->local_addr.sin_port)); | ||
| 2564 | 2792 | ||
| 2565 | /* set qp as having an active connection */ | 2793 | atomic_inc(&cm_connects); |
| 2566 | nesqp->active_conn = 1; | 2794 | nesqp->active_conn = 1; |
| 2567 | 2795 | ||
| 2568 | nes_debug(NES_DBG_CM, "QP%u, Destination IP = 0x%08X:0x%04X, local = 0x%08X:0x%04X.\n", | ||
| 2569 | nesqp->hwqp.qp_id, | ||
| 2570 | ntohl(cm_id->remote_addr.sin_addr.s_addr), | ||
| 2571 | ntohs(cm_id->remote_addr.sin_port), | ||
| 2572 | ntohl(cm_id->local_addr.sin_addr.s_addr), | ||
| 2573 | ntohs(cm_id->local_addr.sin_port)); | ||
| 2574 | |||
| 2575 | /* cache the cm_id in the qp */ | 2796 | /* cache the cm_id in the qp */ |
| 2576 | nesqp->cm_id = cm_id; | 2797 | nesqp->cm_id = cm_id; |
| 2577 | 2798 | ||
| 2578 | cm_id->provider_data = nesqp; | 2799 | cm_id->provider_data = nesqp; |
| 2579 | 2800 | ||
| 2580 | /* copy the private data */ | ||
| 2581 | if (conn_param->private_data_len) { | ||
| 2582 | memcpy(nesqp->ietf_frame->priv_data, conn_param->private_data, | ||
| 2583 | conn_param->private_data_len); | ||
| 2584 | } | ||
| 2585 | |||
| 2586 | nesqp->private_data_len = conn_param->private_data_len; | 2801 | nesqp->private_data_len = conn_param->private_data_len; |
| 2587 | nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((u32)conn_param->ord); | 2802 | nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((u32)conn_param->ord); |
| 2588 | nes_debug(NES_DBG_CM, "requested ord = 0x%08X.\n", (u32)conn_param->ord); | 2803 | nes_debug(NES_DBG_CM, "requested ord = 0x%08X.\n", (u32)conn_param->ord); |
| 2589 | nes_debug(NES_DBG_CM, "mpa private data len =%u\n", conn_param->private_data_len); | 2804 | nes_debug(NES_DBG_CM, "mpa private data len =%u\n", |
| 2590 | 2805 | conn_param->private_data_len); | |
| 2591 | strcpy(&nesqp->ietf_frame->key[0], IEFT_MPA_KEY_REQ); | ||
| 2592 | nesqp->ietf_frame->flags = IETF_MPA_FLAGS_CRC; | ||
| 2593 | nesqp->ietf_frame->rev = IETF_MPA_VERSION; | ||
| 2594 | nesqp->ietf_frame->priv_data_len = htons(conn_param->private_data_len); | ||
| 2595 | 2806 | ||
| 2596 | if (cm_id->local_addr.sin_addr.s_addr != cm_id->remote_addr.sin_addr.s_addr) | 2807 | if (cm_id->local_addr.sin_addr.s_addr != |
| 2808 | cm_id->remote_addr.sin_addr.s_addr) | ||
| 2597 | nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port), | 2809 | nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port), |
| 2598 | PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD); | 2810 | PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD); |
| 2599 | 2811 | ||
| 2600 | /* set up the connection params for the node */ | 2812 | /* set up the connection params for the node */ |
| 2601 | cm_info.loc_addr = (cm_id->local_addr.sin_addr.s_addr); | 2813 | cm_info.loc_addr = htonl(cm_id->local_addr.sin_addr.s_addr); |
| 2602 | cm_info.loc_port = (cm_id->local_addr.sin_port); | 2814 | cm_info.loc_port = htons(cm_id->local_addr.sin_port); |
| 2603 | cm_info.rem_addr = (cm_id->remote_addr.sin_addr.s_addr); | 2815 | cm_info.rem_addr = htonl(cm_id->remote_addr.sin_addr.s_addr); |
| 2604 | cm_info.rem_port = (cm_id->remote_addr.sin_port); | 2816 | cm_info.rem_port = htons(cm_id->remote_addr.sin_port); |
| 2605 | cm_info.cm_id = cm_id; | 2817 | cm_info.cm_id = cm_id; |
| 2606 | cm_info.conn_type = NES_CM_IWARP_CONN_TYPE; | 2818 | cm_info.conn_type = NES_CM_IWARP_CONN_TYPE; |
| 2607 | 2819 | ||
| 2608 | cm_id->add_ref(cm_id); | 2820 | cm_id->add_ref(cm_id); |
| 2609 | nes_add_ref(&nesqp->ibqp); | ||
| 2610 | 2821 | ||
| 2611 | /* create a connect CM node connection */ | 2822 | /* create a connect CM node connection */ |
| 2612 | cm_node = g_cm_core->api->connect(g_cm_core, nesvnic, nesqp->ietf_frame, &cm_info); | 2823 | cm_node = g_cm_core->api->connect(g_cm_core, nesvnic, |
| 2824 | conn_param->private_data_len, (void *)conn_param->private_data, | ||
| 2825 | &cm_info); | ||
| 2613 | if (!cm_node) { | 2826 | if (!cm_node) { |
| 2614 | if (cm_id->local_addr.sin_addr.s_addr != cm_id->remote_addr.sin_addr.s_addr) | 2827 | if (cm_id->local_addr.sin_addr.s_addr != |
| 2828 | cm_id->remote_addr.sin_addr.s_addr) | ||
| 2615 | nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port), | 2829 | nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port), |
| 2616 | PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_DEL); | 2830 | PCI_FUNC(nesdev->pcidev->devfn), |
| 2617 | nes_rem_ref(&nesqp->ibqp); | 2831 | NES_MANAGE_APBVT_DEL); |
| 2618 | kfree(nesqp->ietf_frame); | 2832 | |
| 2619 | nesqp->ietf_frame = NULL; | ||
| 2620 | cm_id->rem_ref(cm_id); | 2833 | cm_id->rem_ref(cm_id); |
| 2621 | return -ENOMEM; | 2834 | return -ENOMEM; |
| 2622 | } | 2835 | } |
| 2623 | 2836 | ||
| 2624 | cm_node->apbvt_set = 1; | 2837 | cm_node->apbvt_set = 1; |
| 2625 | nesqp->cm_node = cm_node; | 2838 | nesqp->cm_node = cm_node; |
| 2839 | cm_node->nesqp = nesqp; | ||
| 2626 | 2840 | ||
| 2627 | return 0; | 2841 | return 0; |
| 2628 | } | 2842 | } |
| @@ -2664,7 +2878,7 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog) | |||
| 2664 | 2878 | ||
| 2665 | cm_node = g_cm_core->api->listen(g_cm_core, nesvnic, &cm_info); | 2879 | cm_node = g_cm_core->api->listen(g_cm_core, nesvnic, &cm_info); |
| 2666 | if (!cm_node) { | 2880 | if (!cm_node) { |
| 2667 | printk("%s[%u] Error returned from listen API call\n", | 2881 | printk(KERN_ERR "%s[%u] Error returned from listen API call\n", |
| 2668 | __func__, __LINE__); | 2882 | __func__, __LINE__); |
| 2669 | return -ENOMEM; | 2883 | return -ENOMEM; |
| 2670 | } | 2884 | } |
| @@ -2672,10 +2886,13 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog) | |||
| 2672 | cm_id->provider_data = cm_node; | 2886 | cm_id->provider_data = cm_node; |
| 2673 | 2887 | ||
| 2674 | if (!cm_node->reused_node) { | 2888 | if (!cm_node->reused_node) { |
| 2675 | err = nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port), | 2889 | err = nes_manage_apbvt(nesvnic, |
| 2676 | PCI_FUNC(nesvnic->nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD); | 2890 | ntohs(cm_id->local_addr.sin_port), |
| 2891 | PCI_FUNC(nesvnic->nesdev->pcidev->devfn), | ||
| 2892 | NES_MANAGE_APBVT_ADD); | ||
| 2677 | if (err) { | 2893 | if (err) { |
| 2678 | printk("nes_manage_apbvt call returned %d.\n", err); | 2894 | printk(KERN_ERR "nes_manage_apbvt call returned %d.\n", |
| 2895 | err); | ||
| 2679 | g_cm_core->api->stop_listener(g_cm_core, (void *)cm_node); | 2896 | g_cm_core->api->stop_listener(g_cm_core, (void *)cm_node); |
| 2680 | return err; | 2897 | return err; |
| 2681 | } | 2898 | } |
| @@ -2795,53 +3012,70 @@ static void cm_event_connected(struct nes_cm_event *event) | |||
| 2795 | nes_cm_init_tsa_conn(nesqp, cm_node); | 3012 | nes_cm_init_tsa_conn(nesqp, cm_node); |
| 2796 | 3013 | ||
| 2797 | /* set the QP tsa context */ | 3014 | /* set the QP tsa context */ |
| 2798 | nesqp->nesqp_context->tcpPorts[0] = cpu_to_le16(ntohs(cm_id->local_addr.sin_port)); | 3015 | nesqp->nesqp_context->tcpPorts[0] = |
| 2799 | nesqp->nesqp_context->tcpPorts[1] = cpu_to_le16(ntohs(cm_id->remote_addr.sin_port)); | 3016 | cpu_to_le16(ntohs(cm_id->local_addr.sin_port)); |
| 2800 | nesqp->nesqp_context->ip0 = cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr)); | 3017 | nesqp->nesqp_context->tcpPorts[1] = |
| 3018 | cpu_to_le16(ntohs(cm_id->remote_addr.sin_port)); | ||
| 3019 | if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr)) | ||
| 3020 | nesqp->nesqp_context->ip0 = | ||
| 3021 | cpu_to_le32(ntohl(nesvnic->local_ipaddr)); | ||
| 3022 | else | ||
| 3023 | nesqp->nesqp_context->ip0 = | ||
| 3024 | cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr)); | ||
| 2801 | 3025 | ||
| 2802 | nesqp->nesqp_context->misc2 |= cpu_to_le32( | 3026 | nesqp->nesqp_context->misc2 |= cpu_to_le32( |
| 2803 | (u32)PCI_FUNC(nesdev->pcidev->devfn) << NES_QPCONTEXT_MISC2_SRC_IP_SHIFT); | 3027 | (u32)PCI_FUNC(nesdev->pcidev->devfn) << |
| 3028 | NES_QPCONTEXT_MISC2_SRC_IP_SHIFT); | ||
| 2804 | nesqp->nesqp_context->arp_index_vlan |= cpu_to_le32( | 3029 | nesqp->nesqp_context->arp_index_vlan |= cpu_to_le32( |
| 2805 | nes_arp_table(nesdev, le32_to_cpu(nesqp->nesqp_context->ip0), | 3030 | nes_arp_table(nesdev, |
| 3031 | le32_to_cpu(nesqp->nesqp_context->ip0), | ||
| 2806 | NULL, NES_ARP_RESOLVE) << 16); | 3032 | NULL, NES_ARP_RESOLVE) << 16); |
| 2807 | nesqp->nesqp_context->ts_val_delta = cpu_to_le32( | 3033 | nesqp->nesqp_context->ts_val_delta = cpu_to_le32( |
| 2808 | jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW)); | 3034 | jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW)); |
| 2809 | nesqp->nesqp_context->ird_index = cpu_to_le32(nesqp->hwqp.qp_id); | 3035 | nesqp->nesqp_context->ird_index = cpu_to_le32(nesqp->hwqp.qp_id); |
| 2810 | nesqp->nesqp_context->ird_ord_sizes |= | 3036 | nesqp->nesqp_context->ird_ord_sizes |= |
| 2811 | cpu_to_le32((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT); | 3037 | cpu_to_le32((u32)1 << |
| 3038 | NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT); | ||
| 2812 | 3039 | ||
| 2813 | /* Adjust tail for not having a LSMM */ | 3040 | /* Adjust tail for not having a LSMM */ |
| 2814 | nesqp->hwqp.sq_tail = 1; | 3041 | nesqp->hwqp.sq_tail = 1; |
| 2815 | 3042 | ||
| 2816 | #if defined(NES_SEND_FIRST_WRITE) | 3043 | #if defined(NES_SEND_FIRST_WRITE) |
| 2817 | if (cm_node->send_write0) { | 3044 | if (cm_node->send_write0) { |
| 2818 | nes_debug(NES_DBG_CM, "Sending first write.\n"); | 3045 | nes_debug(NES_DBG_CM, "Sending first write.\n"); |
| 2819 | wqe = &nesqp->hwqp.sq_vbase[0]; | 3046 | wqe = &nesqp->hwqp.sq_vbase[0]; |
| 2820 | u64temp = (unsigned long)nesqp; | 3047 | u64temp = (unsigned long)nesqp; |
| 2821 | u64temp |= NES_SW_CONTEXT_ALIGN>>1; | 3048 | u64temp |= NES_SW_CONTEXT_ALIGN>>1; |
| 2822 | set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX, | 3049 | set_wqe_64bit_value(wqe->wqe_words, |
| 2823 | u64temp); | 3050 | NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX, u64temp); |
| 2824 | wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] = cpu_to_le32(NES_IWARP_SQ_OP_RDMAW); | 3051 | wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] = |
| 2825 | wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] = 0; | 3052 | cpu_to_le32(NES_IWARP_SQ_OP_RDMAW); |
| 2826 | wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] = 0; | 3053 | wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] = 0; |
| 2827 | wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] = 0; | 3054 | wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] = 0; |
| 2828 | wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] = 0; | 3055 | wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] = 0; |
| 2829 | wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0; | 3056 | wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] = 0; |
| 2830 | 3057 | wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0; | |
| 2831 | /* use the reserved spot on the WQ for the extra first WQE */ | 3058 | |
| 2832 | nesqp->nesqp_context->ird_ord_sizes &= cpu_to_le32(~(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT | | 3059 | /* use the reserved spot on the WQ for the extra first WQE */ |
| 2833 | NES_QPCONTEXT_ORDIRD_WRPDU | NES_QPCONTEXT_ORDIRD_ALSMM)); | 3060 | nesqp->nesqp_context->ird_ord_sizes &= |
| 2834 | nesqp->skip_lsmm = 1; | 3061 | cpu_to_le32(~(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT | |
| 2835 | nesqp->hwqp.sq_tail = 0; | 3062 | NES_QPCONTEXT_ORDIRD_WRPDU | |
| 2836 | nes_write32(nesdev->regs + NES_WQE_ALLOC, | 3063 | NES_QPCONTEXT_ORDIRD_ALSMM)); |
| 2837 | (1 << 24) | 0x00800000 | nesqp->hwqp.qp_id); | 3064 | nesqp->skip_lsmm = 1; |
| 2838 | } | 3065 | nesqp->hwqp.sq_tail = 0; |
| 3066 | nes_write32(nesdev->regs + NES_WQE_ALLOC, | ||
| 3067 | (1 << 24) | 0x00800000 | nesqp->hwqp.qp_id); | ||
| 3068 | } | ||
| 2839 | #endif | 3069 | #endif |
| 2840 | 3070 | ||
| 2841 | memset(&nes_quad, 0, sizeof(nes_quad)); | 3071 | memset(&nes_quad, 0, sizeof(nes_quad)); |
| 2842 | 3072 | ||
| 2843 | nes_quad.DstIpAdrIndex = cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24); | 3073 | nes_quad.DstIpAdrIndex = |
| 2844 | nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr; | 3074 | cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24); |
| 3075 | if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr)) | ||
| 3076 | nes_quad.SrcIpadr = nesvnic->local_ipaddr; | ||
| 3077 | else | ||
| 3078 | nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr; | ||
| 2845 | nes_quad.TcpPorts[0] = cm_id->remote_addr.sin_port; | 3079 | nes_quad.TcpPorts[0] = cm_id->remote_addr.sin_port; |
| 2846 | nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port; | 3080 | nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port; |
| 2847 | 3081 | ||
| @@ -2858,10 +3092,6 @@ static void cm_event_connected(struct nes_cm_event *event) | |||
| 2858 | nesqp->private_data_len = (u8) cm_node->mpa_frame_size; | 3092 | nesqp->private_data_len = (u8) cm_node->mpa_frame_size; |
| 2859 | cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node); | 3093 | cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node); |
| 2860 | 3094 | ||
| 2861 | /* modify QP state to rts */ | ||
| 2862 | attr.qp_state = IB_QPS_RTS; | ||
| 2863 | nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL); | ||
| 2864 | |||
| 2865 | /* notify OF layer we successfully created the requested connection */ | 3095 | /* notify OF layer we successfully created the requested connection */ |
| 2866 | cm_event.event = IW_CM_EVENT_CONNECT_REPLY; | 3096 | cm_event.event = IW_CM_EVENT_CONNECT_REPLY; |
| 2867 | cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED; | 3097 | cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED; |
| @@ -2870,20 +3100,21 @@ static void cm_event_connected(struct nes_cm_event *event) | |||
| 2870 | cm_event.local_addr.sin_port = cm_id->local_addr.sin_port; | 3100 | cm_event.local_addr.sin_port = cm_id->local_addr.sin_port; |
| 2871 | cm_event.remote_addr = cm_id->remote_addr; | 3101 | cm_event.remote_addr = cm_id->remote_addr; |
| 2872 | 3102 | ||
| 2873 | cm_event.private_data = (void *)event->cm_node->mpa_frame_buf; | 3103 | cm_event.private_data = (void *)event->cm_node->mpa_frame_buf; |
| 2874 | cm_event.private_data_len = (u8) event->cm_node->mpa_frame_size; | 3104 | cm_event.private_data_len = (u8) event->cm_node->mpa_frame_size; |
| 2875 | 3105 | ||
| 2876 | cm_event.local_addr.sin_addr.s_addr = event->cm_info.rem_addr; | 3106 | cm_event.local_addr.sin_addr.s_addr = event->cm_info.rem_addr; |
| 2877 | ret = cm_id->event_handler(cm_id, &cm_event); | 3107 | ret = cm_id->event_handler(cm_id, &cm_event); |
| 2878 | nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret); | 3108 | nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret); |
| 2879 | 3109 | ||
| 2880 | if (ret) | 3110 | if (ret) |
| 2881 | printk("%s[%u] OFA CM event_handler returned, ret=%d\n", | 3111 | printk(KERN_ERR "%s[%u] OFA CM event_handler returned, " |
| 2882 | __func__, __LINE__, ret); | 3112 | "ret=%d\n", __func__, __LINE__, ret); |
| 2883 | nes_debug(NES_DBG_CM, "Exiting connect thread for QP%u. jiffies = %lu\n", | 3113 | attr.qp_state = IB_QPS_RTS; |
| 2884 | nesqp->hwqp.qp_id, jiffies ); | 3114 | nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL); |
| 2885 | 3115 | ||
| 2886 | nes_rem_ref(&nesqp->ibqp); | 3116 | nes_debug(NES_DBG_CM, "Exiting connect thread for QP%u. jiffies = " |
| 3117 | "%lu\n", nesqp->hwqp.qp_id, jiffies); | ||
| 2887 | 3118 | ||
| 2888 | return; | 3119 | return; |
| 2889 | } | 3120 | } |
| @@ -2927,17 +3158,19 @@ static void cm_event_connect_error(struct nes_cm_event *event) | |||
| 2927 | cm_event.private_data = NULL; | 3158 | cm_event.private_data = NULL; |
| 2928 | cm_event.private_data_len = 0; | 3159 | cm_event.private_data_len = 0; |
| 2929 | 3160 | ||
| 2930 | nes_debug(NES_DBG_CM, "call CM_EVENT REJECTED, local_addr=%08x, remove_addr=%08x\n", | 3161 | nes_debug(NES_DBG_CM, "call CM_EVENT REJECTED, local_addr=%08x, " |
| 2931 | cm_event.local_addr.sin_addr.s_addr, cm_event.remote_addr.sin_addr.s_addr); | 3162 | "remove_addr=%08x\n", cm_event.local_addr.sin_addr.s_addr, |
| 3163 | cm_event.remote_addr.sin_addr.s_addr); | ||
| 2932 | 3164 | ||
| 2933 | ret = cm_id->event_handler(cm_id, &cm_event); | 3165 | ret = cm_id->event_handler(cm_id, &cm_event); |
| 2934 | nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret); | 3166 | nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret); |
| 2935 | if (ret) | 3167 | if (ret) |
| 2936 | printk("%s[%u] OFA CM event_handler returned, ret=%d\n", | 3168 | printk(KERN_ERR "%s[%u] OFA CM event_handler returned, " |
| 2937 | __func__, __LINE__, ret); | 3169 | "ret=%d\n", __func__, __LINE__, ret); |
| 2938 | nes_rem_ref(&nesqp->ibqp); | 3170 | nes_rem_ref(&nesqp->ibqp); |
| 2939 | cm_id->rem_ref(cm_id); | 3171 | cm_id->rem_ref(cm_id); |
| 2940 | 3172 | ||
| 3173 | rem_ref_cm_node(event->cm_node->cm_core, event->cm_node); | ||
| 2941 | return; | 3174 | return; |
| 2942 | } | 3175 | } |
| 2943 | 3176 | ||
| @@ -3040,7 +3273,8 @@ static int nes_cm_post_event(struct nes_cm_event *event) | |||
| 3040 | add_ref_cm_node(event->cm_node); | 3273 | add_ref_cm_node(event->cm_node); |
| 3041 | event->cm_info.cm_id->add_ref(event->cm_info.cm_id); | 3274 | event->cm_info.cm_id->add_ref(event->cm_info.cm_id); |
| 3042 | INIT_WORK(&event->event_work, nes_cm_event_handler); | 3275 | INIT_WORK(&event->event_work, nes_cm_event_handler); |
| 3043 | nes_debug(NES_DBG_CM, "queue_work, event=%p\n", event); | 3276 | nes_debug(NES_DBG_CM, "cm_node=%p queue_work, event=%p\n", |
| 3277 | event->cm_node, event); | ||
| 3044 | 3278 | ||
| 3045 | queue_work(event->cm_node->cm_core->event_wq, &event->event_work); | 3279 | queue_work(event->cm_node->cm_core->event_wq, &event->event_work); |
| 3046 | 3280 | ||
| @@ -3056,46 +3290,48 @@ static int nes_cm_post_event(struct nes_cm_event *event) | |||
| 3056 | */ | 3290 | */ |
| 3057 | static void nes_cm_event_handler(struct work_struct *work) | 3291 | static void nes_cm_event_handler(struct work_struct *work) |
| 3058 | { | 3292 | { |
| 3059 | struct nes_cm_event *event = container_of(work, struct nes_cm_event, event_work); | 3293 | struct nes_cm_event *event = container_of(work, struct nes_cm_event, |
| 3294 | event_work); | ||
| 3060 | struct nes_cm_core *cm_core; | 3295 | struct nes_cm_core *cm_core; |
| 3061 | 3296 | ||
| 3062 | if ((!event) || (!event->cm_node) || (!event->cm_node->cm_core)) { | 3297 | if ((!event) || (!event->cm_node) || (!event->cm_node->cm_core)) |
| 3063 | return; | 3298 | return; |
| 3064 | } | 3299 | |
| 3065 | cm_core = event->cm_node->cm_core; | 3300 | cm_core = event->cm_node->cm_core; |
| 3066 | nes_debug(NES_DBG_CM, "event=%p, event->type=%u, events posted=%u\n", | 3301 | nes_debug(NES_DBG_CM, "event=%p, event->type=%u, events posted=%u\n", |
| 3067 | event, event->type, atomic_read(&cm_core->events_posted)); | 3302 | event, event->type, atomic_read(&cm_core->events_posted)); |
| 3068 | 3303 | ||
| 3069 | switch (event->type) { | 3304 | switch (event->type) { |
| 3070 | case NES_CM_EVENT_MPA_REQ: | 3305 | case NES_CM_EVENT_MPA_REQ: |
| 3071 | cm_event_mpa_req(event); | 3306 | cm_event_mpa_req(event); |
| 3072 | nes_debug(NES_DBG_CM, "CM Event: MPA REQUEST\n"); | 3307 | nes_debug(NES_DBG_CM, "cm_node=%p CM Event: MPA REQUEST\n", |
| 3073 | break; | 3308 | event->cm_node); |
| 3074 | case NES_CM_EVENT_RESET: | 3309 | break; |
| 3075 | nes_debug(NES_DBG_CM, "CM Event: RESET\n"); | 3310 | case NES_CM_EVENT_RESET: |
| 3076 | cm_event_reset(event); | 3311 | nes_debug(NES_DBG_CM, "cm_node = %p CM Event: RESET\n", |
| 3077 | break; | 3312 | event->cm_node); |
| 3078 | case NES_CM_EVENT_CONNECTED: | 3313 | cm_event_reset(event); |
| 3079 | if ((!event->cm_node->cm_id) || | 3314 | break; |
| 3080 | (event->cm_node->state != NES_CM_STATE_TSA)) { | 3315 | case NES_CM_EVENT_CONNECTED: |
| 3081 | break; | 3316 | if ((!event->cm_node->cm_id) || |
| 3082 | } | 3317 | (event->cm_node->state != NES_CM_STATE_TSA)) |
| 3083 | cm_event_connected(event); | ||
| 3084 | nes_debug(NES_DBG_CM, "CM Event: CONNECTED\n"); | ||
| 3085 | break; | 3318 | break; |
| 3086 | case NES_CM_EVENT_ABORTED: | 3319 | cm_event_connected(event); |
| 3087 | if ((!event->cm_node->cm_id) || (event->cm_node->state == NES_CM_STATE_TSA)) { | 3320 | nes_debug(NES_DBG_CM, "CM Event: CONNECTED\n"); |
| 3088 | break; | 3321 | break; |
| 3089 | } | 3322 | case NES_CM_EVENT_ABORTED: |
| 3090 | cm_event_connect_error(event); | 3323 | if ((!event->cm_node->cm_id) || |
| 3091 | nes_debug(NES_DBG_CM, "CM Event: ABORTED\n"); | 3324 | (event->cm_node->state == NES_CM_STATE_TSA)) |
| 3092 | break; | ||
| 3093 | case NES_CM_EVENT_DROPPED_PKT: | ||
| 3094 | nes_debug(NES_DBG_CM, "CM Event: DROPPED PKT\n"); | ||
| 3095 | break; | ||
| 3096 | default: | ||
| 3097 | nes_debug(NES_DBG_CM, "CM Event: UNKNOWN EVENT TYPE\n"); | ||
| 3098 | break; | 3325 | break; |
| 3326 | cm_event_connect_error(event); | ||
| 3327 | nes_debug(NES_DBG_CM, "CM Event: ABORTED\n"); | ||
| 3328 | break; | ||
| 3329 | case NES_CM_EVENT_DROPPED_PKT: | ||
| 3330 | nes_debug(NES_DBG_CM, "CM Event: DROPPED PKT\n"); | ||
| 3331 | break; | ||
| 3332 | default: | ||
| 3333 | nes_debug(NES_DBG_CM, "CM Event: UNKNOWN EVENT TYPE\n"); | ||
| 3334 | break; | ||
| 3099 | } | 3335 | } |
| 3100 | 3336 | ||
| 3101 | atomic_dec(&cm_core->events_posted); | 3337 | atomic_dec(&cm_core->events_posted); |
diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h index 7717cb2ab500..367b3d290140 100644 --- a/drivers/infiniband/hw/nes/nes_cm.h +++ b/drivers/infiniband/hw/nes/nes_cm.h | |||
| @@ -83,6 +83,8 @@ enum nes_timer_type { | |||
| 83 | #define SET_FIN 4 | 83 | #define SET_FIN 4 |
| 84 | #define SET_RST 8 | 84 | #define SET_RST 8 |
| 85 | 85 | ||
| 86 | #define TCP_OPTIONS_PADDING 3 | ||
| 87 | |||
| 86 | struct option_base { | 88 | struct option_base { |
| 87 | u8 optionnum; | 89 | u8 optionnum; |
| 88 | u8 length; | 90 | u8 length; |
| @@ -177,6 +179,7 @@ enum nes_cm_node_state { | |||
| 177 | NES_CM_STATE_ESTABLISHED, | 179 | NES_CM_STATE_ESTABLISHED, |
| 178 | NES_CM_STATE_ACCEPTING, | 180 | NES_CM_STATE_ACCEPTING, |
| 179 | NES_CM_STATE_MPAREQ_SENT, | 181 | NES_CM_STATE_MPAREQ_SENT, |
| 182 | NES_CM_STATE_MPAREQ_RCVD, | ||
| 180 | NES_CM_STATE_TSA, | 183 | NES_CM_STATE_TSA, |
| 181 | NES_CM_STATE_FIN_WAIT1, | 184 | NES_CM_STATE_FIN_WAIT1, |
| 182 | NES_CM_STATE_FIN_WAIT2, | 185 | NES_CM_STATE_FIN_WAIT2, |
| @@ -187,6 +190,16 @@ enum nes_cm_node_state { | |||
| 187 | NES_CM_STATE_CLOSED | 190 | NES_CM_STATE_CLOSED |
| 188 | }; | 191 | }; |
| 189 | 192 | ||
| 193 | enum nes_tcpip_pkt_type { | ||
| 194 | NES_PKT_TYPE_UNKNOWN, | ||
| 195 | NES_PKT_TYPE_SYN, | ||
| 196 | NES_PKT_TYPE_SYNACK, | ||
| 197 | NES_PKT_TYPE_ACK, | ||
| 198 | NES_PKT_TYPE_FIN, | ||
| 199 | NES_PKT_TYPE_RST | ||
| 200 | }; | ||
| 201 | |||
| 202 | |||
| 190 | /* type of nes connection */ | 203 | /* type of nes connection */ |
| 191 | enum nes_cm_conn_type { | 204 | enum nes_cm_conn_type { |
| 192 | NES_CM_IWARP_CONN_TYPE, | 205 | NES_CM_IWARP_CONN_TYPE, |
| @@ -257,7 +270,9 @@ struct nes_cm_node { | |||
| 257 | struct net_device *netdev; | 270 | struct net_device *netdev; |
| 258 | 271 | ||
| 259 | struct nes_cm_node *loopbackpartner; | 272 | struct nes_cm_node *loopbackpartner; |
| 260 | struct list_head retrans_list; | 273 | |
| 274 | struct nes_timer_entry *send_entry; | ||
| 275 | |||
| 261 | spinlock_t retrans_list_lock; | 276 | spinlock_t retrans_list_lock; |
| 262 | struct list_head recv_list; | 277 | struct list_head recv_list; |
| 263 | spinlock_t recv_list_lock; | 278 | spinlock_t recv_list_lock; |
| @@ -276,6 +291,8 @@ struct nes_cm_node { | |||
| 276 | struct nes_vnic *nesvnic; | 291 | struct nes_vnic *nesvnic; |
| 277 | int apbvt_set; | 292 | int apbvt_set; |
| 278 | int accept_pend; | 293 | int accept_pend; |
| 294 | int freed; | ||
| 295 | struct nes_qp *nesqp; | ||
| 279 | }; | 296 | }; |
| 280 | 297 | ||
| 281 | /* structure for client or CM to fill when making CM api calls. */ | 298 | /* structure for client or CM to fill when making CM api calls. */ |
| @@ -366,14 +383,14 @@ struct nes_cm_ops { | |||
| 366 | struct nes_cm_info *); | 383 | struct nes_cm_info *); |
| 367 | int (*stop_listener)(struct nes_cm_core *, struct nes_cm_listener *); | 384 | int (*stop_listener)(struct nes_cm_core *, struct nes_cm_listener *); |
| 368 | struct nes_cm_node * (*connect)(struct nes_cm_core *, | 385 | struct nes_cm_node * (*connect)(struct nes_cm_core *, |
| 369 | struct nes_vnic *, struct ietf_mpa_frame *, | 386 | struct nes_vnic *, u16, void *, |
| 370 | struct nes_cm_info *); | 387 | struct nes_cm_info *); |
| 371 | int (*close)(struct nes_cm_core *, struct nes_cm_node *); | 388 | int (*close)(struct nes_cm_core *, struct nes_cm_node *); |
| 372 | int (*accept)(struct nes_cm_core *, struct ietf_mpa_frame *, | 389 | int (*accept)(struct nes_cm_core *, struct ietf_mpa_frame *, |
| 373 | struct nes_cm_node *); | 390 | struct nes_cm_node *); |
| 374 | int (*reject)(struct nes_cm_core *, struct ietf_mpa_frame *, | 391 | int (*reject)(struct nes_cm_core *, struct ietf_mpa_frame *, |
| 375 | struct nes_cm_node *); | 392 | struct nes_cm_node *); |
| 376 | int (*recv_pkt)(struct nes_cm_core *, struct nes_vnic *, | 393 | void (*recv_pkt)(struct nes_cm_core *, struct nes_vnic *, |
| 377 | struct sk_buff *); | 394 | struct sk_buff *); |
| 378 | int (*destroy_cm_core)(struct nes_cm_core *); | 395 | int (*destroy_cm_core)(struct nes_cm_core *); |
| 379 | int (*get)(struct nes_cm_core *); | 396 | int (*get)(struct nes_cm_core *); |
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 85f26d19a32b..1513d4066f1b 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c | |||
| @@ -2814,7 +2814,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
| 2814 | nesqp = *((struct nes_qp **)&context); | 2814 | nesqp = *((struct nes_qp **)&context); |
| 2815 | if (atomic_inc_return(&nesqp->close_timer_started) == 1) { | 2815 | if (atomic_inc_return(&nesqp->close_timer_started) == 1) { |
| 2816 | nesqp->cm_id->add_ref(nesqp->cm_id); | 2816 | nesqp->cm_id->add_ref(nesqp->cm_id); |
| 2817 | nes_add_ref(&nesqp->ibqp); | ||
| 2818 | schedule_nes_timer(nesqp->cm_node, (struct sk_buff *)nesqp, | 2817 | schedule_nes_timer(nesqp->cm_node, (struct sk_buff *)nesqp, |
| 2819 | NES_TIMER_TYPE_CLOSE, 1, 0); | 2818 | NES_TIMER_TYPE_CLOSE, 1, 0); |
| 2820 | nes_debug(NES_DBG_AEQ, "QP%u Not decrementing QP refcount (%d)," | 2819 | nes_debug(NES_DBG_AEQ, "QP%u Not decrementing QP refcount (%d)," |
| @@ -2838,7 +2837,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
| 2838 | if (async_event_id == NES_AEQE_AEID_RESET_SENT) { | 2837 | if (async_event_id == NES_AEQE_AEID_RESET_SENT) { |
| 2839 | tcp_state = NES_AEQE_TCP_STATE_CLOSED; | 2838 | tcp_state = NES_AEQE_TCP_STATE_CLOSED; |
| 2840 | } | 2839 | } |
| 2841 | nes_add_ref(&nesqp->ibqp); | ||
| 2842 | spin_lock_irqsave(&nesqp->lock, flags); | 2840 | spin_lock_irqsave(&nesqp->lock, flags); |
| 2843 | nesqp->hw_iwarp_state = iwarp_state; | 2841 | nesqp->hw_iwarp_state = iwarp_state; |
| 2844 | nesqp->hw_tcp_state = tcp_state; | 2842 | nesqp->hw_tcp_state = tcp_state; |
| @@ -2876,7 +2874,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
| 2876 | } | 2874 | } |
| 2877 | spin_unlock_irqrestore(&nesqp->lock, flags); | 2875 | spin_unlock_irqrestore(&nesqp->lock, flags); |
| 2878 | if (next_iwarp_state) { | 2876 | if (next_iwarp_state) { |
| 2879 | nes_add_ref(&nesqp->ibqp); | ||
| 2880 | nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X," | 2877 | nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X," |
| 2881 | " also added another reference\n", | 2878 | " also added another reference\n", |
| 2882 | nesqp->hwqp.qp_id, next_iwarp_state); | 2879 | nesqp->hwqp.qp_id, next_iwarp_state); |
| @@ -2888,7 +2885,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
| 2888 | /* FIN Received but ib state not RTS, | 2885 | /* FIN Received but ib state not RTS, |
| 2889 | close complete will be on its way */ | 2886 | close complete will be on its way */ |
| 2890 | spin_unlock_irqrestore(&nesqp->lock, flags); | 2887 | spin_unlock_irqrestore(&nesqp->lock, flags); |
| 2891 | nes_rem_ref(&nesqp->ibqp); | ||
| 2892 | return; | 2888 | return; |
| 2893 | } | 2889 | } |
| 2894 | spin_unlock_irqrestore(&nesqp->lock, flags); | 2890 | spin_unlock_irqrestore(&nesqp->lock, flags); |
| @@ -2922,7 +2918,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
| 2922 | if ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) || | 2918 | if ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) || |
| 2923 | ((nesqp->ibqp_state == IB_QPS_RTS)&& | 2919 | ((nesqp->ibqp_state == IB_QPS_RTS)&& |
| 2924 | (async_event_id == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { | 2920 | (async_event_id == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { |
| 2925 | nes_add_ref(&nesqp->ibqp); | ||
| 2926 | nes_cm_disconn(nesqp); | 2921 | nes_cm_disconn(nesqp); |
| 2927 | } else { | 2922 | } else { |
| 2928 | nesqp->in_disconnect = 0; | 2923 | nesqp->in_disconnect = 0; |
| @@ -2931,7 +2926,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
| 2931 | break; | 2926 | break; |
| 2932 | case NES_AEQE_AEID_LLP_TOO_MANY_RETRIES: | 2927 | case NES_AEQE_AEID_LLP_TOO_MANY_RETRIES: |
| 2933 | nesqp = *((struct nes_qp **)&context); | 2928 | nesqp = *((struct nes_qp **)&context); |
| 2934 | nes_add_ref(&nesqp->ibqp); | ||
| 2935 | spin_lock_irqsave(&nesqp->lock, flags); | 2929 | spin_lock_irqsave(&nesqp->lock, flags); |
| 2936 | nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_ERROR; | 2930 | nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_ERROR; |
| 2937 | nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; | 2931 | nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; |
| @@ -3042,7 +3036,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
| 3042 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); | 3036 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); |
| 3043 | } | 3037 | } |
| 3044 | /* tell cm to disconnect, cm will queue work to thread */ | 3038 | /* tell cm to disconnect, cm will queue work to thread */ |
| 3045 | nes_add_ref(&nesqp->ibqp); | ||
| 3046 | nes_cm_disconn(nesqp); | 3039 | nes_cm_disconn(nesqp); |
| 3047 | break; | 3040 | break; |
| 3048 | case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE: | 3041 | case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE: |
| @@ -3062,7 +3055,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
| 3062 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); | 3055 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); |
| 3063 | } | 3056 | } |
| 3064 | /* tell cm to disconnect, cm will queue work to thread */ | 3057 | /* tell cm to disconnect, cm will queue work to thread */ |
| 3065 | nes_add_ref(&nesqp->ibqp); | ||
| 3066 | nes_cm_disconn(nesqp); | 3058 | nes_cm_disconn(nesqp); |
| 3067 | break; | 3059 | break; |
| 3068 | case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR: | 3060 | case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR: |
| @@ -3082,7 +3074,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, | |||
| 3082 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); | 3074 | nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); |
| 3083 | } | 3075 | } |
| 3084 | /* tell cm to disconnect, cm will queue work to thread */ | 3076 | /* tell cm to disconnect, cm will queue work to thread */ |
| 3085 | nes_add_ref(&nesqp->ibqp); | ||
| 3086 | nes_cm_disconn(nesqp); | 3077 | nes_cm_disconn(nesqp); |
| 3087 | break; | 3078 | break; |
| 3088 | /* TODO: additional AEs need to be here */ | 3079 | /* TODO: additional AEs need to be here */ |
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index e3939d13484e..d79942e84979 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c | |||
| @@ -2867,7 +2867,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
| 2867 | nesqp->hwqp.qp_id, attr->qp_state, nesqp->ibqp_state, | 2867 | nesqp->hwqp.qp_id, attr->qp_state, nesqp->ibqp_state, |
| 2868 | nesqp->iwarp_state, atomic_read(&nesqp->refcount)); | 2868 | nesqp->iwarp_state, atomic_read(&nesqp->refcount)); |
| 2869 | 2869 | ||
| 2870 | nes_add_ref(&nesqp->ibqp); | ||
| 2871 | spin_lock_irqsave(&nesqp->lock, qplockflags); | 2870 | spin_lock_irqsave(&nesqp->lock, qplockflags); |
| 2872 | 2871 | ||
| 2873 | nes_debug(NES_DBG_MOD_QP, "QP%u: hw_iwarp_state=0x%X, hw_tcp_state=0x%X," | 2872 | nes_debug(NES_DBG_MOD_QP, "QP%u: hw_iwarp_state=0x%X, hw_tcp_state=0x%X," |
| @@ -2882,7 +2881,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
| 2882 | nesqp->hwqp.qp_id); | 2881 | nesqp->hwqp.qp_id); |
| 2883 | if (nesqp->iwarp_state > (u32)NES_CQP_QP_IWARP_STATE_IDLE) { | 2882 | if (nesqp->iwarp_state > (u32)NES_CQP_QP_IWARP_STATE_IDLE) { |
| 2884 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); | 2883 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); |
| 2885 | nes_rem_ref(&nesqp->ibqp); | ||
| 2886 | return -EINVAL; | 2884 | return -EINVAL; |
| 2887 | } | 2885 | } |
| 2888 | next_iwarp_state = NES_CQP_QP_IWARP_STATE_IDLE; | 2886 | next_iwarp_state = NES_CQP_QP_IWARP_STATE_IDLE; |
| @@ -2893,7 +2891,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
| 2893 | nesqp->hwqp.qp_id); | 2891 | nesqp->hwqp.qp_id); |
| 2894 | if (nesqp->iwarp_state>(u32)NES_CQP_QP_IWARP_STATE_IDLE) { | 2892 | if (nesqp->iwarp_state>(u32)NES_CQP_QP_IWARP_STATE_IDLE) { |
| 2895 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); | 2893 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); |
| 2896 | nes_rem_ref(&nesqp->ibqp); | ||
| 2897 | return -EINVAL; | 2894 | return -EINVAL; |
| 2898 | } | 2895 | } |
| 2899 | next_iwarp_state = NES_CQP_QP_IWARP_STATE_IDLE; | 2896 | next_iwarp_state = NES_CQP_QP_IWARP_STATE_IDLE; |
| @@ -2904,14 +2901,12 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
| 2904 | nesqp->hwqp.qp_id); | 2901 | nesqp->hwqp.qp_id); |
| 2905 | if (nesqp->iwarp_state>(u32)NES_CQP_QP_IWARP_STATE_RTS) { | 2902 | if (nesqp->iwarp_state>(u32)NES_CQP_QP_IWARP_STATE_RTS) { |
| 2906 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); | 2903 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); |
| 2907 | nes_rem_ref(&nesqp->ibqp); | ||
| 2908 | return -EINVAL; | 2904 | return -EINVAL; |
| 2909 | } | 2905 | } |
| 2910 | if (nesqp->cm_id == NULL) { | 2906 | if (nesqp->cm_id == NULL) { |
| 2911 | nes_debug(NES_DBG_MOD_QP, "QP%u: Failing attempt to move QP to RTS without a CM_ID. \n", | 2907 | nes_debug(NES_DBG_MOD_QP, "QP%u: Failing attempt to move QP to RTS without a CM_ID. \n", |
| 2912 | nesqp->hwqp.qp_id ); | 2908 | nesqp->hwqp.qp_id ); |
| 2913 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); | 2909 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); |
| 2914 | nes_rem_ref(&nesqp->ibqp); | ||
| 2915 | return -EINVAL; | 2910 | return -EINVAL; |
| 2916 | } | 2911 | } |
| 2917 | next_iwarp_state = NES_CQP_QP_IWARP_STATE_RTS; | 2912 | next_iwarp_state = NES_CQP_QP_IWARP_STATE_RTS; |
| @@ -2929,7 +2924,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
| 2929 | nesqp->hwqp.qp_id, nesqp->hwqp.sq_head, nesqp->hwqp.sq_tail); | 2924 | nesqp->hwqp.qp_id, nesqp->hwqp.sq_head, nesqp->hwqp.sq_tail); |
| 2930 | if (nesqp->iwarp_state == (u32)NES_CQP_QP_IWARP_STATE_CLOSING) { | 2925 | if (nesqp->iwarp_state == (u32)NES_CQP_QP_IWARP_STATE_CLOSING) { |
| 2931 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); | 2926 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); |
| 2932 | nes_rem_ref(&nesqp->ibqp); | ||
| 2933 | return 0; | 2927 | return 0; |
| 2934 | } else { | 2928 | } else { |
| 2935 | if (nesqp->iwarp_state > (u32)NES_CQP_QP_IWARP_STATE_CLOSING) { | 2929 | if (nesqp->iwarp_state > (u32)NES_CQP_QP_IWARP_STATE_CLOSING) { |
| @@ -2937,7 +2931,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
| 2937 | " ignored due to current iWARP state\n", | 2931 | " ignored due to current iWARP state\n", |
| 2938 | nesqp->hwqp.qp_id); | 2932 | nesqp->hwqp.qp_id); |
| 2939 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); | 2933 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); |
| 2940 | nes_rem_ref(&nesqp->ibqp); | ||
| 2941 | return -EINVAL; | 2934 | return -EINVAL; |
| 2942 | } | 2935 | } |
| 2943 | if (nesqp->hw_iwarp_state != NES_AEQE_IWARP_STATE_RTS) { | 2936 | if (nesqp->hw_iwarp_state != NES_AEQE_IWARP_STATE_RTS) { |
| @@ -2969,7 +2962,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
| 2969 | nesqp->hwqp.qp_id); | 2962 | nesqp->hwqp.qp_id); |
| 2970 | if (nesqp->iwarp_state>=(u32)NES_CQP_QP_IWARP_STATE_TERMINATE) { | 2963 | if (nesqp->iwarp_state>=(u32)NES_CQP_QP_IWARP_STATE_TERMINATE) { |
| 2971 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); | 2964 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); |
| 2972 | nes_rem_ref(&nesqp->ibqp); | ||
| 2973 | return -EINVAL; | 2965 | return -EINVAL; |
| 2974 | } | 2966 | } |
| 2975 | /* next_iwarp_state = (NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000); */ | 2967 | /* next_iwarp_state = (NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000); */ |
| @@ -2982,7 +2974,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
| 2982 | case IB_QPS_RESET: | 2974 | case IB_QPS_RESET: |
| 2983 | if (nesqp->iwarp_state == (u32)NES_CQP_QP_IWARP_STATE_ERROR) { | 2975 | if (nesqp->iwarp_state == (u32)NES_CQP_QP_IWARP_STATE_ERROR) { |
| 2984 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); | 2976 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); |
| 2985 | nes_rem_ref(&nesqp->ibqp); | ||
| 2986 | return -EINVAL; | 2977 | return -EINVAL; |
| 2987 | } | 2978 | } |
| 2988 | nes_debug(NES_DBG_MOD_QP, "QP%u: new state = error\n", | 2979 | nes_debug(NES_DBG_MOD_QP, "QP%u: new state = error\n", |
| @@ -3008,7 +2999,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
| 3008 | break; | 2999 | break; |
| 3009 | default: | 3000 | default: |
| 3010 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); | 3001 | spin_unlock_irqrestore(&nesqp->lock, qplockflags); |
| 3011 | nes_rem_ref(&nesqp->ibqp); | ||
| 3012 | return -EINVAL; | 3002 | return -EINVAL; |
| 3013 | break; | 3003 | break; |
| 3014 | } | 3004 | } |
| @@ -3088,7 +3078,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
| 3088 | nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount), | 3078 | nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount), |
| 3089 | original_last_aeq, nesqp->last_aeq); | 3079 | original_last_aeq, nesqp->last_aeq); |
| 3090 | /* this one is for the cm_disconnect thread */ | 3080 | /* this one is for the cm_disconnect thread */ |
| 3091 | nes_add_ref(&nesqp->ibqp); | ||
| 3092 | spin_lock_irqsave(&nesqp->lock, qplockflags); | 3081 | spin_lock_irqsave(&nesqp->lock, qplockflags); |
| 3093 | nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; | 3082 | nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; |
| 3094 | nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT; | 3083 | nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT; |
| @@ -3097,14 +3086,12 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
| 3097 | } else { | 3086 | } else { |
| 3098 | nes_debug(NES_DBG_MOD_QP, "QP%u No fake disconnect, QP refcount=%d\n", | 3087 | nes_debug(NES_DBG_MOD_QP, "QP%u No fake disconnect, QP refcount=%d\n", |
| 3099 | nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount)); | 3088 | nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount)); |
| 3100 | nes_rem_ref(&nesqp->ibqp); | ||
| 3101 | } | 3089 | } |
| 3102 | } else { | 3090 | } else { |
| 3103 | spin_lock_irqsave(&nesqp->lock, qplockflags); | 3091 | spin_lock_irqsave(&nesqp->lock, qplockflags); |
| 3104 | if (nesqp->cm_id) { | 3092 | if (nesqp->cm_id) { |
| 3105 | /* These two are for the timer thread */ | 3093 | /* These two are for the timer thread */ |
| 3106 | if (atomic_inc_return(&nesqp->close_timer_started) == 1) { | 3094 | if (atomic_inc_return(&nesqp->close_timer_started) == 1) { |
| 3107 | nes_add_ref(&nesqp->ibqp); | ||
| 3108 | nesqp->cm_id->add_ref(nesqp->cm_id); | 3095 | nesqp->cm_id->add_ref(nesqp->cm_id); |
| 3109 | nes_debug(NES_DBG_MOD_QP, "QP%u Not decrementing QP refcount (%d)," | 3096 | nes_debug(NES_DBG_MOD_QP, "QP%u Not decrementing QP refcount (%d)," |
| 3110 | " need ae to finish up, original_last_aeq = 0x%04X." | 3097 | " need ae to finish up, original_last_aeq = 0x%04X." |
| @@ -3128,14 +3115,12 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, | |||
| 3128 | " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n", | 3115 | " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n", |
| 3129 | nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount), | 3116 | nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount), |
| 3130 | original_last_aeq, nesqp->last_aeq); | 3117 | original_last_aeq, nesqp->last_aeq); |
| 3131 | nes_rem_ref(&nesqp->ibqp); | ||
| 3132 | } | 3118 | } |
| 3133 | } else { | 3119 | } else { |
| 3134 | nes_debug(NES_DBG_MOD_QP, "QP%u Decrementing QP refcount (%d), No ae to finish up," | 3120 | nes_debug(NES_DBG_MOD_QP, "QP%u Decrementing QP refcount (%d), No ae to finish up," |
| 3135 | " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n", | 3121 | " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n", |
| 3136 | nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount), | 3122 | nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount), |
| 3137 | original_last_aeq, nesqp->last_aeq); | 3123 | original_last_aeq, nesqp->last_aeq); |
| 3138 | nes_rem_ref(&nesqp->ibqp); | ||
| 3139 | } | 3124 | } |
| 3140 | 3125 | ||
| 3141 | err = 0; | 3126 | err = 0; |
diff --git a/drivers/infiniband/ulp/ipoib/Kconfig b/drivers/infiniband/ulp/ipoib/Kconfig index 691525cf394a..9d9a9dc51f18 100644 --- a/drivers/infiniband/ulp/ipoib/Kconfig +++ b/drivers/infiniband/ulp/ipoib/Kconfig | |||
| @@ -11,16 +11,17 @@ config INFINIBAND_IPOIB | |||
| 11 | 11 | ||
| 12 | config INFINIBAND_IPOIB_CM | 12 | config INFINIBAND_IPOIB_CM |
| 13 | bool "IP-over-InfiniBand Connected Mode support" | 13 | bool "IP-over-InfiniBand Connected Mode support" |
| 14 | depends on INFINIBAND_IPOIB && EXPERIMENTAL | 14 | depends on INFINIBAND_IPOIB |
| 15 | default n | 15 | default n |
| 16 | ---help--- | 16 | ---help--- |
| 17 | This option enables experimental support for IPoIB connected mode. | 17 | This option enables support for IPoIB connected mode. After |
| 18 | After enabling this option, you need to switch to connected mode through | 18 | enabling this option, you need to switch to connected mode |
| 19 | /sys/class/net/ibXXX/mode to actually create connections, and then increase | 19 | through /sys/class/net/ibXXX/mode to actually create |
| 20 | the interface MTU with e.g. ifconfig ib0 mtu 65520. | 20 | connections, and then increase the interface MTU with |
| 21 | e.g. ifconfig ib0 mtu 65520. | ||
| 21 | 22 | ||
| 22 | WARNING: Enabling connected mode will trigger some | 23 | WARNING: Enabling connected mode will trigger some packet |
| 23 | packet drops for multicast and UD mode traffic from this interface, | 24 | drops for multicast and UD mode traffic from this interface, |
| 24 | unless you limit mtu for these destinations to 2044. | 25 | unless you limit mtu for these destinations to 2044. |
| 25 | 26 | ||
| 26 | config INFINIBAND_IPOIB_DEBUG | 27 | config INFINIBAND_IPOIB_DEBUG |
| @@ -33,9 +34,10 @@ config INFINIBAND_IPOIB_DEBUG | |||
| 33 | debug_level and mcast_debug_level module parameters (which | 34 | debug_level and mcast_debug_level module parameters (which |
| 34 | can also be set after the driver is loaded through sysfs). | 35 | can also be set after the driver is loaded through sysfs). |
| 35 | 36 | ||
| 36 | This option also creates an "ipoib_debugfs," which can be | 37 | This option also creates a directory tree under ipoib/ in |
| 37 | mounted to expose debugging information about IB multicast | 38 | debugfs, which contains files that expose debugging |
| 38 | groups used by the IPoIB driver. | 39 | information about IB multicast groups used by the IPoIB |
| 40 | driver. | ||
| 39 | 41 | ||
| 40 | config INFINIBAND_IPOIB_DEBUG_DATA | 42 | config INFINIBAND_IPOIB_DEBUG_DATA |
| 41 | bool "IP-over-InfiniBand data path debugging" | 43 | bool "IP-over-InfiniBand data path debugging" |
diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c index 4e9d8eece2e0..d0e13fc4a88c 100644 --- a/drivers/input/touchscreen/corgi_ts.c +++ b/drivers/input/touchscreen/corgi_ts.c | |||
| @@ -195,7 +195,7 @@ static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer) | |||
| 195 | { | 195 | { |
| 196 | if ((GPLR(IRQ_TO_GPIO(corgi_ts->irq_gpio)) & GPIO_bit(IRQ_TO_GPIO(corgi_ts->irq_gpio))) == 0) { | 196 | if ((GPLR(IRQ_TO_GPIO(corgi_ts->irq_gpio)) & GPIO_bit(IRQ_TO_GPIO(corgi_ts->irq_gpio))) == 0) { |
| 197 | /* Disable Interrupt */ | 197 | /* Disable Interrupt */ |
| 198 | set_irq_type(corgi_ts->irq_gpio, IRQT_NOEDGE); | 198 | set_irq_type(corgi_ts->irq_gpio, IRQ_TYPE_NONE); |
| 199 | if (read_xydata(corgi_ts)) { | 199 | if (read_xydata(corgi_ts)) { |
| 200 | corgi_ts->pendown = 1; | 200 | corgi_ts->pendown = 1; |
| 201 | new_data(corgi_ts); | 201 | new_data(corgi_ts); |
| @@ -214,7 +214,7 @@ static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer) | |||
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | /* Enable Falling Edge */ | 216 | /* Enable Falling Edge */ |
| 217 | set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING); | 217 | set_irq_type(corgi_ts->irq_gpio, IRQ_TYPE_EDGE_FALLING); |
| 218 | corgi_ts->pendown = 0; | 218 | corgi_ts->pendown = 0; |
| 219 | } | 219 | } |
| 220 | } | 220 | } |
| @@ -258,7 +258,7 @@ static int corgits_resume(struct platform_device *dev) | |||
| 258 | 258 | ||
| 259 | corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS); | 259 | corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS); |
| 260 | /* Enable Falling Edge */ | 260 | /* Enable Falling Edge */ |
| 261 | set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING); | 261 | set_irq_type(corgi_ts->irq_gpio, IRQ_TYPE_EDGE_FALLING); |
| 262 | corgi_ts->power_mode = PWR_MODE_ACTIVE; | 262 | corgi_ts->power_mode = PWR_MODE_ACTIVE; |
| 263 | 263 | ||
| 264 | return 0; | 264 | return 0; |
| @@ -333,7 +333,7 @@ static int __init corgits_probe(struct platform_device *pdev) | |||
| 333 | corgi_ts->power_mode = PWR_MODE_ACTIVE; | 333 | corgi_ts->power_mode = PWR_MODE_ACTIVE; |
| 334 | 334 | ||
| 335 | /* Enable Falling Edge */ | 335 | /* Enable Falling Edge */ |
| 336 | set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING); | 336 | set_irq_type(corgi_ts->irq_gpio, IRQ_TYPE_EDGE_FALLING); |
| 337 | 337 | ||
| 338 | return 0; | 338 | return 0; |
| 339 | 339 | ||
diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c index a79f029b91c0..590a1379aa32 100644 --- a/drivers/input/touchscreen/mainstone-wm97xx.c +++ b/drivers/input/touchscreen/mainstone-wm97xx.c | |||
| @@ -198,7 +198,7 @@ static int wm97xx_acc_startup(struct wm97xx *wm) | |||
| 198 | switch (wm->id) { | 198 | switch (wm->id) { |
| 199 | case WM9705_ID2: | 199 | case WM9705_ID2: |
| 200 | wm->pen_irq = IRQ_GPIO(4); | 200 | wm->pen_irq = IRQ_GPIO(4); |
| 201 | set_irq_type(IRQ_GPIO(4), IRQT_BOTHEDGE); | 201 | set_irq_type(IRQ_GPIO(4), IRQ_TYPE_EDGE_BOTH); |
| 202 | break; | 202 | break; |
| 203 | case WM9712_ID2: | 203 | case WM9712_ID2: |
| 204 | case WM9713_ID2: | 204 | case WM9713_ID2: |
diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig index 66f946aa30b3..3d113c6e4a70 100644 --- a/drivers/isdn/Kconfig +++ b/drivers/isdn/Kconfig | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | menuconfig ISDN | 5 | menuconfig ISDN |
| 6 | tristate "ISDN support" | 6 | bool "ISDN support" |
| 7 | depends on NET | 7 | depends on NET |
| 8 | depends on !S390 | 8 | depends on !S390 |
| 9 | ---help--- | 9 | ---help--- |
| @@ -21,6 +21,8 @@ menuconfig ISDN | |||
| 21 | 21 | ||
| 22 | if ISDN | 22 | if ISDN |
| 23 | 23 | ||
| 24 | source "drivers/isdn/mISDN/Kconfig" | ||
| 25 | |||
| 24 | menuconfig ISDN_I4L | 26 | menuconfig ISDN_I4L |
| 25 | tristate "Old ISDN4Linux (deprecated)" | 27 | tristate "Old ISDN4Linux (deprecated)" |
| 26 | ---help--- | 28 | ---help--- |
diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile index 988142c30a6d..8380a4568d11 100644 --- a/drivers/isdn/Makefile +++ b/drivers/isdn/Makefile | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | obj-$(CONFIG_ISDN_I4L) += i4l/ | 5 | obj-$(CONFIG_ISDN_I4L) += i4l/ |
| 6 | obj-$(CONFIG_ISDN_CAPI) += capi/ | 6 | obj-$(CONFIG_ISDN_CAPI) += capi/ |
| 7 | obj-$(CONFIG_MISDN) += mISDN/ | ||
| 7 | obj-$(CONFIG_ISDN_CAPI) += hardware/ | 8 | obj-$(CONFIG_ISDN_CAPI) += hardware/ |
| 8 | obj-$(CONFIG_ISDN_DIVERSION) += divert/ | 9 | obj-$(CONFIG_ISDN_DIVERSION) += divert/ |
| 9 | obj-$(CONFIG_ISDN_DRV_HISAX) += hisax/ | 10 | obj-$(CONFIG_ISDN_DRV_HISAX) += hisax/ |
diff --git a/drivers/isdn/hardware/Makefile b/drivers/isdn/hardware/Makefile index 11c8a183948c..a5d8fce4c4c4 100644 --- a/drivers/isdn/hardware/Makefile +++ b/drivers/isdn/hardware/Makefile | |||
| @@ -4,3 +4,4 @@ | |||
| 4 | 4 | ||
| 5 | obj-$(CONFIG_CAPI_AVM) += avm/ | 5 | obj-$(CONFIG_CAPI_AVM) += avm/ |
| 6 | obj-$(CONFIG_CAPI_EICON) += eicon/ | 6 | obj-$(CONFIG_CAPI_EICON) += eicon/ |
| 7 | obj-$(CONFIG_MISDN) += mISDN/ | ||
diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig new file mode 100644 index 000000000000..9cd5f5f62280 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/Kconfig | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | # | ||
| 2 | # Hardware for mISDN | ||
| 3 | # | ||
| 4 | comment "mISDN hardware drivers" | ||
| 5 | |||
| 6 | config MISDN_HFCPCI | ||
| 7 | tristate "Support for HFC PCI cards" | ||
| 8 | depends on MISDN | ||
| 9 | depends on PCI | ||
| 10 | depends on VIRT_TO_BUS | ||
| 11 | help | ||
| 12 | Enable support for cards with Cologne Chip AG's | ||
| 13 | HFC PCI chip. | ||
| 14 | |||
| 15 | config MISDN_HFCMULTI | ||
| 16 | tristate "Support for HFC multiport cards (HFC-4S/8S/E1)" | ||
| 17 | depends on PCI | ||
| 18 | depends on MISDN | ||
| 19 | help | ||
| 20 | Enable support for cards with Cologne Chip AG's HFC multiport | ||
| 21 | chip. There are three types of chips that are quite similar, | ||
| 22 | but the interface is different: | ||
| 23 | * HFC-4S (4 S/T interfaces on one chip) | ||
| 24 | * HFC-8S (8 S/T interfaces on one chip) | ||
| 25 | * HFC-E1 (E1 interface for 2Mbit ISDN) | ||
| 26 | |||
diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile new file mode 100644 index 000000000000..1e7ca5332ad7 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/Makefile | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | # | ||
| 2 | # Makefile for the modular ISDN hardware drivers | ||
| 3 | # | ||
| 4 | # | ||
| 5 | |||
| 6 | obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o | ||
| 7 | obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o | ||
diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h new file mode 100644 index 000000000000..a33d87afc843 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/hfc_multi.h | |||
| @@ -0,0 +1,1204 @@ | |||
| 1 | /* | ||
| 2 | * see notice in hfc_multi.c | ||
| 3 | */ | ||
| 4 | |||
| 5 | extern void ztdummy_extern_interrupt(void); | ||
| 6 | extern void ztdummy_register_interrupt(void); | ||
| 7 | extern int ztdummy_unregister_interrupt(void); | ||
| 8 | |||
| 9 | #define DEBUG_HFCMULTI_FIFO 0x00010000 | ||
| 10 | #define DEBUG_HFCMULTI_CRC 0x00020000 | ||
| 11 | #define DEBUG_HFCMULTI_INIT 0x00040000 | ||
| 12 | #define DEBUG_HFCMULTI_PLXSD 0x00080000 | ||
| 13 | #define DEBUG_HFCMULTI_MODE 0x00100000 | ||
| 14 | #define DEBUG_HFCMULTI_MSG 0x00200000 | ||
| 15 | #define DEBUG_HFCMULTI_STATE 0x00400000 | ||
| 16 | #define DEBUG_HFCMULTI_SYNC 0x01000000 | ||
| 17 | #define DEBUG_HFCMULTI_DTMF 0x02000000 | ||
| 18 | #define DEBUG_HFCMULTI_LOCK 0x80000000 | ||
| 19 | |||
| 20 | #define PCI_ENA_REGIO 0x01 | ||
| 21 | #define PCI_ENA_MEMIO 0x02 | ||
| 22 | |||
| 23 | /* | ||
| 24 | * NOTE: some registers are assigned multiple times due to different modes | ||
| 25 | * also registers are assigned differen for HFC-4s/8s and HFC-E1 | ||
| 26 | */ | ||
| 27 | |||
| 28 | /* | ||
| 29 | #define MAX_FRAME_SIZE 2048 | ||
| 30 | */ | ||
| 31 | |||
| 32 | struct hfc_chan { | ||
| 33 | struct dchannel *dch; /* link if channel is a D-channel */ | ||
| 34 | struct bchannel *bch; /* link if channel is a B-channel */ | ||
| 35 | int port; /* the interface port this */ | ||
| 36 | /* channel is associated with */ | ||
| 37 | int nt_timer; /* -1 if off, 0 if elapsed, >0 if running */ | ||
| 38 | int los, ais, slip_tx, slip_rx, rdi; /* current alarms */ | ||
| 39 | int jitter; | ||
| 40 | u_long cfg; /* port configuration */ | ||
| 41 | int sync; /* sync state (used by E1) */ | ||
| 42 | u_int protocol; /* current protocol */ | ||
| 43 | int slot_tx; /* current pcm slot */ | ||
| 44 | int bank_tx; /* current pcm bank */ | ||
| 45 | int slot_rx; | ||
| 46 | int bank_rx; | ||
| 47 | int conf; /* conference setting of TX slot */ | ||
| 48 | int txpending; /* if there is currently data in */ | ||
| 49 | /* the FIFO 0=no, 1=yes, 2=splloop */ | ||
| 50 | int rx_off; /* set to turn fifo receive off */ | ||
| 51 | int coeff_count; /* curren coeff block */ | ||
| 52 | s32 *coeff; /* memory pointer to 8 coeff blocks */ | ||
| 53 | }; | ||
| 54 | |||
| 55 | |||
| 56 | struct hfcm_hw { | ||
| 57 | u_char r_ctrl; | ||
| 58 | u_char r_irq_ctrl; | ||
| 59 | u_char r_cirm; | ||
| 60 | u_char r_ram_sz; | ||
| 61 | u_char r_pcm_md0; | ||
| 62 | u_char r_irqmsk_misc; | ||
| 63 | u_char r_dtmf; | ||
| 64 | u_char r_st_sync; | ||
| 65 | u_char r_sci_msk; | ||
| 66 | u_char r_tx0, r_tx1; | ||
| 67 | u_char a_st_ctrl0[8]; | ||
| 68 | timer_t timer; | ||
| 69 | }; | ||
| 70 | |||
| 71 | |||
| 72 | /* for each stack these flags are used (cfg) */ | ||
| 73 | #define HFC_CFG_NONCAP_TX 1 /* S/T TX interface has less capacity */ | ||
| 74 | #define HFC_CFG_DIS_ECHANNEL 2 /* disable E-channel processing */ | ||
| 75 | #define HFC_CFG_REG_ECHANNEL 3 /* register E-channel */ | ||
| 76 | #define HFC_CFG_OPTICAL 4 /* the E1 interface is optical */ | ||
| 77 | #define HFC_CFG_REPORT_LOS 5 /* the card should report loss of signal */ | ||
| 78 | #define HFC_CFG_REPORT_AIS 6 /* the card should report alarm ind. sign. */ | ||
| 79 | #define HFC_CFG_REPORT_SLIP 7 /* the card should report bit slips */ | ||
| 80 | #define HFC_CFG_REPORT_RDI 8 /* the card should report remote alarm */ | ||
| 81 | #define HFC_CFG_DTMF 9 /* enable DTMF-detection */ | ||
| 82 | #define HFC_CFG_CRC4 10 /* disable CRC-4 Multiframe mode, */ | ||
| 83 | /* use double frame instead. */ | ||
| 84 | |||
| 85 | #define HFC_CHIP_EXRAM_128 0 /* external ram 128k */ | ||
| 86 | #define HFC_CHIP_EXRAM_512 1 /* external ram 256k */ | ||
| 87 | #define HFC_CHIP_REVISION0 2 /* old fifo handling */ | ||
| 88 | #define HFC_CHIP_PCM_SLAVE 3 /* PCM is slave */ | ||
| 89 | #define HFC_CHIP_PCM_MASTER 4 /* PCM is master */ | ||
| 90 | #define HFC_CHIP_RX_SYNC 5 /* disable pll sync for pcm */ | ||
| 91 | #define HFC_CHIP_DTMF 6 /* DTMF decoding is enabled */ | ||
| 92 | #define HFC_CHIP_ULAW 7 /* ULAW mode */ | ||
| 93 | #define HFC_CHIP_CLOCK2 8 /* double clock mode */ | ||
| 94 | #define HFC_CHIP_E1CLOCK_GET 9 /* always get clock from E1 interface */ | ||
| 95 | #define HFC_CHIP_E1CLOCK_PUT 10 /* always put clock from E1 interface */ | ||
| 96 | #define HFC_CHIP_WATCHDOG 11 /* whether we should send signals */ | ||
| 97 | /* to the watchdog */ | ||
| 98 | #define HFC_CHIP_B410P 12 /* whether we have a b410p with echocan in */ | ||
| 99 | /* hw */ | ||
| 100 | #define HFC_CHIP_PLXSD 13 /* whether we have a Speech-Design PLX */ | ||
| 101 | |||
| 102 | #define HFC_IO_MODE_PCIMEM 0x00 /* normal memory mapped IO */ | ||
| 103 | #define HFC_IO_MODE_REGIO 0x01 /* PCI io access */ | ||
| 104 | #define HFC_IO_MODE_PLXSD 0x02 /* access HFC via PLX9030 */ | ||
| 105 | |||
| 106 | /* table entry in the PCI devices list */ | ||
| 107 | struct hm_map { | ||
| 108 | char *vendor_name; | ||
| 109 | char *card_name; | ||
| 110 | int type; | ||
| 111 | int ports; | ||
| 112 | int clock2; | ||
| 113 | int leds; | ||
| 114 | int opticalsupport; | ||
| 115 | int dip_type; | ||
| 116 | int io_mode; | ||
| 117 | }; | ||
| 118 | |||
| 119 | struct hfc_multi { | ||
| 120 | struct list_head list; | ||
| 121 | struct hm_map *mtyp; | ||
| 122 | int id; | ||
| 123 | int pcm; /* id of pcm bus */ | ||
| 124 | int type; | ||
| 125 | int ports; | ||
| 126 | |||
| 127 | u_int irq; /* irq used by card */ | ||
| 128 | u_int irqcnt; | ||
| 129 | struct pci_dev *pci_dev; | ||
| 130 | int io_mode; /* selects mode */ | ||
| 131 | #ifdef HFC_REGISTER_DEBUG | ||
| 132 | void (*HFC_outb)(struct hfc_multi *hc, u_char reg, | ||
| 133 | u_char val, const char *function, int line); | ||
| 134 | void (*HFC_outb_nodebug)(struct hfc_multi *hc, u_char reg, | ||
| 135 | u_char val, const char *function, int line); | ||
| 136 | u_char (*HFC_inb)(struct hfc_multi *hc, u_char reg, | ||
| 137 | const char *function, int line); | ||
| 138 | u_char (*HFC_inb_nodebug)(struct hfc_multi *hc, u_char reg, | ||
| 139 | const char *function, int line); | ||
| 140 | u_short (*HFC_inw)(struct hfc_multi *hc, u_char reg, | ||
| 141 | const char *function, int line); | ||
| 142 | u_short (*HFC_inw_nodebug)(struct hfc_multi *hc, u_char reg, | ||
| 143 | const char *function, int line); | ||
| 144 | void (*HFC_wait)(struct hfc_multi *hc, | ||
| 145 | const char *function, int line); | ||
| 146 | void (*HFC_wait_nodebug)(struct hfc_multi *hc, | ||
| 147 | const char *function, int line); | ||
| 148 | #else | ||
| 149 | void (*HFC_outb)(struct hfc_multi *hc, u_char reg, | ||
| 150 | u_char val); | ||
| 151 | void (*HFC_outb_nodebug)(struct hfc_multi *hc, u_char reg, | ||
| 152 | u_char val); | ||
| 153 | u_char (*HFC_inb)(struct hfc_multi *hc, u_char reg); | ||
| 154 | u_char (*HFC_inb_nodebug)(struct hfc_multi *hc, u_char reg); | ||
| 155 | u_short (*HFC_inw)(struct hfc_multi *hc, u_char reg); | ||
| 156 | u_short (*HFC_inw_nodebug)(struct hfc_multi *hc, u_char reg); | ||
| 157 | void (*HFC_wait)(struct hfc_multi *hc); | ||
| 158 | void (*HFC_wait_nodebug)(struct hfc_multi *hc); | ||
| 159 | #endif | ||
| 160 | void (*read_fifo)(struct hfc_multi *hc, u_char *data, | ||
| 161 | int len); | ||
| 162 | void (*write_fifo)(struct hfc_multi *hc, u_char *data, | ||
| 163 | int len); | ||
| 164 | u_long pci_origmembase, plx_origmembase, dsp_origmembase; | ||
| 165 | u_char *pci_membase; /* PCI memory (MUST BE BYTE POINTER) */ | ||
| 166 | u_char *plx_membase; /* PLX memory */ | ||
| 167 | u_char *dsp_membase; /* DSP on PLX */ | ||
| 168 | u_long pci_iobase; /* PCI IO */ | ||
| 169 | struct hfcm_hw hw; /* remember data of write-only-registers */ | ||
| 170 | |||
| 171 | u_long chip; /* chip configuration */ | ||
| 172 | int masterclk; /* port that provides master clock -1=off */ | ||
| 173 | int dtmf; /* flag that dtmf is currently in process */ | ||
| 174 | int Flen; /* F-buffer size */ | ||
| 175 | int Zlen; /* Z-buffer size (must be int for calculation)*/ | ||
| 176 | int max_trans; /* maximum transparent fifo fill */ | ||
| 177 | int Zmin; /* Z-buffer offset */ | ||
| 178 | int DTMFbase; /* base address of DTMF coefficients */ | ||
| 179 | |||
| 180 | u_int slots; /* number of PCM slots */ | ||
| 181 | u_int leds; /* type of leds */ | ||
| 182 | u_int ledcount; /* used to animate leds */ | ||
| 183 | u_long ledstate; /* save last state of leds */ | ||
| 184 | int opticalsupport; /* has the e1 board */ | ||
| 185 | /* an optical Interface */ | ||
| 186 | int dslot; /* channel # of d-channel (E1) default 16 */ | ||
| 187 | |||
| 188 | u_long wdcount; /* every 500 ms we need to */ | ||
| 189 | /* send the watchdog a signal */ | ||
| 190 | u_char wdbyte; /* watchdog toggle byte */ | ||
| 191 | u_int activity[8]; /* if there is any action on this */ | ||
| 192 | /* port (will be cleared after */ | ||
| 193 | /* showing led-states) */ | ||
| 194 | int e1_state; /* keep track of last state */ | ||
| 195 | int e1_getclock; /* if sync is retrieved from interface */ | ||
| 196 | int syncronized; /* keep track of existing sync interface */ | ||
| 197 | int e1_resync; /* resync jobs */ | ||
| 198 | |||
| 199 | spinlock_t lock; /* the lock */ | ||
| 200 | |||
| 201 | /* | ||
| 202 | * the channel index is counted from 0, regardless where the channel | ||
| 203 | * is located on the hfc-channel. | ||
| 204 | * the bch->channel is equvalent to the hfc-channel | ||
| 205 | */ | ||
| 206 | struct hfc_chan chan[32]; | ||
| 207 | u_char created[8]; /* what port is created */ | ||
| 208 | signed char slot_owner[256]; /* owner channel of slot */ | ||
| 209 | }; | ||
| 210 | |||
| 211 | /* PLX GPIOs */ | ||
| 212 | #define PLX_GPIO4_DIR_BIT 13 | ||
| 213 | #define PLX_GPIO4_BIT 14 | ||
| 214 | #define PLX_GPIO5_DIR_BIT 16 | ||
| 215 | #define PLX_GPIO5_BIT 17 | ||
| 216 | #define PLX_GPIO6_DIR_BIT 19 | ||
| 217 | #define PLX_GPIO6_BIT 20 | ||
| 218 | #define PLX_GPIO7_DIR_BIT 22 | ||
| 219 | #define PLX_GPIO7_BIT 23 | ||
| 220 | #define PLX_GPIO8_DIR_BIT 25 | ||
| 221 | #define PLX_GPIO8_BIT 26 | ||
| 222 | |||
| 223 | #define PLX_GPIO4 (1 << PLX_GPIO4_BIT) | ||
| 224 | #define PLX_GPIO5 (1 << PLX_GPIO5_BIT) | ||
| 225 | #define PLX_GPIO6 (1 << PLX_GPIO6_BIT) | ||
| 226 | #define PLX_GPIO7 (1 << PLX_GPIO7_BIT) | ||
| 227 | #define PLX_GPIO8 (1 << PLX_GPIO8_BIT) | ||
| 228 | |||
| 229 | #define PLX_GPIO4_DIR (1 << PLX_GPIO4_DIR_BIT) | ||
| 230 | #define PLX_GPIO5_DIR (1 << PLX_GPIO5_DIR_BIT) | ||
| 231 | #define PLX_GPIO6_DIR (1 << PLX_GPIO6_DIR_BIT) | ||
| 232 | #define PLX_GPIO7_DIR (1 << PLX_GPIO7_DIR_BIT) | ||
| 233 | #define PLX_GPIO8_DIR (1 << PLX_GPIO8_DIR_BIT) | ||
| 234 | |||
| 235 | #define PLX_TERM_ON PLX_GPIO7 | ||
| 236 | #define PLX_SLAVE_EN_N PLX_GPIO5 | ||
| 237 | #define PLX_MASTER_EN PLX_GPIO6 | ||
| 238 | #define PLX_SYNC_O_EN PLX_GPIO4 | ||
| 239 | #define PLX_DSP_RES_N PLX_GPIO8 | ||
| 240 | /* GPIO4..8 Enable & Set to OUT, SLAVE_EN_N = 1 */ | ||
| 241 | #define PLX_GPIOC_INIT (PLX_GPIO4_DIR | PLX_GPIO5_DIR | PLX_GPIO6_DIR \ | ||
| 242 | | PLX_GPIO7_DIR | PLX_GPIO8_DIR | PLX_SLAVE_EN_N) | ||
| 243 | |||
| 244 | /* PLX Interrupt Control/STATUS */ | ||
| 245 | #define PLX_INTCSR_LINTI1_ENABLE 0x01 | ||
| 246 | #define PLX_INTCSR_LINTI1_STATUS 0x04 | ||
| 247 | #define PLX_INTCSR_LINTI2_ENABLE 0x08 | ||
| 248 | #define PLX_INTCSR_LINTI2_STATUS 0x20 | ||
| 249 | #define PLX_INTCSR_PCIINT_ENABLE 0x40 | ||
| 250 | |||
| 251 | /* PLX Registers */ | ||
| 252 | #define PLX_INTCSR 0x4c | ||
| 253 | #define PLX_CNTRL 0x50 | ||
| 254 | #define PLX_GPIOC 0x54 | ||
| 255 | |||
| 256 | |||
| 257 | /* | ||
| 258 | * REGISTER SETTING FOR HFC-4S/8S AND HFC-E1 | ||
| 259 | */ | ||
| 260 | |||
| 261 | /* write only registers */ | ||
| 262 | #define R_CIRM 0x00 | ||
| 263 | #define R_CTRL 0x01 | ||
| 264 | #define R_BRG_PCM_CFG 0x02 | ||
| 265 | #define R_RAM_ADDR0 0x08 | ||
| 266 | #define R_RAM_ADDR1 0x09 | ||
| 267 | #define R_RAM_ADDR2 0x0A | ||
| 268 | #define R_FIRST_FIFO 0x0B | ||
| 269 | #define R_RAM_SZ 0x0C | ||
| 270 | #define R_FIFO_MD 0x0D | ||
| 271 | #define R_INC_RES_FIFO 0x0E | ||
| 272 | #define R_FSM_IDX 0x0F | ||
| 273 | #define R_FIFO 0x0F | ||
| 274 | #define R_SLOT 0x10 | ||
| 275 | #define R_IRQMSK_MISC 0x11 | ||
| 276 | #define R_SCI_MSK 0x12 | ||
| 277 | #define R_IRQ_CTRL 0x13 | ||
| 278 | #define R_PCM_MD0 0x14 | ||
| 279 | #define R_PCM_MD1 0x15 | ||
| 280 | #define R_PCM_MD2 0x15 | ||
| 281 | #define R_SH0H 0x15 | ||
| 282 | #define R_SH1H 0x15 | ||
| 283 | #define R_SH0L 0x15 | ||
| 284 | #define R_SH1L 0x15 | ||
| 285 | #define R_SL_SEL0 0x15 | ||
| 286 | #define R_SL_SEL1 0x15 | ||
| 287 | #define R_SL_SEL2 0x15 | ||
| 288 | #define R_SL_SEL3 0x15 | ||
| 289 | #define R_SL_SEL4 0x15 | ||
| 290 | #define R_SL_SEL5 0x15 | ||
| 291 | #define R_SL_SEL6 0x15 | ||
| 292 | #define R_SL_SEL7 0x15 | ||
| 293 | #define R_ST_SEL 0x16 | ||
| 294 | #define R_ST_SYNC 0x17 | ||
| 295 | #define R_CONF_EN 0x18 | ||
| 296 | #define R_TI_WD 0x1A | ||
| 297 | #define R_BERT_WD_MD 0x1B | ||
| 298 | #define R_DTMF 0x1C | ||
| 299 | #define R_DTMF_N 0x1D | ||
| 300 | #define R_E1_WR_STA 0x20 | ||
| 301 | #define R_E1_RD_STA 0x20 | ||
| 302 | #define R_LOS0 0x22 | ||
| 303 | #define R_LOS1 0x23 | ||
| 304 | #define R_RX0 0x24 | ||
| 305 | #define R_RX_FR0 0x25 | ||
| 306 | #define R_RX_FR1 0x26 | ||
| 307 | #define R_TX0 0x28 | ||
| 308 | #define R_TX1 0x29 | ||
| 309 | #define R_TX_FR0 0x2C | ||
| 310 | |||
| 311 | #define R_TX_FR1 0x2D | ||
| 312 | #define R_TX_FR2 0x2E | ||
| 313 | #define R_JATT_ATT 0x2F /* undocumented */ | ||
| 314 | #define A_ST_RD_STATE 0x30 | ||
| 315 | #define A_ST_WR_STATE 0x30 | ||
| 316 | #define R_RX_OFF 0x30 | ||
| 317 | #define A_ST_CTRL0 0x31 | ||
| 318 | #define R_SYNC_OUT 0x31 | ||
| 319 | #define A_ST_CTRL1 0x32 | ||
| 320 | #define A_ST_CTRL2 0x33 | ||
| 321 | #define A_ST_SQ_WR 0x34 | ||
| 322 | #define R_TX_OFF 0x34 | ||
| 323 | #define R_SYNC_CTRL 0x35 | ||
| 324 | #define A_ST_CLK_DLY 0x37 | ||
| 325 | #define R_PWM0 0x38 | ||
| 326 | #define R_PWM1 0x39 | ||
| 327 | #define A_ST_B1_TX 0x3C | ||
| 328 | #define A_ST_B2_TX 0x3D | ||
| 329 | #define A_ST_D_TX 0x3E | ||
| 330 | #define R_GPIO_OUT0 0x40 | ||
| 331 | #define R_GPIO_OUT1 0x41 | ||
| 332 | #define R_GPIO_EN0 0x42 | ||
| 333 | #define R_GPIO_EN1 0x43 | ||
| 334 | #define R_GPIO_SEL 0x44 | ||
| 335 | #define R_BRG_CTRL 0x45 | ||
| 336 | #define R_PWM_MD 0x46 | ||
| 337 | #define R_BRG_MD 0x47 | ||
| 338 | #define R_BRG_TIM0 0x48 | ||
| 339 | #define R_BRG_TIM1 0x49 | ||
| 340 | #define R_BRG_TIM2 0x4A | ||
| 341 | #define R_BRG_TIM3 0x4B | ||
| 342 | #define R_BRG_TIM_SEL01 0x4C | ||
| 343 | #define R_BRG_TIM_SEL23 0x4D | ||
| 344 | #define R_BRG_TIM_SEL45 0x4E | ||
| 345 | #define R_BRG_TIM_SEL67 0x4F | ||
| 346 | #define A_SL_CFG 0xD0 | ||
| 347 | #define A_CONF 0xD1 | ||
| 348 | #define A_CH_MSK 0xF4 | ||
| 349 | #define A_CON_HDLC 0xFA | ||
| 350 | #define A_SUBCH_CFG 0xFB | ||
| 351 | #define A_CHANNEL 0xFC | ||
| 352 | #define A_FIFO_SEQ 0xFD | ||
| 353 | #define A_IRQ_MSK 0xFF | ||
| 354 | |||
| 355 | /* read only registers */ | ||
| 356 | #define A_Z12 0x04 | ||
| 357 | #define A_Z1L 0x04 | ||
| 358 | #define A_Z1 0x04 | ||
| 359 | #define A_Z1H 0x05 | ||
| 360 | #define A_Z2L 0x06 | ||
| 361 | #define A_Z2 0x06 | ||
| 362 | #define A_Z2H 0x07 | ||
| 363 | #define A_F1 0x0C | ||
| 364 | #define A_F12 0x0C | ||
| 365 | #define A_F2 0x0D | ||
| 366 | #define R_IRQ_OVIEW 0x10 | ||
| 367 | #define R_IRQ_MISC 0x11 | ||
| 368 | #define R_IRQ_STATECH 0x12 | ||
| 369 | #define R_CONF_OFLOW 0x14 | ||
| 370 | #define R_RAM_USE 0x15 | ||
| 371 | #define R_CHIP_ID 0x16 | ||
| 372 | #define R_BERT_STA 0x17 | ||
| 373 | #define R_F0_CNTL 0x18 | ||
| 374 | #define R_F0_CNTH 0x19 | ||
| 375 | #define R_BERT_EC 0x1A | ||
| 376 | #define R_BERT_ECL 0x1A | ||
| 377 | #define R_BERT_ECH 0x1B | ||
| 378 | #define R_STATUS 0x1C | ||
| 379 | #define R_CHIP_RV 0x1F | ||
| 380 | #define R_STATE 0x20 | ||
| 381 | #define R_SYNC_STA 0x24 | ||
| 382 | #define R_RX_SL0_0 0x25 | ||
| 383 | #define R_RX_SL0_1 0x26 | ||
| 384 | #define R_RX_SL0_2 0x27 | ||
| 385 | #define R_JATT_DIR 0x2b /* undocumented */ | ||
| 386 | #define R_SLIP 0x2c | ||
| 387 | #define A_ST_RD_STA 0x30 | ||
| 388 | #define R_FAS_EC 0x30 | ||
| 389 | #define R_FAS_ECL 0x30 | ||
| 390 | #define R_FAS_ECH 0x31 | ||
| 391 | #define R_VIO_EC 0x32 | ||
| 392 | #define R_VIO_ECL 0x32 | ||
| 393 | #define R_VIO_ECH 0x33 | ||
| 394 | #define A_ST_SQ_RD 0x34 | ||
| 395 | #define R_CRC_EC 0x34 | ||
| 396 | #define R_CRC_ECL 0x34 | ||
| 397 | #define R_CRC_ECH 0x35 | ||
| 398 | #define R_E_EC 0x36 | ||
| 399 | #define R_E_ECL 0x36 | ||
| 400 | #define R_E_ECH 0x37 | ||
| 401 | #define R_SA6_SA13_EC 0x38 | ||
| 402 | #define R_SA6_SA13_ECL 0x38 | ||
| 403 | #define R_SA6_SA13_ECH 0x39 | ||
| 404 | #define R_SA6_SA23_EC 0x3A | ||
| 405 | #define R_SA6_SA23_ECL 0x3A | ||
| 406 | #define R_SA6_SA23_ECH 0x3B | ||
| 407 | #define A_ST_B1_RX 0x3C | ||
| 408 | #define A_ST_B2_RX 0x3D | ||
| 409 | #define A_ST_D_RX 0x3E | ||
| 410 | #define A_ST_E_RX 0x3F | ||
| 411 | #define R_GPIO_IN0 0x40 | ||
| 412 | #define R_GPIO_IN1 0x41 | ||
| 413 | #define R_GPI_IN0 0x44 | ||
| 414 | #define R_GPI_IN1 0x45 | ||
| 415 | #define R_GPI_IN2 0x46 | ||
| 416 | #define R_GPI_IN3 0x47 | ||
| 417 | #define R_INT_DATA 0x88 | ||
| 418 | #define R_IRQ_FIFO_BL0 0xC8 | ||
| 419 | #define R_IRQ_FIFO_BL1 0xC9 | ||
| 420 | #define R_IRQ_FIFO_BL2 0xCA | ||
| 421 | #define R_IRQ_FIFO_BL3 0xCB | ||
| 422 | #define R_IRQ_FIFO_BL4 0xCC | ||
| 423 | #define R_IRQ_FIFO_BL5 0xCD | ||
| 424 | #define R_IRQ_FIFO_BL6 0xCE | ||
| 425 | #define R_IRQ_FIFO_BL7 0xCF | ||
| 426 | |||
| 427 | /* read and write registers */ | ||
| 428 | #define A_FIFO_DATA0 0x80 | ||
| 429 | #define A_FIFO_DATA1 0x80 | ||
| 430 | #define A_FIFO_DATA2 0x80 | ||
| 431 | #define A_FIFO_DATA0_NOINC 0x84 | ||
| 432 | #define A_FIFO_DATA1_NOINC 0x84 | ||
| 433 | #define A_FIFO_DATA2_NOINC 0x84 | ||
| 434 | #define R_RAM_DATA 0xC0 | ||
| 435 | |||
| 436 | |||
| 437 | /* | ||
| 438 | * BIT SETTING FOR HFC-4S/8S AND HFC-E1 | ||
| 439 | */ | ||
| 440 | |||
| 441 | /* chapter 2: universal bus interface */ | ||
| 442 | /* R_CIRM */ | ||
| 443 | #define V_IRQ_SEL 0x01 | ||
| 444 | #define V_SRES 0x08 | ||
| 445 | #define V_HFCRES 0x10 | ||
| 446 | #define V_PCMRES 0x20 | ||
| 447 | #define V_STRES 0x40 | ||
| 448 | #define V_ETRES 0x40 | ||
| 449 | #define V_RLD_EPR 0x80 | ||
| 450 | /* R_CTRL */ | ||
| 451 | #define V_FIFO_LPRIO 0x02 | ||
| 452 | #define V_SLOW_RD 0x04 | ||
| 453 | #define V_EXT_RAM 0x08 | ||
| 454 | #define V_CLK_OFF 0x20 | ||
| 455 | #define V_ST_CLK 0x40 | ||
| 456 | /* R_RAM_ADDR0 */ | ||
| 457 | #define V_RAM_ADDR2 0x01 | ||
| 458 | #define V_ADDR_RES 0x40 | ||
| 459 | #define V_ADDR_INC 0x80 | ||
| 460 | /* R_RAM_SZ */ | ||
| 461 | #define V_RAM_SZ 0x01 | ||
| 462 | #define V_PWM0_16KHZ 0x10 | ||
| 463 | #define V_PWM1_16KHZ 0x20 | ||
| 464 | #define V_FZ_MD 0x80 | ||
| 465 | /* R_CHIP_ID */ | ||
| 466 | #define V_PNP_IRQ 0x01 | ||
| 467 | #define V_CHIP_ID 0x10 | ||
| 468 | |||
| 469 | /* chapter 3: data flow */ | ||
| 470 | /* R_FIRST_FIFO */ | ||
| 471 | #define V_FIRST_FIRO_DIR 0x01 | ||
| 472 | #define V_FIRST_FIFO_NUM 0x02 | ||
| 473 | /* R_FIFO_MD */ | ||
| 474 | #define V_FIFO_MD 0x01 | ||
| 475 | #define V_CSM_MD 0x04 | ||
| 476 | #define V_FSM_MD 0x08 | ||
| 477 | #define V_FIFO_SZ 0x10 | ||
| 478 | /* R_FIFO */ | ||
| 479 | #define V_FIFO_DIR 0x01 | ||
| 480 | #define V_FIFO_NUM 0x02 | ||
| 481 | #define V_REV 0x80 | ||
| 482 | /* R_SLOT */ | ||
| 483 | #define V_SL_DIR 0x01 | ||
| 484 | #define V_SL_NUM 0x02 | ||
| 485 | /* A_SL_CFG */ | ||
| 486 | #define V_CH_DIR 0x01 | ||
| 487 | #define V_CH_SEL 0x02 | ||
| 488 | #define V_ROUTING 0x40 | ||
| 489 | /* A_CON_HDLC */ | ||
| 490 | #define V_IFF 0x01 | ||
| 491 | #define V_HDLC_TRP 0x02 | ||
| 492 | #define V_TRP_IRQ 0x04 | ||
| 493 | #define V_DATA_FLOW 0x20 | ||
| 494 | /* A_SUBCH_CFG */ | ||
| 495 | #define V_BIT_CNT 0x01 | ||
| 496 | #define V_START_BIT 0x08 | ||
| 497 | #define V_LOOP_FIFO 0x40 | ||
| 498 | #define V_INV_DATA 0x80 | ||
| 499 | /* A_CHANNEL */ | ||
| 500 | #define V_CH_DIR0 0x01 | ||
| 501 | #define V_CH_NUM0 0x02 | ||
| 502 | /* A_FIFO_SEQ */ | ||
| 503 | #define V_NEXT_FIFO_DIR 0x01 | ||
| 504 | #define V_NEXT_FIFO_NUM 0x02 | ||
| 505 | #define V_SEQ_END 0x40 | ||
| 506 | |||
| 507 | /* chapter 4: FIFO handling and HDLC controller */ | ||
| 508 | /* R_INC_RES_FIFO */ | ||
| 509 | #define V_INC_F 0x01 | ||
| 510 | #define V_RES_F 0x02 | ||
| 511 | #define V_RES_LOST 0x04 | ||
| 512 | |||
| 513 | /* chapter 5: S/T interface */ | ||
| 514 | /* R_SCI_MSK */ | ||
| 515 | #define V_SCI_MSK_ST0 0x01 | ||
| 516 | #define V_SCI_MSK_ST1 0x02 | ||
| 517 | #define V_SCI_MSK_ST2 0x04 | ||
| 518 | #define V_SCI_MSK_ST3 0x08 | ||
| 519 | #define V_SCI_MSK_ST4 0x10 | ||
| 520 | #define V_SCI_MSK_ST5 0x20 | ||
| 521 | #define V_SCI_MSK_ST6 0x40 | ||
| 522 | #define V_SCI_MSK_ST7 0x80 | ||
| 523 | /* R_ST_SEL */ | ||
| 524 | #define V_ST_SEL 0x01 | ||
| 525 | #define V_MULT_ST 0x08 | ||
| 526 | /* R_ST_SYNC */ | ||
| 527 | #define V_SYNC_SEL 0x01 | ||
| 528 | #define V_AUTO_SYNC 0x08 | ||
| 529 | /* A_ST_WR_STA */ | ||
| 530 | #define V_ST_SET_STA 0x01 | ||
| 531 | #define V_ST_LD_STA 0x10 | ||
| 532 | #define V_ST_ACT 0x20 | ||
| 533 | #define V_SET_G2_G3 0x80 | ||
| 534 | /* A_ST_CTRL0 */ | ||
| 535 | #define V_B1_EN 0x01 | ||
| 536 | #define V_B2_EN 0x02 | ||
| 537 | #define V_ST_MD 0x04 | ||
| 538 | #define V_D_PRIO 0x08 | ||
| 539 | #define V_SQ_EN 0x10 | ||
| 540 | #define V_96KHZ 0x20 | ||
| 541 | #define V_TX_LI 0x40 | ||
| 542 | #define V_ST_STOP 0x80 | ||
| 543 | /* A_ST_CTRL1 */ | ||
| 544 | #define V_G2_G3_EN 0x01 | ||
| 545 | #define V_D_HI 0x04 | ||
| 546 | #define V_E_IGNO 0x08 | ||
| 547 | #define V_E_LO 0x10 | ||
| 548 | #define V_B12_SWAP 0x80 | ||
| 549 | /* A_ST_CTRL2 */ | ||
| 550 | #define V_B1_RX_EN 0x01 | ||
| 551 | #define V_B2_RX_EN 0x02 | ||
| 552 | #define V_ST_TRIS 0x40 | ||
| 553 | /* A_ST_CLK_DLY */ | ||
| 554 | #define V_ST_CK_DLY 0x01 | ||
| 555 | #define V_ST_SMPL 0x10 | ||
| 556 | /* A_ST_D_TX */ | ||
| 557 | #define V_ST_D_TX 0x40 | ||
| 558 | /* R_IRQ_STATECH */ | ||
| 559 | #define V_SCI_ST0 0x01 | ||
| 560 | #define V_SCI_ST1 0x02 | ||
| 561 | #define V_SCI_ST2 0x04 | ||
| 562 | #define V_SCI_ST3 0x08 | ||
| 563 | #define V_SCI_ST4 0x10 | ||
| 564 | #define V_SCI_ST5 0x20 | ||
| 565 | #define V_SCI_ST6 0x40 | ||
| 566 | #define V_SCI_ST7 0x80 | ||
| 567 | /* A_ST_RD_STA */ | ||
| 568 | #define V_ST_STA 0x01 | ||
| 569 | #define V_FR_SYNC_ST 0x10 | ||
| 570 | #define V_TI2_EXP 0x20 | ||
| 571 | #define V_INFO0 0x40 | ||
| 572 | #define V_G2_G3 0x80 | ||
| 573 | /* A_ST_SQ_RD */ | ||
| 574 | #define V_ST_SQ 0x01 | ||
| 575 | #define V_MF_RX_RDY 0x10 | ||
| 576 | #define V_MF_TX_RDY 0x80 | ||
| 577 | /* A_ST_D_RX */ | ||
| 578 | #define V_ST_D_RX 0x40 | ||
| 579 | /* A_ST_E_RX */ | ||
| 580 | #define V_ST_E_RX 0x40 | ||
| 581 | |||
| 582 | /* chapter 5: E1 interface */ | ||
| 583 | /* R_E1_WR_STA */ | ||
| 584 | /* R_E1_RD_STA */ | ||
| 585 | #define V_E1_SET_STA 0x01 | ||
| 586 | #define V_E1_LD_STA 0x10 | ||
| 587 | /* R_RX0 */ | ||
| 588 | #define V_RX_CODE 0x01 | ||
| 589 | #define V_RX_FBAUD 0x04 | ||
| 590 | #define V_RX_CMI 0x08 | ||
| 591 | #define V_RX_INV_CMI 0x10 | ||
| 592 | #define V_RX_INV_CLK 0x20 | ||
| 593 | #define V_RX_INV_DATA 0x40 | ||
| 594 | #define V_AIS_ITU 0x80 | ||
| 595 | /* R_RX_FR0 */ | ||
| 596 | #define V_NO_INSYNC 0x01 | ||
| 597 | #define V_AUTO_RESYNC 0x02 | ||
| 598 | #define V_AUTO_RECO 0x04 | ||
| 599 | #define V_SWORD_COND 0x08 | ||
| 600 | #define V_SYNC_LOSS 0x10 | ||
| 601 | #define V_XCRC_SYNC 0x20 | ||
| 602 | #define V_MF_RESYNC 0x40 | ||
| 603 | #define V_RESYNC 0x80 | ||
| 604 | /* R_RX_FR1 */ | ||
| 605 | #define V_RX_MF 0x01 | ||
| 606 | #define V_RX_MF_SYNC 0x02 | ||
| 607 | #define V_RX_SL0_RAM 0x04 | ||
| 608 | #define V_ERR_SIM 0x20 | ||
| 609 | #define V_RES_NMF 0x40 | ||
| 610 | /* R_TX0 */ | ||
| 611 | #define V_TX_CODE 0x01 | ||
| 612 | #define V_TX_FBAUD 0x04 | ||
| 613 | #define V_TX_CMI_CODE 0x08 | ||
| 614 | #define V_TX_INV_CMI_CODE 0x10 | ||
| 615 | #define V_TX_INV_CLK 0x20 | ||
| 616 | #define V_TX_INV_DATA 0x40 | ||
| 617 | #define V_OUT_EN 0x80 | ||
| 618 | /* R_TX1 */ | ||
| 619 | #define V_INV_CLK 0x01 | ||
| 620 | #define V_EXCHG_DATA_LI 0x02 | ||
| 621 | #define V_AIS_OUT 0x04 | ||
| 622 | #define V_ATX 0x20 | ||
| 623 | #define V_NTRI 0x40 | ||
| 624 | #define V_AUTO_ERR_RES 0x80 | ||
| 625 | /* R_TX_FR0 */ | ||
| 626 | #define V_TRP_FAS 0x01 | ||
| 627 | #define V_TRP_NFAS 0x02 | ||
| 628 | #define V_TRP_RAL 0x04 | ||
| 629 | #define V_TRP_SA 0x08 | ||
| 630 | /* R_TX_FR1 */ | ||
| 631 | #define V_TX_FAS 0x01 | ||
| 632 | #define V_TX_NFAS 0x02 | ||
| 633 | #define V_TX_RAL 0x04 | ||
| 634 | #define V_TX_SA 0x08 | ||
| 635 | /* R_TX_FR2 */ | ||
| 636 | #define V_TX_MF 0x01 | ||
| 637 | #define V_TRP_SL0 0x02 | ||
| 638 | #define V_TX_SL0_RAM 0x04 | ||
| 639 | #define V_TX_E 0x10 | ||
| 640 | #define V_NEG_E 0x20 | ||
| 641 | #define V_XS12_ON 0x40 | ||
| 642 | #define V_XS15_ON 0x80 | ||
| 643 | /* R_RX_OFF */ | ||
| 644 | #define V_RX_SZ 0x01 | ||
| 645 | #define V_RX_INIT 0x04 | ||
| 646 | /* R_SYNC_OUT */ | ||
| 647 | #define V_SYNC_E1_RX 0x01 | ||
| 648 | #define V_IPATS0 0x20 | ||
| 649 | #define V_IPATS1 0x40 | ||
| 650 | #define V_IPATS2 0x80 | ||
| 651 | /* R_TX_OFF */ | ||
| 652 | #define V_TX_SZ 0x01 | ||
| 653 | #define V_TX_INIT 0x04 | ||
| 654 | /* R_SYNC_CTRL */ | ||
| 655 | #define V_EXT_CLK_SYNC 0x01 | ||
| 656 | #define V_SYNC_OFFS 0x02 | ||
| 657 | #define V_PCM_SYNC 0x04 | ||
| 658 | #define V_NEG_CLK 0x08 | ||
| 659 | #define V_HCLK 0x10 | ||
| 660 | /* | ||
| 661 | #define V_JATT_AUTO_DEL 0x20 | ||
| 662 | #define V_JATT_AUTO 0x40 | ||
| 663 | */ | ||
| 664 | #define V_JATT_OFF 0x80 | ||
| 665 | /* R_STATE */ | ||
| 666 | #define V_E1_STA 0x01 | ||
| 667 | #define V_ALT_FR_RX 0x40 | ||
| 668 | #define V_ALT_FR_TX 0x80 | ||
| 669 | /* R_SYNC_STA */ | ||
| 670 | #define V_RX_STA 0x01 | ||
| 671 | #define V_FR_SYNC_E1 0x04 | ||
| 672 | #define V_SIG_LOS 0x08 | ||
| 673 | #define V_MFA_STA 0x10 | ||
| 674 | #define V_AIS 0x40 | ||
| 675 | #define V_NO_MF_SYNC 0x80 | ||
| 676 | /* R_RX_SL0_0 */ | ||
| 677 | #define V_SI_FAS 0x01 | ||
| 678 | #define V_SI_NFAS 0x02 | ||
| 679 | #define V_A 0x04 | ||
| 680 | #define V_CRC_OK 0x08 | ||
| 681 | #define V_TX_E1 0x10 | ||
| 682 | #define V_TX_E2 0x20 | ||
| 683 | #define V_RX_E1 0x40 | ||
| 684 | #define V_RX_E2 0x80 | ||
| 685 | /* R_SLIP */ | ||
| 686 | #define V_SLIP_RX 0x01 | ||
| 687 | #define V_FOSLIP_RX 0x08 | ||
| 688 | #define V_SLIP_TX 0x10 | ||
| 689 | #define V_FOSLIP_TX 0x80 | ||
| 690 | |||
| 691 | /* chapter 6: PCM interface */ | ||
| 692 | /* R_PCM_MD0 */ | ||
| 693 | #define V_PCM_MD 0x01 | ||
| 694 | #define V_C4_POL 0x02 | ||
| 695 | #define V_F0_NEG 0x04 | ||
| 696 | #define V_F0_LEN 0x08 | ||
| 697 | #define V_PCM_ADDR 0x10 | ||
| 698 | /* R_SL_SEL0 */ | ||
| 699 | #define V_SL_SEL0 0x01 | ||
| 700 | #define V_SH_SEL0 0x80 | ||
| 701 | /* R_SL_SEL1 */ | ||
| 702 | #define V_SL_SEL1 0x01 | ||
| 703 | #define V_SH_SEL1 0x80 | ||
| 704 | /* R_SL_SEL2 */ | ||
| 705 | #define V_SL_SEL2 0x01 | ||
| 706 | #define V_SH_SEL2 0x80 | ||
| 707 | /* R_SL_SEL3 */ | ||
| 708 | #define V_SL_SEL3 0x01 | ||
| 709 | #define V_SH_SEL3 0x80 | ||
| 710 | /* R_SL_SEL4 */ | ||
| 711 | #define V_SL_SEL4 0x01 | ||
| 712 | #define V_SH_SEL4 0x80 | ||
| 713 | /* R_SL_SEL5 */ | ||
| 714 | #define V_SL_SEL5 0x01 | ||
| 715 | #define V_SH_SEL5 0x80 | ||
| 716 | /* R_SL_SEL6 */ | ||
| 717 | #define V_SL_SEL6 0x01 | ||
| 718 | #define V_SH_SEL6 0x80 | ||
| 719 | /* R_SL_SEL7 */ | ||
| 720 | #define V_SL_SEL7 0x01 | ||
| 721 | #define V_SH_SEL7 0x80 | ||
| 722 | /* R_PCM_MD1 */ | ||
| 723 | #define V_ODEC_CON 0x01 | ||
| 724 | #define V_PLL_ADJ 0x04 | ||
| 725 | #define V_PCM_DR 0x10 | ||
| 726 | #define V_PCM_LOOP 0x40 | ||
| 727 | /* R_PCM_MD2 */ | ||
| 728 | #define V_SYNC_PLL 0x02 | ||
| 729 | #define V_SYNC_SRC 0x04 | ||
| 730 | #define V_SYNC_OUT 0x08 | ||
| 731 | #define V_ICR_FR_TIME 0x40 | ||
| 732 | #define V_EN_PLL 0x80 | ||
| 733 | |||
| 734 | /* chapter 7: pulse width modulation */ | ||
| 735 | /* R_PWM_MD */ | ||
| 736 | #define V_EXT_IRQ_EN 0x08 | ||
| 737 | #define V_PWM0_MD 0x10 | ||
| 738 | #define V_PWM1_MD 0x40 | ||
| 739 | |||
| 740 | /* chapter 8: multiparty audio conferences */ | ||
| 741 | /* R_CONF_EN */ | ||
| 742 | #define V_CONF_EN 0x01 | ||
| 743 | #define V_ULAW 0x80 | ||
| 744 | /* A_CONF */ | ||
| 745 | #define V_CONF_NUM 0x01 | ||
| 746 | #define V_NOISE_SUPPR 0x08 | ||
| 747 | #define V_ATT_LEV 0x20 | ||
| 748 | #define V_CONF_SL 0x80 | ||
| 749 | /* R_CONF_OFLOW */ | ||
| 750 | #define V_CONF_OFLOW0 0x01 | ||
| 751 | #define V_CONF_OFLOW1 0x02 | ||
| 752 | #define V_CONF_OFLOW2 0x04 | ||
| 753 | #define V_CONF_OFLOW3 0x08 | ||
| 754 | #define V_CONF_OFLOW4 0x10 | ||
| 755 | #define V_CONF_OFLOW5 0x20 | ||
| 756 | #define V_CONF_OFLOW6 0x40 | ||
| 757 | #define V_CONF_OFLOW7 0x80 | ||
| 758 | |||
| 759 | /* chapter 9: DTMF contoller */ | ||
| 760 | /* R_DTMF0 */ | ||
| 761 | #define V_DTMF_EN 0x01 | ||
| 762 | #define V_HARM_SEL 0x02 | ||
| 763 | #define V_DTMF_RX_CH 0x04 | ||
| 764 | #define V_DTMF_STOP 0x08 | ||
| 765 | #define V_CHBL_SEL 0x10 | ||
| 766 | #define V_RST_DTMF 0x40 | ||
| 767 | #define V_ULAW_SEL 0x80 | ||
| 768 | |||
| 769 | /* chapter 10: BERT */ | ||
| 770 | /* R_BERT_WD_MD */ | ||
| 771 | #define V_PAT_SEQ 0x01 | ||
| 772 | #define V_BERT_ERR 0x08 | ||
| 773 | #define V_AUTO_WD_RES 0x20 | ||
| 774 | #define V_WD_RES 0x80 | ||
| 775 | /* R_BERT_STA */ | ||
| 776 | #define V_BERT_SYNC_SRC 0x01 | ||
| 777 | #define V_BERT_SYNC 0x10 | ||
| 778 | #define V_BERT_INV_DATA 0x20 | ||
| 779 | |||
| 780 | /* chapter 11: auxiliary interface */ | ||
| 781 | /* R_BRG_PCM_CFG */ | ||
| 782 | #define V_BRG_EN 0x01 | ||
| 783 | #define V_BRG_MD 0x02 | ||
| 784 | #define V_PCM_CLK 0x20 | ||
| 785 | #define V_ADDR_WRDLY 0x40 | ||
| 786 | /* R_BRG_CTRL */ | ||
| 787 | #define V_BRG_CS 0x01 | ||
| 788 | #define V_BRG_ADDR 0x08 | ||
| 789 | #define V_BRG_CS_SRC 0x80 | ||
| 790 | /* R_BRG_MD */ | ||
| 791 | #define V_BRG_MD0 0x01 | ||
| 792 | #define V_BRG_MD1 0x02 | ||
| 793 | #define V_BRG_MD2 0x04 | ||
| 794 | #define V_BRG_MD3 0x08 | ||
| 795 | #define V_BRG_MD4 0x10 | ||
| 796 | #define V_BRG_MD5 0x20 | ||
| 797 | #define V_BRG_MD6 0x40 | ||
| 798 | #define V_BRG_MD7 0x80 | ||
| 799 | /* R_BRG_TIM0 */ | ||
| 800 | #define V_BRG_TIM0_IDLE 0x01 | ||
| 801 | #define V_BRG_TIM0_CLK 0x10 | ||
| 802 | /* R_BRG_TIM1 */ | ||
| 803 | #define V_BRG_TIM1_IDLE 0x01 | ||
| 804 | #define V_BRG_TIM1_CLK 0x10 | ||
| 805 | /* R_BRG_TIM2 */ | ||
| 806 | #define V_BRG_TIM2_IDLE 0x01 | ||
| 807 | #define V_BRG_TIM2_CLK 0x10 | ||
| 808 | /* R_BRG_TIM3 */ | ||
| 809 | #define V_BRG_TIM3_IDLE 0x01 | ||
| 810 | #define V_BRG_TIM3_CLK 0x10 | ||
| 811 | /* R_BRG_TIM_SEL01 */ | ||
| 812 | #define V_BRG_WR_SEL0 0x01 | ||
| 813 | #define V_BRG_RD_SEL0 0x04 | ||
| 814 | #define V_BRG_WR_SEL1 0x10 | ||
| 815 | #define V_BRG_RD_SEL1 0x40 | ||
| 816 | /* R_BRG_TIM_SEL23 */ | ||
| 817 | #define V_BRG_WR_SEL2 0x01 | ||
| 818 | #define V_BRG_RD_SEL2 0x04 | ||
| 819 | #define V_BRG_WR_SEL3 0x10 | ||
| 820 | #define V_BRG_RD_SEL3 0x40 | ||
| 821 | /* R_BRG_TIM_SEL45 */ | ||
| 822 | #define V_BRG_WR_SEL4 0x01 | ||
| 823 | #define V_BRG_RD_SEL4 0x04 | ||
| 824 | #define V_BRG_WR_SEL5 0x10 | ||
| 825 | #define V_BRG_RD_SEL5 0x40 | ||
| 826 | /* R_BRG_TIM_SEL67 */ | ||
| 827 | #define V_BRG_WR_SEL6 0x01 | ||
| 828 | #define V_BRG_RD_SEL6 0x04 | ||
| 829 | #define V_BRG_WR_SEL7 0x10 | ||
| 830 | #define V_BRG_RD_SEL7 0x40 | ||
| 831 | |||
| 832 | /* chapter 12: clock, reset, interrupt, timer and watchdog */ | ||
| 833 | /* R_IRQMSK_MISC */ | ||
| 834 | #define V_STA_IRQMSK 0x01 | ||
| 835 | #define V_TI_IRQMSK 0x02 | ||
| 836 | #define V_PROC_IRQMSK 0x04 | ||
| 837 | #define V_DTMF_IRQMSK 0x08 | ||
| 838 | #define V_IRQ1S_MSK 0x10 | ||
| 839 | #define V_SA6_IRQMSK 0x20 | ||
| 840 | #define V_RX_EOMF_MSK 0x40 | ||
| 841 | #define V_TX_EOMF_MSK 0x80 | ||
| 842 | /* R_IRQ_CTRL */ | ||
| 843 | #define V_FIFO_IRQ 0x01 | ||
| 844 | #define V_GLOB_IRQ_EN 0x08 | ||
| 845 | #define V_IRQ_POL 0x10 | ||
| 846 | /* R_TI_WD */ | ||
| 847 | #define V_EV_TS 0x01 | ||
| 848 | #define V_WD_TS 0x10 | ||
| 849 | /* A_IRQ_MSK */ | ||
| 850 | #define V_IRQ 0x01 | ||
| 851 | #define V_BERT_EN 0x02 | ||
| 852 | #define V_MIX_IRQ 0x04 | ||
| 853 | /* R_IRQ_OVIEW */ | ||
| 854 | #define V_IRQ_FIFO_BL0 0x01 | ||
| 855 | #define V_IRQ_FIFO_BL1 0x02 | ||
| 856 | #define V_IRQ_FIFO_BL2 0x04 | ||
| 857 | #define V_IRQ_FIFO_BL3 0x08 | ||
| 858 | #define V_IRQ_FIFO_BL4 0x10 | ||
| 859 | #define V_IRQ_FIFO_BL5 0x20 | ||
| 860 | #define V_IRQ_FIFO_BL6 0x40 | ||
| 861 | #define V_IRQ_FIFO_BL7 0x80 | ||
| 862 | /* R_IRQ_MISC */ | ||
| 863 | #define V_STA_IRQ 0x01 | ||
| 864 | #define V_TI_IRQ 0x02 | ||
| 865 | #define V_IRQ_PROC 0x04 | ||
| 866 | #define V_DTMF_IRQ 0x08 | ||
| 867 | #define V_IRQ1S 0x10 | ||
| 868 | #define V_SA6_IRQ 0x20 | ||
| 869 | #define V_RX_EOMF 0x40 | ||
| 870 | #define V_TX_EOMF 0x80 | ||
| 871 | /* R_STATUS */ | ||
| 872 | #define V_BUSY 0x01 | ||
| 873 | #define V_PROC 0x02 | ||
| 874 | #define V_DTMF_STA 0x04 | ||
| 875 | #define V_LOST_STA 0x08 | ||
| 876 | #define V_SYNC_IN 0x10 | ||
| 877 | #define V_EXT_IRQSTA 0x20 | ||
| 878 | #define V_MISC_IRQSTA 0x40 | ||
| 879 | #define V_FR_IRQSTA 0x80 | ||
| 880 | /* R_IRQ_FIFO_BL0 */ | ||
| 881 | #define V_IRQ_FIFO0_TX 0x01 | ||
| 882 | #define V_IRQ_FIFO0_RX 0x02 | ||
| 883 | #define V_IRQ_FIFO1_TX 0x04 | ||
| 884 | #define V_IRQ_FIFO1_RX 0x08 | ||
| 885 | #define V_IRQ_FIFO2_TX 0x10 | ||
| 886 | #define V_IRQ_FIFO2_RX 0x20 | ||
| 887 | #define V_IRQ_FIFO3_TX 0x40 | ||
| 888 | #define V_IRQ_FIFO3_RX 0x80 | ||
| 889 | /* R_IRQ_FIFO_BL1 */ | ||
| 890 | #define V_IRQ_FIFO4_TX 0x01 | ||
| 891 | #define V_IRQ_FIFO4_RX 0x02 | ||
| 892 | #define V_IRQ_FIFO5_TX 0x04 | ||
| 893 | #define V_IRQ_FIFO5_RX 0x08 | ||
| 894 | #define V_IRQ_FIFO6_TX 0x10 | ||
| 895 | #define V_IRQ_FIFO6_RX 0x20 | ||
| 896 | #define V_IRQ_FIFO7_TX 0x40 | ||
| 897 | #define V_IRQ_FIFO7_RX 0x80 | ||
| 898 | /* R_IRQ_FIFO_BL2 */ | ||
| 899 | #define V_IRQ_FIFO8_TX 0x01 | ||
| 900 | #define V_IRQ_FIFO8_RX 0x02 | ||
| 901 | #define V_IRQ_FIFO9_TX 0x04 | ||
| 902 | #define V_IRQ_FIFO9_RX 0x08 | ||
| 903 | #define V_IRQ_FIFO10_TX 0x10 | ||
| 904 | #define V_IRQ_FIFO10_RX 0x20 | ||
| 905 | #define V_IRQ_FIFO11_TX 0x40 | ||
| 906 | #define V_IRQ_FIFO11_RX 0x80 | ||
| 907 | /* R_IRQ_FIFO_BL3 */ | ||
| 908 | #define V_IRQ_FIFO12_TX 0x01 | ||
| 909 | #define V_IRQ_FIFO12_RX 0x02 | ||
| 910 | #define V_IRQ_FIFO13_TX 0x04 | ||
| 911 | #define V_IRQ_FIFO13_RX 0x08 | ||
| 912 | #define V_IRQ_FIFO14_TX 0x10 | ||
| 913 | #define V_IRQ_FIFO14_RX 0x20 | ||
| 914 | #define V_IRQ_FIFO15_TX 0x40 | ||
| 915 | #define V_IRQ_FIFO15_RX 0x80 | ||
| 916 | /* R_IRQ_FIFO_BL4 */ | ||
| 917 | #define V_IRQ_FIFO16_TX 0x01 | ||
| 918 | #define V_IRQ_FIFO16_RX 0x02 | ||
| 919 | #define V_IRQ_FIFO17_TX 0x04 | ||
| 920 | #define V_IRQ_FIFO17_RX 0x08 | ||
| 921 | #define V_IRQ_FIFO18_TX 0x10 | ||
| 922 | #define V_IRQ_FIFO18_RX 0x20 | ||
| 923 | #define V_IRQ_FIFO19_TX 0x40 | ||
| 924 | #define V_IRQ_FIFO19_RX 0x80 | ||
| 925 | /* R_IRQ_FIFO_BL5 */ | ||
| 926 | #define V_IRQ_FIFO20_TX 0x01 | ||
| 927 | #define V_IRQ_FIFO20_RX 0x02 | ||
| 928 | #define V_IRQ_FIFO21_TX 0x04 | ||
| 929 | #define V_IRQ_FIFO21_RX 0x08 | ||
| 930 | #define V_IRQ_FIFO22_TX 0x10 | ||
| 931 | #define V_IRQ_FIFO22_RX 0x20 | ||
| 932 | #define V_IRQ_FIFO23_TX 0x40 | ||
| 933 | #define V_IRQ_FIFO23_RX 0x80 | ||
| 934 | /* R_IRQ_FIFO_BL6 */ | ||
| 935 | #define V_IRQ_FIFO24_TX 0x01 | ||
| 936 | #define V_IRQ_FIFO24_RX 0x02 | ||
| 937 | #define V_IRQ_FIFO25_TX 0x04 | ||
| 938 | #define V_IRQ_FIFO25_RX 0x08 | ||
| 939 | #define V_IRQ_FIFO26_TX 0x10 | ||
| 940 | #define V_IRQ_FIFO26_RX 0x20 | ||
| 941 | #define V_IRQ_FIFO27_TX 0x40 | ||
| 942 | #define V_IRQ_FIFO27_RX 0x80 | ||
| 943 | /* R_IRQ_FIFO_BL7 */ | ||
| 944 | #define V_IRQ_FIFO28_TX 0x01 | ||
| 945 | #define V_IRQ_FIFO28_RX 0x02 | ||
| 946 | #define V_IRQ_FIFO29_TX 0x04 | ||
| 947 | #define V_IRQ_FIFO29_RX 0x08 | ||
| 948 | #define V_IRQ_FIFO30_TX 0x10 | ||
| 949 | #define V_IRQ_FIFO30_RX 0x20 | ||
| 950 | #define V_IRQ_FIFO31_TX 0x40 | ||
| 951 | #define V_IRQ_FIFO31_RX 0x80 | ||
| 952 | |||
| 953 | /* chapter 13: general purpose I/O pins (GPIO) and input pins (GPI) */ | ||
| 954 | /* R_GPIO_OUT0 */ | ||
| 955 | #define V_GPIO_OUT0 0x01 | ||
| 956 | #define V_GPIO_OUT1 0x02 | ||
| 957 | #define V_GPIO_OUT2 0x04 | ||
| 958 | #define V_GPIO_OUT3 0x08 | ||
| 959 | #define V_GPIO_OUT4 0x10 | ||
| 960 | #define V_GPIO_OUT5 0x20 | ||
| 961 | #define V_GPIO_OUT6 0x40 | ||
| 962 | #define V_GPIO_OUT7 0x80 | ||
| 963 | /* R_GPIO_OUT1 */ | ||
| 964 | #define V_GPIO_OUT8 0x01 | ||
| 965 | #define V_GPIO_OUT9 0x02 | ||
| 966 | #define V_GPIO_OUT10 0x04 | ||
| 967 | #define V_GPIO_OUT11 0x08 | ||
| 968 | #define V_GPIO_OUT12 0x10 | ||
| 969 | #define V_GPIO_OUT13 0x20 | ||
| 970 | #define V_GPIO_OUT14 0x40 | ||
| 971 | #define V_GPIO_OUT15 0x80 | ||
| 972 | /* R_GPIO_EN0 */ | ||
| 973 | #define V_GPIO_EN0 0x01 | ||
| 974 | #define V_GPIO_EN1 0x02 | ||
| 975 | #define V_GPIO_EN2 0x04 | ||
| 976 | #define V_GPIO_EN3 0x08 | ||
| 977 | #define V_GPIO_EN4 0x10 | ||
| 978 | #define V_GPIO_EN5 0x20 | ||
| 979 | #define V_GPIO_EN6 0x40 | ||
| 980 | #define V_GPIO_EN7 0x80 | ||
| 981 | /* R_GPIO_EN1 */ | ||
| 982 | #define V_GPIO_EN8 0x01 | ||
| 983 | #define V_GPIO_EN9 0x02 | ||
| 984 | #define V_GPIO_EN10 0x04 | ||
| 985 | #define V_GPIO_EN11 0x08 | ||
| 986 | #define V_GPIO_EN12 0x10 | ||
| 987 | #define V_GPIO_EN13 0x20 | ||
| 988 | #define V_GPIO_EN14 0x40 | ||
| 989 | #define V_GPIO_EN15 0x80 | ||
| 990 | /* R_GPIO_SEL */ | ||
| 991 | #define V_GPIO_SEL0 0x01 | ||
| 992 | #define V_GPIO_SEL1 0x02 | ||
| 993 | #define V_GPIO_SEL2 0x04 | ||
| 994 | #define V_GPIO_SEL3 0x08 | ||
| 995 | #define V_GPIO_SEL4 0x10 | ||
| 996 | #define V_GPIO_SEL5 0x20 | ||
| 997 | #define V_GPIO_SEL6 0x40 | ||
| 998 | #define V_GPIO_SEL7 0x80 | ||
| 999 | /* R_GPIO_IN0 */ | ||
| 1000 | #define V_GPIO_IN0 0x01 | ||
| 1001 | #define V_GPIO_IN1 0x02 | ||
| 1002 | #define V_GPIO_IN2 0x04 | ||
| 1003 | #define V_GPIO_IN3 0x08 | ||
| 1004 | #define V_GPIO_IN4 0x10 | ||
| 1005 | #define V_GPIO_IN5 0x20 | ||
| 1006 | #define V_GPIO_IN6 0x40 | ||
| 1007 | #define V_GPIO_IN7 0x80 | ||
| 1008 | /* R_GPIO_IN1 */ | ||
| 1009 | #define V_GPIO_IN8 0x01 | ||
| 1010 | #define V_GPIO_IN9 0x02 | ||
| 1011 | #define V_GPIO_IN10 0x04 | ||
| 1012 | #define V_GPIO_IN11 0x08 | ||
| 1013 | #define V_GPIO_IN12 0x10 | ||
| 1014 | #define V_GPIO_IN13 0x20 | ||
| 1015 | #define V_GPIO_IN14 0x40 | ||
| 1016 | #define V_GPIO_IN15 0x80 | ||
| 1017 | /* R_GPI_IN0 */ | ||
| 1018 | #define V_GPI_IN0 0x01 | ||
| 1019 | #define V_GPI_IN1 0x02 | ||
| 1020 | #define V_GPI_IN2 0x04 | ||
| 1021 | #define V_GPI_IN3 0x08 | ||
| 1022 | #define V_GPI_IN4 0x10 | ||
| 1023 | #define V_GPI_IN5 0x20 | ||
| 1024 | #define V_GPI_IN6 0x40 | ||
| 1025 | #define V_GPI_IN7 0x80 | ||
| 1026 | /* R_GPI_IN1 */ | ||
| 1027 | #define V_GPI_IN8 0x01 | ||
| 1028 | #define V_GPI_IN9 0x02 | ||
| 1029 | #define V_GPI_IN10 0x04 | ||
| 1030 | #define V_GPI_IN11 0x08 | ||
| 1031 | #define V_GPI_IN12 0x10 | ||
| 1032 | #define V_GPI_IN13 0x20 | ||
| 1033 | #define V_GPI_IN14 0x40 | ||
| 1034 | #define V_GPI_IN15 0x80 | ||
| 1035 | /* R_GPI_IN2 */ | ||
| 1036 | #define V_GPI_IN16 0x01 | ||
| 1037 | #define V_GPI_IN17 0x02 | ||
| 1038 | #define V_GPI_IN18 0x04 | ||
| 1039 | #define V_GPI_IN19 0x08 | ||
| 1040 | #define V_GPI_IN20 0x10 | ||
| 1041 | #define V_GPI_IN21 0x20 | ||
| 1042 | #define V_GPI_IN22 0x40 | ||
| 1043 | #define V_GPI_IN23 0x80 | ||
| 1044 | /* R_GPI_IN3 */ | ||
| 1045 | #define V_GPI_IN24 0x01 | ||
| 1046 | #define V_GPI_IN25 0x02 | ||
| 1047 | #define V_GPI_IN26 0x04 | ||
| 1048 | #define V_GPI_IN27 0x08 | ||
| 1049 | #define V_GPI_IN28 0x10 | ||
| 1050 | #define V_GPI_IN29 0x20 | ||
| 1051 | #define V_GPI_IN30 0x40 | ||
| 1052 | #define V_GPI_IN31 0x80 | ||
| 1053 | |||
| 1054 | /* map of all registers, used for debugging */ | ||
| 1055 | |||
| 1056 | #ifdef HFC_REGISTER_DEBUG | ||
| 1057 | struct hfc_register_names { | ||
| 1058 | char *name; | ||
| 1059 | u_char reg; | ||
| 1060 | } hfc_register_names[] = { | ||
| 1061 | /* write registers */ | ||
| 1062 | {"R_CIRM", 0x00}, | ||
| 1063 | {"R_CTRL", 0x01}, | ||
| 1064 | {"R_BRG_PCM_CFG ", 0x02}, | ||
| 1065 | {"R_RAM_ADDR0", 0x08}, | ||
| 1066 | {"R_RAM_ADDR1", 0x09}, | ||
| 1067 | {"R_RAM_ADDR2", 0x0A}, | ||
| 1068 | {"R_FIRST_FIFO", 0x0B}, | ||
| 1069 | {"R_RAM_SZ", 0x0C}, | ||
| 1070 | {"R_FIFO_MD", 0x0D}, | ||
| 1071 | {"R_INC_RES_FIFO", 0x0E}, | ||
| 1072 | {"R_FIFO / R_FSM_IDX", 0x0F}, | ||
| 1073 | {"R_SLOT", 0x10}, | ||
| 1074 | {"R_IRQMSK_MISC", 0x11}, | ||
| 1075 | {"R_SCI_MSK", 0x12}, | ||
| 1076 | {"R_IRQ_CTRL", 0x13}, | ||
| 1077 | {"R_PCM_MD0", 0x14}, | ||
| 1078 | {"R_0x15", 0x15}, | ||
| 1079 | {"R_ST_SEL", 0x16}, | ||
| 1080 | {"R_ST_SYNC", 0x17}, | ||
| 1081 | {"R_CONF_EN", 0x18}, | ||
| 1082 | {"R_TI_WD", 0x1A}, | ||
| 1083 | {"R_BERT_WD_MD", 0x1B}, | ||
| 1084 | {"R_DTMF", 0x1C}, | ||
| 1085 | {"R_DTMF_N", 0x1D}, | ||
| 1086 | {"R_E1_XX_STA", 0x20}, | ||
| 1087 | {"R_LOS0", 0x22}, | ||
| 1088 | {"R_LOS1", 0x23}, | ||
| 1089 | {"R_RX0", 0x24}, | ||
| 1090 | {"R_RX_FR0", 0x25}, | ||
| 1091 | {"R_RX_FR1", 0x26}, | ||
| 1092 | {"R_TX0", 0x28}, | ||
| 1093 | {"R_TX1", 0x29}, | ||
| 1094 | {"R_TX_FR0", 0x2C}, | ||
| 1095 | {"R_TX_FR1", 0x2D}, | ||
| 1096 | {"R_TX_FR2", 0x2E}, | ||
| 1097 | {"R_JATT_ATT", 0x2F}, | ||
| 1098 | {"A_ST_xx_STA/R_RX_OFF", 0x30}, | ||
| 1099 | {"A_ST_CTRL0/R_SYNC_OUT", 0x31}, | ||
| 1100 | {"A_ST_CTRL1", 0x32}, | ||
| 1101 | {"A_ST_CTRL2", 0x33}, | ||
| 1102 | {"A_ST_SQ_WR", 0x34}, | ||
| 1103 | {"R_TX_OFF", 0x34}, | ||
| 1104 | {"R_SYNC_CTRL", 0x35}, | ||
| 1105 | {"A_ST_CLK_DLY", 0x37}, | ||
| 1106 | {"R_PWM0", 0x38}, | ||
| 1107 | {"R_PWM1", 0x39}, | ||
| 1108 | {"A_ST_B1_TX", 0x3C}, | ||
| 1109 | {"A_ST_B2_TX", 0x3D}, | ||
| 1110 | {"A_ST_D_TX", 0x3E}, | ||
| 1111 | {"R_GPIO_OUT0", 0x40}, | ||
| 1112 | {"R_GPIO_OUT1", 0x41}, | ||
| 1113 | {"R_GPIO_EN0", 0x42}, | ||
| 1114 | {"R_GPIO_EN1", 0x43}, | ||
| 1115 | {"R_GPIO_SEL", 0x44}, | ||
| 1116 | {"R_BRG_CTRL", 0x45}, | ||
| 1117 | {"R_PWM_MD", 0x46}, | ||
| 1118 | {"R_BRG_MD", 0x47}, | ||
| 1119 | {"R_BRG_TIM0", 0x48}, | ||
| 1120 | {"R_BRG_TIM1", 0x49}, | ||
| 1121 | {"R_BRG_TIM2", 0x4A}, | ||
| 1122 | {"R_BRG_TIM3", 0x4B}, | ||
| 1123 | {"R_BRG_TIM_SEL01", 0x4C}, | ||
| 1124 | {"R_BRG_TIM_SEL23", 0x4D}, | ||
| 1125 | {"R_BRG_TIM_SEL45", 0x4E}, | ||
| 1126 | {"R_BRG_TIM_SEL67", 0x4F}, | ||
| 1127 | {"A_FIFO_DATA0-2", 0x80}, | ||
| 1128 | {"A_FIFO_DATA0-2_NOINC", 0x84}, | ||
| 1129 | {"R_RAM_DATA", 0xC0}, | ||
| 1130 | {"A_SL_CFG", 0xD0}, | ||
| 1131 | {"A_CONF", 0xD1}, | ||
| 1132 | {"A_CH_MSK", 0xF4}, | ||
| 1133 | {"A_CON_HDLC", 0xFA}, | ||
| 1134 | {"A_SUBCH_CFG", 0xFB}, | ||
| 1135 | {"A_CHANNEL", 0xFC}, | ||
| 1136 | {"A_FIFO_SEQ", 0xFD}, | ||
| 1137 | {"A_IRQ_MSK", 0xFF}, | ||
| 1138 | {NULL, 0}, | ||
| 1139 | |||
| 1140 | /* read registers */ | ||
| 1141 | {"A_Z1", 0x04}, | ||
| 1142 | {"A_Z1H", 0x05}, | ||
| 1143 | {"A_Z2", 0x06}, | ||
| 1144 | {"A_Z2H", 0x07}, | ||
| 1145 | {"A_F1", 0x0C}, | ||
| 1146 | {"A_F2", 0x0D}, | ||
| 1147 | {"R_IRQ_OVIEW", 0x10}, | ||
| 1148 | {"R_IRQ_MISC", 0x11}, | ||
| 1149 | {"R_IRQ_STATECH", 0x12}, | ||
| 1150 | {"R_CONF_OFLOW", 0x14}, | ||
| 1151 | {"R_RAM_USE", 0x15}, | ||
| 1152 | {"R_CHIP_ID", 0x16}, | ||
| 1153 | {"R_BERT_STA", 0x17}, | ||
| 1154 | {"R_F0_CNTL", 0x18}, | ||
| 1155 | {"R_F0_CNTH", 0x19}, | ||
| 1156 | {"R_BERT_ECL", 0x1A}, | ||
| 1157 | {"R_BERT_ECH", 0x1B}, | ||
| 1158 | {"R_STATUS", 0x1C}, | ||
| 1159 | {"R_CHIP_RV", 0x1F}, | ||
| 1160 | {"R_STATE", 0x20}, | ||
| 1161 | {"R_SYNC_STA", 0x24}, | ||
| 1162 | {"R_RX_SL0_0", 0x25}, | ||
| 1163 | {"R_RX_SL0_1", 0x26}, | ||
| 1164 | {"R_RX_SL0_2", 0x27}, | ||
| 1165 | {"R_JATT_DIR", 0x2b}, | ||
| 1166 | {"R_SLIP", 0x2c}, | ||
| 1167 | {"A_ST_RD_STA", 0x30}, | ||
| 1168 | {"R_FAS_ECL", 0x30}, | ||
| 1169 | {"R_FAS_ECH", 0x31}, | ||
| 1170 | {"R_VIO_ECL", 0x32}, | ||
| 1171 | {"R_VIO_ECH", 0x33}, | ||
| 1172 | {"R_CRC_ECL / A_ST_SQ_RD", 0x34}, | ||
| 1173 | {"R_CRC_ECH", 0x35}, | ||
| 1174 | {"R_E_ECL", 0x36}, | ||
| 1175 | {"R_E_ECH", 0x37}, | ||
| 1176 | {"R_SA6_SA13_ECL", 0x38}, | ||
| 1177 | {"R_SA6_SA13_ECH", 0x39}, | ||
| 1178 | {"R_SA6_SA23_ECL", 0x3A}, | ||
| 1179 | {"R_SA6_SA23_ECH", 0x3B}, | ||
| 1180 | {"A_ST_B1_RX", 0x3C}, | ||
| 1181 | {"A_ST_B2_RX", 0x3D}, | ||
| 1182 | {"A_ST_D_RX", 0x3E}, | ||
| 1183 | {"A_ST_E_RX", 0x3F}, | ||
| 1184 | {"R_GPIO_IN0", 0x40}, | ||
| 1185 | {"R_GPIO_IN1", 0x41}, | ||
| 1186 | {"R_GPI_IN0", 0x44}, | ||
| 1187 | {"R_GPI_IN1", 0x45}, | ||
| 1188 | {"R_GPI_IN2", 0x46}, | ||
| 1189 | {"R_GPI_IN3", 0x47}, | ||
| 1190 | {"A_FIFO_DATA0-2", 0x80}, | ||
| 1191 | {"A_FIFO_DATA0-2_NOINC", 0x84}, | ||
| 1192 | {"R_INT_DATA", 0x88}, | ||
| 1193 | {"R_RAM_DATA", 0xC0}, | ||
| 1194 | {"R_IRQ_FIFO_BL0", 0xC8}, | ||
| 1195 | {"R_IRQ_FIFO_BL1", 0xC9}, | ||
| 1196 | {"R_IRQ_FIFO_BL2", 0xCA}, | ||
| 1197 | {"R_IRQ_FIFO_BL3", 0xCB}, | ||
| 1198 | {"R_IRQ_FIFO_BL4", 0xCC}, | ||
| 1199 | {"R_IRQ_FIFO_BL5", 0xCD}, | ||
| 1200 | {"R_IRQ_FIFO_BL6", 0xCE}, | ||
| 1201 | {"R_IRQ_FIFO_BL7", 0xCF}, | ||
| 1202 | }; | ||
| 1203 | #endif /* HFC_REGISTER_DEBUG */ | ||
| 1204 | |||
diff --git a/drivers/isdn/hardware/mISDN/hfc_pci.h b/drivers/isdn/hardware/mISDN/hfc_pci.h new file mode 100644 index 000000000000..fd2c9be6d849 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/hfc_pci.h | |||
| @@ -0,0 +1,228 @@ | |||
| 1 | /* | ||
| 2 | * specific defines for CCD's HFC 2BDS0 PCI chips | ||
| 3 | * | ||
| 4 | * Author Werner Cornelius (werner@isdn4linux.de) | ||
| 5 | * | ||
| 6 | * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de) | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 11 | * any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 21 | * | ||
| 22 | */ | ||
| 23 | |||
| 24 | /* | ||
| 25 | * thresholds for transparent B-channel mode | ||
| 26 | * change mask and threshold simultaneously | ||
| 27 | */ | ||
| 28 | #define HFCPCI_BTRANS_THRESHOLD 128 | ||
| 29 | #define HFCPCI_BTRANS_MAX 256 | ||
| 30 | #define HFCPCI_BTRANS_THRESMASK 0x00 | ||
| 31 | |||
| 32 | /* defines for PCI config */ | ||
| 33 | #define PCI_ENA_MEMIO 0x02 | ||
| 34 | #define PCI_ENA_MASTER 0x04 | ||
| 35 | |||
| 36 | /* GCI/IOM bus monitor registers */ | ||
| 37 | #define HCFPCI_C_I 0x08 | ||
| 38 | #define HFCPCI_TRxR 0x0C | ||
| 39 | #define HFCPCI_MON1_D 0x28 | ||
| 40 | #define HFCPCI_MON2_D 0x2C | ||
| 41 | |||
| 42 | /* GCI/IOM bus timeslot registers */ | ||
| 43 | #define HFCPCI_B1_SSL 0x80 | ||
| 44 | #define HFCPCI_B2_SSL 0x84 | ||
| 45 | #define HFCPCI_AUX1_SSL 0x88 | ||
| 46 | #define HFCPCI_AUX2_SSL 0x8C | ||
| 47 | #define HFCPCI_B1_RSL 0x90 | ||
| 48 | #define HFCPCI_B2_RSL 0x94 | ||
| 49 | #define HFCPCI_AUX1_RSL 0x98 | ||
| 50 | #define HFCPCI_AUX2_RSL 0x9C | ||
| 51 | |||
| 52 | /* GCI/IOM bus data registers */ | ||
| 53 | #define HFCPCI_B1_D 0xA0 | ||
| 54 | #define HFCPCI_B2_D 0xA4 | ||
| 55 | #define HFCPCI_AUX1_D 0xA8 | ||
| 56 | #define HFCPCI_AUX2_D 0xAC | ||
| 57 | |||
| 58 | /* GCI/IOM bus configuration registers */ | ||
| 59 | #define HFCPCI_MST_EMOD 0xB4 | ||
| 60 | #define HFCPCI_MST_MODE 0xB8 | ||
| 61 | #define HFCPCI_CONNECT 0xBC | ||
| 62 | |||
| 63 | |||
| 64 | /* Interrupt and status registers */ | ||
| 65 | #define HFCPCI_FIFO_EN 0x44 | ||
| 66 | #define HFCPCI_TRM 0x48 | ||
| 67 | #define HFCPCI_B_MODE 0x4C | ||
| 68 | #define HFCPCI_CHIP_ID 0x58 | ||
| 69 | #define HFCPCI_CIRM 0x60 | ||
| 70 | #define HFCPCI_CTMT 0x64 | ||
| 71 | #define HFCPCI_INT_M1 0x68 | ||
| 72 | #define HFCPCI_INT_M2 0x6C | ||
| 73 | #define HFCPCI_INT_S1 0x78 | ||
| 74 | #define HFCPCI_INT_S2 0x7C | ||
| 75 | #define HFCPCI_STATUS 0x70 | ||
| 76 | |||
| 77 | /* S/T section registers */ | ||
| 78 | #define HFCPCI_STATES 0xC0 | ||
| 79 | #define HFCPCI_SCTRL 0xC4 | ||
| 80 | #define HFCPCI_SCTRL_E 0xC8 | ||
| 81 | #define HFCPCI_SCTRL_R 0xCC | ||
| 82 | #define HFCPCI_SQ 0xD0 | ||
| 83 | #define HFCPCI_CLKDEL 0xDC | ||
| 84 | #define HFCPCI_B1_REC 0xF0 | ||
| 85 | #define HFCPCI_B1_SEND 0xF0 | ||
| 86 | #define HFCPCI_B2_REC 0xF4 | ||
| 87 | #define HFCPCI_B2_SEND 0xF4 | ||
| 88 | #define HFCPCI_D_REC 0xF8 | ||
| 89 | #define HFCPCI_D_SEND 0xF8 | ||
| 90 | #define HFCPCI_E_REC 0xFC | ||
| 91 | |||
| 92 | |||
| 93 | /* bits in status register (READ) */ | ||
| 94 | #define HFCPCI_PCI_PROC 0x02 | ||
| 95 | #define HFCPCI_NBUSY 0x04 | ||
| 96 | #define HFCPCI_TIMER_ELAP 0x10 | ||
| 97 | #define HFCPCI_STATINT 0x20 | ||
| 98 | #define HFCPCI_FRAMEINT 0x40 | ||
| 99 | #define HFCPCI_ANYINT 0x80 | ||
| 100 | |||
| 101 | /* bits in CTMT (Write) */ | ||
| 102 | #define HFCPCI_CLTIMER 0x80 | ||
| 103 | #define HFCPCI_TIM3_125 0x04 | ||
| 104 | #define HFCPCI_TIM25 0x10 | ||
| 105 | #define HFCPCI_TIM50 0x14 | ||
| 106 | #define HFCPCI_TIM400 0x18 | ||
| 107 | #define HFCPCI_TIM800 0x1C | ||
| 108 | #define HFCPCI_AUTO_TIMER 0x20 | ||
| 109 | #define HFCPCI_TRANSB2 0x02 | ||
| 110 | #define HFCPCI_TRANSB1 0x01 | ||
| 111 | |||
| 112 | /* bits in CIRM (Write) */ | ||
| 113 | #define HFCPCI_AUX_MSK 0x07 | ||
| 114 | #define HFCPCI_RESET 0x08 | ||
| 115 | #define HFCPCI_B1_REV 0x40 | ||
| 116 | #define HFCPCI_B2_REV 0x80 | ||
| 117 | |||
| 118 | /* bits in INT_M1 and INT_S1 */ | ||
| 119 | #define HFCPCI_INTS_B1TRANS 0x01 | ||
| 120 | #define HFCPCI_INTS_B2TRANS 0x02 | ||
| 121 | #define HFCPCI_INTS_DTRANS 0x04 | ||
| 122 | #define HFCPCI_INTS_B1REC 0x08 | ||
| 123 | #define HFCPCI_INTS_B2REC 0x10 | ||
| 124 | #define HFCPCI_INTS_DREC 0x20 | ||
| 125 | #define HFCPCI_INTS_L1STATE 0x40 | ||
| 126 | #define HFCPCI_INTS_TIMER 0x80 | ||
| 127 | |||
| 128 | /* bits in INT_M2 */ | ||
| 129 | #define HFCPCI_PROC_TRANS 0x01 | ||
| 130 | #define HFCPCI_GCI_I_CHG 0x02 | ||
| 131 | #define HFCPCI_GCI_MON_REC 0x04 | ||
| 132 | #define HFCPCI_IRQ_ENABLE 0x08 | ||
| 133 | #define HFCPCI_PMESEL 0x80 | ||
| 134 | |||
| 135 | /* bits in STATES */ | ||
| 136 | #define HFCPCI_STATE_MSK 0x0F | ||
| 137 | #define HFCPCI_LOAD_STATE 0x10 | ||
| 138 | #define HFCPCI_ACTIVATE 0x20 | ||
| 139 | #define HFCPCI_DO_ACTION 0x40 | ||
| 140 | #define HFCPCI_NT_G2_G3 0x80 | ||
| 141 | |||
| 142 | /* bits in HFCD_MST_MODE */ | ||
| 143 | #define HFCPCI_MASTER 0x01 | ||
| 144 | #define HFCPCI_SLAVE 0x00 | ||
| 145 | #define HFCPCI_F0IO_POSITIV 0x02 | ||
| 146 | #define HFCPCI_F0_NEGATIV 0x04 | ||
| 147 | #define HFCPCI_F0_2C4 0x08 | ||
| 148 | /* remaining bits are for codecs control */ | ||
| 149 | |||
| 150 | /* bits in HFCD_SCTRL */ | ||
| 151 | #define SCTRL_B1_ENA 0x01 | ||
| 152 | #define SCTRL_B2_ENA 0x02 | ||
| 153 | #define SCTRL_MODE_TE 0x00 | ||
| 154 | #define SCTRL_MODE_NT 0x04 | ||
| 155 | #define SCTRL_LOW_PRIO 0x08 | ||
| 156 | #define SCTRL_SQ_ENA 0x10 | ||
| 157 | #define SCTRL_TEST 0x20 | ||
| 158 | #define SCTRL_NONE_CAP 0x40 | ||
| 159 | #define SCTRL_PWR_DOWN 0x80 | ||
| 160 | |||
| 161 | /* bits in SCTRL_E */ | ||
| 162 | #define HFCPCI_AUTO_AWAKE 0x01 | ||
| 163 | #define HFCPCI_DBIT_1 0x04 | ||
| 164 | #define HFCPCI_IGNORE_COL 0x08 | ||
| 165 | #define HFCPCI_CHG_B1_B2 0x80 | ||
| 166 | |||
| 167 | /* bits in FIFO_EN register */ | ||
| 168 | #define HFCPCI_FIFOEN_B1 0x03 | ||
| 169 | #define HFCPCI_FIFOEN_B2 0x0C | ||
| 170 | #define HFCPCI_FIFOEN_DTX 0x10 | ||
| 171 | #define HFCPCI_FIFOEN_B1TX 0x01 | ||
| 172 | #define HFCPCI_FIFOEN_B1RX 0x02 | ||
| 173 | #define HFCPCI_FIFOEN_B2TX 0x04 | ||
| 174 | #define HFCPCI_FIFOEN_B2RX 0x08 | ||
| 175 | |||
| 176 | |||
| 177 | /* definitions of fifo memory area */ | ||
| 178 | #define MAX_D_FRAMES 15 | ||
| 179 | #define MAX_B_FRAMES 31 | ||
| 180 | #define B_SUB_VAL 0x200 | ||
| 181 | #define B_FIFO_SIZE (0x2000 - B_SUB_VAL) | ||
| 182 | #define D_FIFO_SIZE 512 | ||
| 183 | #define D_FREG_MASK 0xF | ||
| 184 | |||
| 185 | struct zt { | ||
| 186 | unsigned short z1; /* Z1 pointer 16 Bit */ | ||
| 187 | unsigned short z2; /* Z2 pointer 16 Bit */ | ||
| 188 | }; | ||
| 189 | |||
| 190 | struct dfifo { | ||
| 191 | u_char data[D_FIFO_SIZE]; /* FIFO data space */ | ||
| 192 | u_char fill1[0x20A0-D_FIFO_SIZE]; /* reserved, do not use */ | ||
| 193 | u_char f1, f2; /* f pointers */ | ||
| 194 | u_char fill2[0x20C0-0x20A2]; /* reserved, do not use */ | ||
| 195 | /* mask index with D_FREG_MASK for access */ | ||
| 196 | struct zt za[MAX_D_FRAMES+1]; | ||
| 197 | u_char fill3[0x4000-0x2100]; /* align 16K */ | ||
| 198 | }; | ||
| 199 | |||
| 200 | struct bzfifo { | ||
| 201 | struct zt za[MAX_B_FRAMES+1]; /* only range 0x0..0x1F allowed */ | ||
| 202 | u_char f1, f2; /* f pointers */ | ||
| 203 | u_char fill[0x2100-0x2082]; /* alignment */ | ||
| 204 | }; | ||
| 205 | |||
| 206 | |||
| 207 | union fifo_area { | ||
| 208 | struct { | ||
| 209 | struct dfifo d_tx; /* D-send channel */ | ||
| 210 | struct dfifo d_rx; /* D-receive channel */ | ||
| 211 | } d_chan; | ||
| 212 | struct { | ||
| 213 | u_char fill1[0x200]; | ||
| 214 | u_char txdat_b1[B_FIFO_SIZE]; | ||
| 215 | struct bzfifo txbz_b1; | ||
| 216 | struct bzfifo txbz_b2; | ||
| 217 | u_char txdat_b2[B_FIFO_SIZE]; | ||
| 218 | u_char fill2[D_FIFO_SIZE]; | ||
| 219 | u_char rxdat_b1[B_FIFO_SIZE]; | ||
| 220 | struct bzfifo rxbz_b1; | ||
| 221 | struct bzfifo rxbz_b2; | ||
| 222 | u_char rxdat_b2[B_FIFO_SIZE]; | ||
| 223 | } b_chans; | ||
| 224 | u_char fill[32768]; | ||
| 225 | }; | ||
| 226 | |||
| 227 | #define Write_hfc(a, b, c) (writeb(c, (a->hw.pci_io)+b)) | ||
| 228 | #define Read_hfc(a, b) (readb((a->hw.pci_io)+b)) | ||
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c new file mode 100644 index 000000000000..2649ea55a9e8 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c | |||
| @@ -0,0 +1,5320 @@ | |||
| 1 | /* | ||
| 2 | * hfcmulti.c low level driver for hfc-4s/hfc-8s/hfc-e1 based cards | ||
| 3 | * | ||
| 4 | * Author Andreas Eversberg (jolly@eversberg.eu) | ||
| 5 | * ported to mqueue mechanism: | ||
| 6 | * Peter Sprenger (sprengermoving-bytes.de) | ||
| 7 | * | ||
| 8 | * inspired by existing hfc-pci driver: | ||
| 9 | * Copyright 1999 by Werner Cornelius (werner@isdn-development.de) | ||
| 10 | * Copyright 2008 by Karsten Keil (kkeil@suse.de) | ||
| 11 | * Copyright 2008 by Andreas Eversberg (jolly@eversberg.eu) | ||
| 12 | * | ||
| 13 | * This program is free software; you can redistribute it and/or modify | ||
| 14 | * it under the terms of the GNU General Public License as published by | ||
| 15 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 16 | * any later version. | ||
| 17 | * | ||
| 18 | * This program is distributed in the hope that it will be useful, | ||
| 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 21 | * GNU General Public License for more details. | ||
| 22 | * | ||
| 23 | * You should have received a copy of the GNU General Public License | ||
| 24 | * along with this program; if not, write to the Free Software | ||
| 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 26 | * | ||
| 27 | * | ||
| 28 | * Thanks to Cologne Chip AG for this great controller! | ||
| 29 | */ | ||
| 30 | |||
| 31 | /* | ||
| 32 | * module parameters: | ||
| 33 | * type: | ||
| 34 | * By default (0), the card is automatically detected. | ||
| 35 | * Or use the following combinations: | ||
| 36 | * Bit 0-7 = 0x00001 = HFC-E1 (1 port) | ||
| 37 | * or Bit 0-7 = 0x00004 = HFC-4S (4 ports) | ||
| 38 | * or Bit 0-7 = 0x00008 = HFC-8S (8 ports) | ||
| 39 | * Bit 8 = 0x00100 = uLaw (instead of aLaw) | ||
| 40 | * Bit 9 = 0x00200 = Disable DTMF detect on all B-channels via hardware | ||
| 41 | * Bit 10 = spare | ||
| 42 | * Bit 11 = 0x00800 = Force PCM bus into slave mode. (otherwhise auto) | ||
| 43 | * or Bit 12 = 0x01000 = Force PCM bus into master mode. (otherwhise auto) | ||
| 44 | * Bit 13 = spare | ||
| 45 | * Bit 14 = 0x04000 = Use external ram (128K) | ||
| 46 | * Bit 15 = 0x08000 = Use external ram (512K) | ||
| 47 | * Bit 16 = 0x10000 = Use 64 timeslots instead of 32 | ||
| 48 | * or Bit 17 = 0x20000 = Use 128 timeslots instead of anything else | ||
| 49 | * Bit 18 = spare | ||
| 50 | * Bit 19 = 0x80000 = Send the Watchdog a Signal (Dual E1 with Watchdog) | ||
| 51 | * (all other bits are reserved and shall be 0) | ||
| 52 | * example: 0x20204 one HFC-4S with dtmf detection and 128 timeslots on PCM | ||
| 53 | * bus (PCM master) | ||
| 54 | * | ||
| 55 | * port: (optional or required for all ports on all installed cards) | ||
| 56 | * HFC-4S/HFC-8S only bits: | ||
| 57 | * Bit 0 = 0x001 = Use master clock for this S/T interface | ||
| 58 | * (ony once per chip). | ||
| 59 | * Bit 1 = 0x002 = transmitter line setup (non capacitive mode) | ||
| 60 | * Don't use this unless you know what you are doing! | ||
| 61 | * Bit 2 = 0x004 = Disable E-channel. (No E-channel processing) | ||
| 62 | * example: 0x0001,0x0000,0x0000,0x0000 one HFC-4S with master clock | ||
| 63 | * received from port 1 | ||
| 64 | * | ||
| 65 | * HFC-E1 only bits: | ||
| 66 | * Bit 0 = 0x0001 = interface: 0=copper, 1=optical | ||
| 67 | * Bit 1 = 0x0002 = reserved (later for 32 B-channels transparent mode) | ||
| 68 | * Bit 2 = 0x0004 = Report LOS | ||
| 69 | * Bit 3 = 0x0008 = Report AIS | ||
| 70 | * Bit 4 = 0x0010 = Report SLIP | ||
| 71 | * Bit 5 = 0x0020 = Report RDI | ||
| 72 | * Bit 8 = 0x0100 = Turn off CRC-4 Multiframe Mode, use double frame | ||
| 73 | * mode instead. | ||
| 74 | * Bit 9 = 0x0200 = Force get clock from interface, even in NT mode. | ||
| 75 | * or Bit 10 = 0x0400 = Force put clock to interface, even in TE mode. | ||
| 76 | * Bit 11 = 0x0800 = Use direct RX clock for PCM sync rather than PLL. | ||
| 77 | * (E1 only) | ||
| 78 | * Bit 12-13 = 0xX000 = elastic jitter buffer (1-3), Set both bits to 0 | ||
| 79 | * for default. | ||
| 80 | * (all other bits are reserved and shall be 0) | ||
| 81 | * | ||
| 82 | * debug: | ||
| 83 | * NOTE: only one debug value must be given for all cards | ||
| 84 | * enable debugging (see hfc_multi.h for debug options) | ||
| 85 | * | ||
| 86 | * poll: | ||
| 87 | * NOTE: only one poll value must be given for all cards | ||
| 88 | * Give the number of samples for each fifo process. | ||
| 89 | * By default 128 is used. Decrease to reduce delay, increase to | ||
| 90 | * reduce cpu load. If unsure, don't mess with it! | ||
| 91 | * Valid is 8, 16, 32, 64, 128, 256. | ||
| 92 | * | ||
| 93 | * pcm: | ||
| 94 | * NOTE: only one pcm value must be given for every card. | ||
| 95 | * The PCM bus id tells the mISDNdsp module about the connected PCM bus. | ||
| 96 | * By default (0), the PCM bus id is 100 for the card that is PCM master. | ||
| 97 | * If multiple cards are PCM master (because they are not interconnected), | ||
| 98 | * each card with PCM master will have increasing PCM id. | ||
| 99 | * All PCM busses with the same ID are expected to be connected and have | ||
| 100 | * common time slots slots. | ||
| 101 | * Only one chip of the PCM bus must be master, the others slave. | ||
| 102 | * -1 means no support of PCM bus not even. | ||
| 103 | * Omit this value, if all cards are interconnected or none is connected. | ||
| 104 | * If unsure, don't give this parameter. | ||
| 105 | * | ||
| 106 | * dslot: | ||
| 107 | * NOTE: only one poll value must be given for every card. | ||
| 108 | * Also this value must be given for non-E1 cards. If omitted, the E1 | ||
| 109 | * card has D-channel on time slot 16, which is default. | ||
| 110 | * If 1..15 or 17..31, an alternate time slot is used for D-channel. | ||
| 111 | * In this case, the application must be able to handle this. | ||
| 112 | * If -1 is given, the D-channel is disabled and all 31 slots can be used | ||
| 113 | * for B-channel. (only for specific applications) | ||
| 114 | * If you don't know how to use it, you don't need it! | ||
| 115 | * | ||
| 116 | * iomode: | ||
| 117 | * NOTE: only one mode value must be given for every card. | ||
| 118 | * -> See hfc_multi.h for HFC_IO_MODE_* values | ||
| 119 | * By default, the IO mode is pci memory IO (MEMIO). | ||
| 120 | * Some cards requre specific IO mode, so it cannot be changed. | ||
| 121 | * It may be usefull to set IO mode to register io (REGIO) to solve | ||
| 122 | * PCI bridge problems. | ||
| 123 | * If unsure, don't give this parameter. | ||
| 124 | * | ||
| 125 | * clockdelay_nt: | ||
| 126 | * NOTE: only one clockdelay_nt value must be given once for all cards. | ||
| 127 | * Give the value of the clock control register (A_ST_CLK_DLY) | ||
| 128 | * of the S/T interfaces in NT mode. | ||
| 129 | * This register is needed for the TBR3 certification, so don't change it. | ||
| 130 | * | ||
| 131 | * clockdelay_te: | ||
| 132 | * NOTE: only one clockdelay_te value must be given once | ||
| 133 | * Give the value of the clock control register (A_ST_CLK_DLY) | ||
| 134 | * of the S/T interfaces in TE mode. | ||
| 135 | * This register is needed for the TBR3 certification, so don't change it. | ||
| 136 | */ | ||
| 137 | |||
| 138 | /* | ||
| 139 | * debug register access (never use this, it will flood your system log) | ||
| 140 | * #define HFC_REGISTER_DEBUG | ||
| 141 | */ | ||
| 142 | |||
| 143 | static const char *hfcmulti_revision = "2.00"; | ||
| 144 | |||
| 145 | #include <linux/module.h> | ||
| 146 | #include <linux/pci.h> | ||
| 147 | #include <linux/delay.h> | ||
| 148 | #include <linux/mISDNhw.h> | ||
| 149 | #include <linux/mISDNdsp.h> | ||
| 150 | |||
| 151 | /* | ||
| 152 | #define IRQCOUNT_DEBUG | ||
| 153 | #define IRQ_DEBUG | ||
| 154 | */ | ||
| 155 | |||
| 156 | #include "hfc_multi.h" | ||
| 157 | #ifdef ECHOPREP | ||
| 158 | #include "gaintab.h" | ||
| 159 | #endif | ||
| 160 | |||
| 161 | #define MAX_CARDS 8 | ||
| 162 | #define MAX_PORTS (8 * MAX_CARDS) | ||
| 163 | |||
| 164 | static LIST_HEAD(HFClist); | ||
| 165 | static spinlock_t HFClock; /* global hfc list lock */ | ||
| 166 | |||
| 167 | static void ph_state_change(struct dchannel *); | ||
| 168 | static void (*hfc_interrupt)(void); | ||
| 169 | static void (*register_interrupt)(void); | ||
| 170 | static int (*unregister_interrupt)(void); | ||
| 171 | static int interrupt_registered; | ||
| 172 | |||
| 173 | static struct hfc_multi *syncmaster; | ||
| 174 | int plxsd_master; /* if we have a master card (yet) */ | ||
| 175 | static spinlock_t plx_lock; /* may not acquire other lock inside */ | ||
| 176 | EXPORT_SYMBOL(plx_lock); | ||
| 177 | |||
| 178 | #define TYP_E1 1 | ||
| 179 | #define TYP_4S 4 | ||
| 180 | #define TYP_8S 8 | ||
| 181 | |||
| 182 | static int poll_timer = 6; /* default = 128 samples = 16ms */ | ||
| 183 | /* number of POLL_TIMER interrupts for G2 timeout (ca 1s) */ | ||
| 184 | static int nt_t1_count[] = { 3840, 1920, 960, 480, 240, 120, 60, 30 }; | ||
| 185 | #define CLKDEL_TE 0x0f /* CLKDEL in TE mode */ | ||
| 186 | #define CLKDEL_NT 0x6c /* CLKDEL in NT mode | ||
| 187 | (0x60 MUST be included!) */ | ||
| 188 | static u_char silence = 0xff; /* silence by LAW */ | ||
| 189 | |||
| 190 | #define DIP_4S 0x1 /* DIP Switches for Beronet 1S/2S/4S cards */ | ||
| 191 | #define DIP_8S 0x2 /* DIP Switches for Beronet 8S+ cards */ | ||
| 192 | #define DIP_E1 0x3 /* DIP Switches for Beronet E1 cards */ | ||
| 193 | |||
| 194 | /* | ||
| 195 | * module stuff | ||
| 196 | */ | ||
| 197 | |||
| 198 | static uint type[MAX_CARDS]; | ||
| 199 | static uint pcm[MAX_CARDS]; | ||
| 200 | static uint dslot[MAX_CARDS]; | ||
| 201 | static uint iomode[MAX_CARDS]; | ||
| 202 | static uint port[MAX_PORTS]; | ||
| 203 | static uint debug; | ||
| 204 | static uint poll; | ||
| 205 | static uint timer; | ||
| 206 | static uint clockdelay_te = CLKDEL_TE; | ||
| 207 | static uint clockdelay_nt = CLKDEL_NT; | ||
| 208 | |||
| 209 | static int HFC_cnt, Port_cnt, PCM_cnt = 99; | ||
| 210 | |||
| 211 | MODULE_AUTHOR("Andreas Eversberg"); | ||
| 212 | MODULE_LICENSE("GPL"); | ||
| 213 | module_param(debug, uint, S_IRUGO | S_IWUSR); | ||
| 214 | module_param(poll, uint, S_IRUGO | S_IWUSR); | ||
| 215 | module_param(timer, uint, S_IRUGO | S_IWUSR); | ||
| 216 | module_param(clockdelay_te, uint, S_IRUGO | S_IWUSR); | ||
| 217 | module_param(clockdelay_nt, uint, S_IRUGO | S_IWUSR); | ||
| 218 | module_param_array(type, uint, NULL, S_IRUGO | S_IWUSR); | ||
| 219 | module_param_array(pcm, uint, NULL, S_IRUGO | S_IWUSR); | ||
| 220 | module_param_array(dslot, uint, NULL, S_IRUGO | S_IWUSR); | ||
| 221 | module_param_array(iomode, uint, NULL, S_IRUGO | S_IWUSR); | ||
| 222 | module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR); | ||
| 223 | |||
| 224 | #ifdef HFC_REGISTER_DEBUG | ||
| 225 | #define HFC_outb(hc, reg, val) \ | ||
| 226 | (hc->HFC_outb(hc, reg, val, __func__, __LINE__)) | ||
| 227 | #define HFC_outb_nodebug(hc, reg, val) \ | ||
| 228 | (hc->HFC_outb_nodebug(hc, reg, val, __func__, __LINE__)) | ||
| 229 | #define HFC_inb(hc, reg) \ | ||
| 230 | (hc->HFC_inb(hc, reg, __func__, __LINE__)) | ||
| 231 | #define HFC_inb_nodebug(hc, reg) \ | ||
| 232 | (hc->HFC_inb_nodebug(hc, reg, __func__, __LINE__)) | ||
| 233 | #define HFC_inw(hc, reg) \ | ||
| 234 | (hc->HFC_inw(hc, reg, __func__, __LINE__)) | ||
| 235 | #define HFC_inw_nodebug(hc, reg) \ | ||
| 236 | (hc->HFC_inw_nodebug(hc, reg, __func__, __LINE__)) | ||
| 237 | #define HFC_wait(hc) \ | ||
| 238 | (hc->HFC_wait(hc, __func__, __LINE__)) | ||
| 239 | #define HFC_wait_nodebug(hc) \ | ||
| 240 | (hc->HFC_wait_nodebug(hc, __func__, __LINE__)) | ||
| 241 | #else | ||
| 242 | #define HFC_outb(hc, reg, val) (hc->HFC_outb(hc, reg, val)) | ||
| 243 | #define HFC_outb_nodebug(hc, reg, val) (hc->HFC_outb_nodebug(hc, reg, val)) | ||
| 244 | #define HFC_inb(hc, reg) (hc->HFC_inb(hc, reg)) | ||
| 245 | #define HFC_inb_nodebug(hc, reg) (hc->HFC_inb_nodebug(hc, reg)) | ||
| 246 | #define HFC_inw(hc, reg) (hc->HFC_inw(hc, reg)) | ||
| 247 | #define HFC_inw_nodebug(hc, reg) (hc->HFC_inw_nodebug(hc, reg)) | ||
| 248 | #define HFC_wait(hc) (hc->HFC_wait(hc)) | ||
| 249 | #define HFC_wait_nodebug(hc) (hc->HFC_wait_nodebug(hc)) | ||
| 250 | #endif | ||
| 251 | |||
| 252 | /* HFC_IO_MODE_PCIMEM */ | ||
| 253 | static void | ||
| 254 | #ifdef HFC_REGISTER_DEBUG | ||
| 255 | HFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val, | ||
| 256 | const char *function, int line) | ||
| 257 | #else | ||
| 258 | HFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val) | ||
| 259 | #endif | ||
| 260 | { | ||
| 261 | writeb(val, (hc->pci_membase)+reg); | ||
| 262 | } | ||
| 263 | static u_char | ||
| 264 | #ifdef HFC_REGISTER_DEBUG | ||
| 265 | HFC_inb_pcimem(struct hfc_multi *hc, u_char reg, const char *function, int line) | ||
| 266 | #else | ||
| 267 | HFC_inb_pcimem(struct hfc_multi *hc, u_char reg) | ||
| 268 | #endif | ||
| 269 | { | ||
| 270 | return readb((hc->pci_membase)+reg); | ||
| 271 | } | ||
| 272 | static u_short | ||
| 273 | #ifdef HFC_REGISTER_DEBUG | ||
| 274 | HFC_inw_pcimem(struct hfc_multi *hc, u_char reg, const char *function, int line) | ||
| 275 | #else | ||
| 276 | HFC_inw_pcimem(struct hfc_multi *hc, u_char reg) | ||
| 277 | #endif | ||
| 278 | { | ||
| 279 | return readw((hc->pci_membase)+reg); | ||
| 280 | } | ||
| 281 | static void | ||
| 282 | #ifdef HFC_REGISTER_DEBUG | ||
| 283 | HFC_wait_pcimem(struct hfc_multi *hc, const char *function, int line) | ||
| 284 | #else | ||
| 285 | HFC_wait_pcimem(struct hfc_multi *hc) | ||
| 286 | #endif | ||
| 287 | { | ||
| 288 | while (readb((hc->pci_membase)+R_STATUS) & V_BUSY); | ||
| 289 | } | ||
| 290 | |||
| 291 | /* HFC_IO_MODE_REGIO */ | ||
| 292 | static void | ||
| 293 | #ifdef HFC_REGISTER_DEBUG | ||
| 294 | HFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val, | ||
| 295 | const char *function, int line) | ||
| 296 | #else | ||
| 297 | HFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val) | ||
| 298 | #endif | ||
| 299 | { | ||
| 300 | outb(reg, (hc->pci_iobase)+4); | ||
| 301 | outb(val, hc->pci_iobase); | ||
| 302 | } | ||
| 303 | static u_char | ||
| 304 | #ifdef HFC_REGISTER_DEBUG | ||
| 305 | HFC_inb_regio(struct hfc_multi *hc, u_char reg, const char *function, int line) | ||
| 306 | #else | ||
| 307 | HFC_inb_regio(struct hfc_multi *hc, u_char reg) | ||
| 308 | #endif | ||
| 309 | { | ||
| 310 | outb(reg, (hc->pci_iobase)+4); | ||
| 311 | return inb(hc->pci_iobase); | ||
| 312 | } | ||
| 313 | static u_short | ||
| 314 | #ifdef HFC_REGISTER_DEBUG | ||
| 315 | HFC_inw_regio(struct hfc_multi *hc, u_char reg, const char *function, int line) | ||
| 316 | #else | ||
| 317 | HFC_inw_regio(struct hfc_multi *hc, u_char reg) | ||
| 318 | #endif | ||
| 319 | { | ||
| 320 | outb(reg, (hc->pci_iobase)+4); | ||
| 321 | return inw(hc->pci_iobase); | ||
| 322 | } | ||
| 323 | static void | ||
| 324 | #ifdef HFC_REGISTER_DEBUG | ||
| 325 | HFC_wait_regio(struct hfc_multi *hc, const char *function, int line) | ||
| 326 | #else | ||
| 327 | HFC_wait_regio(struct hfc_multi *hc) | ||
| 328 | #endif | ||
| 329 | { | ||
| 330 | outb(R_STATUS, (hc->pci_iobase)+4); | ||
| 331 | while (inb(hc->pci_iobase) & V_BUSY); | ||
| 332 | } | ||
| 333 | |||
| 334 | #ifdef HFC_REGISTER_DEBUG | ||
| 335 | static void | ||
| 336 | HFC_outb_debug(struct hfc_multi *hc, u_char reg, u_char val, | ||
| 337 | const char *function, int line) | ||
| 338 | { | ||
| 339 | char regname[256] = "", bits[9] = "xxxxxxxx"; | ||
| 340 | int i; | ||
| 341 | |||
| 342 | i = -1; | ||
| 343 | while (hfc_register_names[++i].name) { | ||
| 344 | if (hfc_register_names[i].reg == reg) | ||
| 345 | strcat(regname, hfc_register_names[i].name); | ||
| 346 | } | ||
| 347 | if (regname[0] == '\0') | ||
| 348 | strcpy(regname, "register"); | ||
| 349 | |||
| 350 | bits[7] = '0'+(!!(val&1)); | ||
| 351 | bits[6] = '0'+(!!(val&2)); | ||
| 352 | bits[5] = '0'+(!!(val&4)); | ||
| 353 | bits[4] = '0'+(!!(val&8)); | ||
| 354 | bits[3] = '0'+(!!(val&16)); | ||
| 355 | bits[2] = '0'+(!!(val&32)); | ||
| 356 | bits[1] = '0'+(!!(val&64)); | ||
| 357 | bits[0] = '0'+(!!(val&128)); | ||
| 358 | printk(KERN_DEBUG | ||
| 359 | "HFC_outb(chip %d, %02x=%s, 0x%02x=%s); in %s() line %d\n", | ||
| 360 | hc->id, reg, regname, val, bits, function, line); | ||
| 361 | HFC_outb_nodebug(hc, reg, val); | ||
| 362 | } | ||
| 363 | static u_char | ||
| 364 | HFC_inb_debug(struct hfc_multi *hc, u_char reg, const char *function, int line) | ||
| 365 | { | ||
| 366 | char regname[256] = "", bits[9] = "xxxxxxxx"; | ||
| 367 | u_char val = HFC_inb_nodebug(hc, reg); | ||
| 368 | int i; | ||
| 369 | |||
| 370 | i = 0; | ||
| 371 | while (hfc_register_names[i++].name) | ||
| 372 | ; | ||
| 373 | while (hfc_register_names[++i].name) { | ||
| 374 | if (hfc_register_names[i].reg == reg) | ||
| 375 | strcat(regname, hfc_register_names[i].name); | ||
| 376 | } | ||
| 377 | if (regname[0] == '\0') | ||
| 378 | strcpy(regname, "register"); | ||
| 379 | |||
| 380 | bits[7] = '0'+(!!(val&1)); | ||
| 381 | bits[6] = '0'+(!!(val&2)); | ||
| 382 | bits[5] = '0'+(!!(val&4)); | ||
| 383 | bits[4] = '0'+(!!(val&8)); | ||
| 384 | bits[3] = '0'+(!!(val&16)); | ||
| 385 | bits[2] = '0'+(!!(val&32)); | ||
| 386 | bits[1] = '0'+(!!(val&64)); | ||
| 387 | bits[0] = '0'+(!!(val&128)); | ||
| 388 | printk(KERN_DEBUG | ||
| 389 | "HFC_inb(chip %d, %02x=%s) = 0x%02x=%s; in %s() line %d\n", | ||
| 390 | hc->id, reg, regname, val, bits, function, line); | ||
| 391 | return val; | ||
| 392 | } | ||
| 393 | static u_short | ||
| 394 | HFC_inw_debug(struct hfc_multi *hc, u_char reg, const char *function, int line) | ||
| 395 | { | ||
| 396 | char regname[256] = ""; | ||
| 397 | u_short val = HFC_inw_nodebug(hc, reg); | ||
| 398 | int i; | ||
| 399 | |||
| 400 | i = 0; | ||
| 401 | while (hfc_register_names[i++].name) | ||
| 402 | ; | ||
| 403 | while (hfc_register_names[++i].name) { | ||
| 404 | if (hfc_register_names[i].reg == reg) | ||
| 405 | strcat(regname, hfc_register_names[i].name); | ||
| 406 | } | ||
| 407 | if (regname[0] == '\0') | ||
| 408 | strcpy(regname, "register"); | ||
| 409 | |||
| 410 | printk(KERN_DEBUG | ||
| 411 | "HFC_inw(chip %d, %02x=%s) = 0x%04x; in %s() line %d\n", | ||
| 412 | hc->id, reg, regname, val, function, line); | ||
| 413 | return val; | ||
| 414 | } | ||
| 415 | static void | ||
| 416 | HFC_wait_debug(struct hfc_multi *hc, const char *function, int line) | ||
| 417 | { | ||
| 418 | printk(KERN_DEBUG "HFC_wait(chip %d); in %s() line %d\n", | ||
| 419 | hc->id, function, line); | ||
| 420 | HFC_wait_nodebug(hc); | ||
| 421 | } | ||
| 422 | #endif | ||
| 423 | |||
| 424 | /* write fifo data (REGIO) */ | ||
| 425 | void | ||
| 426 | write_fifo_regio(struct hfc_multi *hc, u_char *data, int len) | ||
| 427 | { | ||
| 428 | outb(A_FIFO_DATA0, (hc->pci_iobase)+4); | ||
| 429 | while (len>>2) { | ||
| 430 | outl(*(u32 *)data, hc->pci_iobase); | ||
| 431 | data += 4; | ||
| 432 | len -= 4; | ||
| 433 | } | ||
| 434 | while (len>>1) { | ||
| 435 | outw(*(u16 *)data, hc->pci_iobase); | ||
| 436 | data += 2; | ||
| 437 | len -= 2; | ||
| 438 | } | ||
| 439 | while (len) { | ||
| 440 | outb(*data, hc->pci_iobase); | ||
| 441 | data++; | ||
| 442 | len--; | ||
| 443 | } | ||
| 444 | } | ||
| 445 | /* write fifo data (PCIMEM) */ | ||
| 446 | void | ||
| 447 | write_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) | ||
| 448 | { | ||
| 449 | while (len>>2) { | ||
| 450 | writel(*(u32 *)data, (hc->pci_membase)+A_FIFO_DATA0); | ||
| 451 | data += 4; | ||
| 452 | len -= 4; | ||
| 453 | } | ||
| 454 | while (len>>1) { | ||
| 455 | writew(*(u16 *)data, (hc->pci_membase)+A_FIFO_DATA0); | ||
| 456 | data += 2; | ||
| 457 | len -= 2; | ||
| 458 | } | ||
| 459 | while (len) { | ||
| 460 | writeb(*data, (hc->pci_membase)+A_FIFO_DATA0); | ||
| 461 | data++; | ||
| 462 | len--; | ||
| 463 | } | ||
| 464 | } | ||
| 465 | /* read fifo data (REGIO) */ | ||
| 466 | void | ||
| 467 | read_fifo_regio(struct hfc_multi *hc, u_char *data, int len) | ||
| 468 | { | ||
| 469 | outb(A_FIFO_DATA0, (hc->pci_iobase)+4); | ||
| 470 | while (len>>2) { | ||
| 471 | *(u32 *)data = inl(hc->pci_iobase); | ||
| 472 | data += 4; | ||
| 473 | len -= 4; | ||
| 474 | } | ||
| 475 | while (len>>1) { | ||
| 476 | *(u16 *)data = inw(hc->pci_iobase); | ||
| 477 | data += 2; | ||
| 478 | len -= 2; | ||
| 479 | } | ||
| 480 | while (len) { | ||
| 481 | *data = inb(hc->pci_iobase); | ||
| 482 | data++; | ||
| 483 | len--; | ||
| 484 | } | ||
| 485 | } | ||
| 486 | |||
| 487 | /* read fifo data (PCIMEM) */ | ||
| 488 | void | ||
| 489 | read_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) | ||
| 490 | { | ||
| 491 | while (len>>2) { | ||
| 492 | *(u32 *)data = | ||
| 493 | readl((hc->pci_membase)+A_FIFO_DATA0); | ||
| 494 | data += 4; | ||
| 495 | len -= 4; | ||
| 496 | } | ||
| 497 | while (len>>1) { | ||
| 498 | *(u16 *)data = | ||
| 499 | readw((hc->pci_membase)+A_FIFO_DATA0); | ||
| 500 | data += 2; | ||
| 501 | len -= 2; | ||
| 502 | } | ||
| 503 | while (len) { | ||
| 504 | *data = readb((hc->pci_membase)+A_FIFO_DATA0); | ||
| 505 | data++; | ||
| 506 | len--; | ||
| 507 | } | ||
| 508 | } | ||
| 509 | |||
| 510 | |||
| 511 | static void | ||
| 512 | enable_hwirq(struct hfc_multi *hc) | ||
| 513 | { | ||
| 514 | hc->hw.r_irq_ctrl |= V_GLOB_IRQ_EN; | ||
| 515 | HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl); | ||
| 516 | } | ||
| 517 | |||
| 518 | static void | ||
| 519 | disable_hwirq(struct hfc_multi *hc) | ||
| 520 | { | ||
| 521 | hc->hw.r_irq_ctrl &= ~((u_char)V_GLOB_IRQ_EN); | ||
| 522 | HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl); | ||
| 523 | } | ||
| 524 | |||
| 525 | #define NUM_EC 2 | ||
| 526 | #define MAX_TDM_CHAN 32 | ||
| 527 | |||
| 528 | |||
| 529 | inline void | ||
| 530 | enablepcibridge(struct hfc_multi *c) | ||
| 531 | { | ||
| 532 | HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x3); /* was _io before */ | ||
| 533 | } | ||
| 534 | |||
| 535 | inline void | ||
| 536 | disablepcibridge(struct hfc_multi *c) | ||
| 537 | { | ||
| 538 | HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x2); /* was _io before */ | ||
| 539 | } | ||
| 540 | |||
| 541 | inline unsigned char | ||
| 542 | readpcibridge(struct hfc_multi *hc, unsigned char address) | ||
| 543 | { | ||
| 544 | unsigned short cipv; | ||
| 545 | unsigned char data; | ||
| 546 | |||
| 547 | if (!hc->pci_iobase) | ||
| 548 | return 0; | ||
| 549 | |||
| 550 | /* slow down a PCI read access by 1 PCI clock cycle */ | ||
| 551 | HFC_outb(hc, R_CTRL, 0x4); /*was _io before*/ | ||
| 552 | |||
| 553 | if (address == 0) | ||
| 554 | cipv = 0x4000; | ||
| 555 | else | ||
| 556 | cipv = 0x5800; | ||
| 557 | |||
| 558 | /* select local bridge port address by writing to CIP port */ | ||
| 559 | /* data = HFC_inb(c, cipv); * was _io before */ | ||
| 560 | outw(cipv, hc->pci_iobase + 4); | ||
| 561 | data = inb(hc->pci_iobase); | ||
| 562 | |||
| 563 | /* restore R_CTRL for normal PCI read cycle speed */ | ||
| 564 | HFC_outb(hc, R_CTRL, 0x0); /* was _io before */ | ||
| 565 | |||
| 566 | return data; | ||
| 567 | } | ||
| 568 | |||
| 569 | inline void | ||
| 570 | writepcibridge(struct hfc_multi *hc, unsigned char address, unsigned char data) | ||
| 571 | { | ||
| 572 | unsigned short cipv; | ||
| 573 | unsigned int datav; | ||
| 574 | |||
| 575 | if (!hc->pci_iobase) | ||
| 576 | return; | ||
| 577 | |||
| 578 | if (address == 0) | ||
| 579 | cipv = 0x4000; | ||
| 580 | else | ||
| 581 | cipv = 0x5800; | ||
| 582 | |||
| 583 | /* select local bridge port address by writing to CIP port */ | ||
| 584 | outw(cipv, hc->pci_iobase + 4); | ||
| 585 | /* define a 32 bit dword with 4 identical bytes for write sequence */ | ||
| 586 | datav = data | ((__u32) data << 8) | ((__u32) data << 16) | | ||
| 587 | ((__u32) data << 24); | ||
| 588 | |||
| 589 | /* | ||
| 590 | * write this 32 bit dword to the bridge data port | ||
| 591 | * this will initiate a write sequence of up to 4 writes to the same | ||
| 592 | * address on the local bus interface the number of write accesses | ||
| 593 | * is undefined but >=1 and depends on the next PCI transaction | ||
| 594 | * during write sequence on the local bus | ||
| 595 | */ | ||
| 596 | outl(datav, hc->pci_iobase); | ||
| 597 | } | ||
| 598 | |||
| 599 | inline void | ||
| 600 | cpld_set_reg(struct hfc_multi *hc, unsigned char reg) | ||
| 601 | { | ||
| 602 | /* Do data pin read low byte */ | ||
| 603 | HFC_outb(hc, R_GPIO_OUT1, reg); | ||
| 604 | } | ||
| 605 | |||
| 606 | inline void | ||
| 607 | cpld_write_reg(struct hfc_multi *hc, unsigned char reg, unsigned char val) | ||
| 608 | { | ||
| 609 | cpld_set_reg(hc, reg); | ||
| 610 | |||
| 611 | enablepcibridge(hc); | ||
| 612 | writepcibridge(hc, 1, val); | ||
| 613 | disablepcibridge(hc); | ||
| 614 | |||
| 615 | return; | ||
| 616 | } | ||
| 617 | |||
| 618 | inline unsigned char | ||
| 619 | cpld_read_reg(struct hfc_multi *hc, unsigned char reg) | ||
| 620 | { | ||
| 621 | unsigned char bytein; | ||
| 622 | |||
| 623 | cpld_set_reg(hc, reg); | ||
| 624 | |||
| 625 | /* Do data pin read low byte */ | ||
| 626 | HFC_outb(hc, R_GPIO_OUT1, reg); | ||
| 627 | |||
| 628 | enablepcibridge(hc); | ||
| 629 | bytein = readpcibridge(hc, 1); | ||
| 630 | disablepcibridge(hc); | ||
| 631 | |||
| 632 | return bytein; | ||
| 633 | } | ||
| 634 | |||
| 635 | inline void | ||
| 636 | vpm_write_address(struct hfc_multi *hc, unsigned short addr) | ||
| 637 | { | ||
| 638 | cpld_write_reg(hc, 0, 0xff & addr); | ||
| 639 | cpld_write_reg(hc, 1, 0x01 & (addr >> 8)); | ||
| 640 | } | ||
| 641 | |||
| 642 | inline unsigned short | ||
| 643 | vpm_read_address(struct hfc_multi *c) | ||
| 644 | { | ||
| 645 | unsigned short addr; | ||
| 646 | unsigned short highbit; | ||
| 647 | |||
| 648 | addr = cpld_read_reg(c, 0); | ||
| 649 | highbit = cpld_read_reg(c, 1); | ||
| 650 | |||
| 651 | addr = addr | (highbit << 8); | ||
| 652 | |||
| 653 | return addr & 0x1ff; | ||
| 654 | } | ||
| 655 | |||
| 656 | inline unsigned char | ||
| 657 | vpm_in(struct hfc_multi *c, int which, unsigned short addr) | ||
| 658 | { | ||
| 659 | unsigned char res; | ||
| 660 | |||
| 661 | vpm_write_address(c, addr); | ||
| 662 | |||
| 663 | if (!which) | ||
| 664 | cpld_set_reg(c, 2); | ||
| 665 | else | ||
| 666 | cpld_set_reg(c, 3); | ||
| 667 | |||
| 668 | enablepcibridge(c); | ||
| 669 | res = readpcibridge(c, 1); | ||
| 670 | disablepcibridge(c); | ||
| 671 | |||
| 672 | cpld_set_reg(c, 0); | ||
| 673 | |||
| 674 | return res; | ||
| 675 | } | ||
| 676 | |||
| 677 | inline void | ||
| 678 | vpm_out(struct hfc_multi *c, int which, unsigned short addr, | ||
| 679 | unsigned char data) | ||
| 680 | { | ||
| 681 | vpm_write_address(c, addr); | ||
| 682 | |||
| 683 | enablepcibridge(c); | ||
| 684 | |||
| 685 | if (!which) | ||
| 686 | cpld_set_reg(c, 2); | ||
| 687 | else | ||
| 688 | cpld_set_reg(c, 3); | ||
| 689 | |||
| 690 | writepcibridge(c, 1, data); | ||
| 691 | |||
| 692 | cpld_set_reg(c, 0); | ||
| 693 | |||
| 694 | disablepcibridge(c); | ||
| 695 | |||
| 696 | { | ||
| 697 | unsigned char regin; | ||
| 698 | regin = vpm_in(c, which, addr); | ||
| 699 | if (regin != data) | ||
| 700 | printk(KERN_DEBUG "Wrote 0x%x to register 0x%x but got back " | ||
| 701 | "0x%x\n", data, addr, regin); | ||
| 702 | } | ||
| 703 | |||
| 704 | } | ||
| 705 | |||
| 706 | |||
| 707 | void | ||
| 708 | vpm_init(struct hfc_multi *wc) | ||
| 709 | { | ||
| 710 | unsigned char reg; | ||
| 711 | unsigned int mask; | ||
| 712 | unsigned int i, x, y; | ||
| 713 | unsigned int ver; | ||
| 714 | |||
| 715 | for (x = 0; x < NUM_EC; x++) { | ||
| 716 | /* Setup GPIO's */ | ||
| 717 | if (!x) { | ||
| 718 | ver = vpm_in(wc, x, 0x1a0); | ||
| 719 | printk(KERN_DEBUG "VPM: Chip %d: ver %02x\n", x, ver); | ||
| 720 | } | ||
| 721 | |||
| 722 | for (y = 0; y < 4; y++) { | ||
| 723 | vpm_out(wc, x, 0x1a8 + y, 0x00); /* GPIO out */ | ||
| 724 | vpm_out(wc, x, 0x1ac + y, 0x00); /* GPIO dir */ | ||
| 725 | vpm_out(wc, x, 0x1b0 + y, 0x00); /* GPIO sel */ | ||
| 726 | } | ||
| 727 | |||
| 728 | /* Setup TDM path - sets fsync and tdm_clk as inputs */ | ||
| 729 | reg = vpm_in(wc, x, 0x1a3); /* misc_con */ | ||
| 730 | vpm_out(wc, x, 0x1a3, reg & ~2); | ||
| 731 | |||
| 732 | /* Setup Echo length (256 taps) */ | ||
| 733 | vpm_out(wc, x, 0x022, 1); | ||
| 734 | vpm_out(wc, x, 0x023, 0xff); | ||
| 735 | |||
| 736 | /* Setup timeslots */ | ||
| 737 | vpm_out(wc, x, 0x02f, 0x00); | ||
| 738 | mask = 0x02020202 << (x * 4); | ||
| 739 | |||
| 740 | /* Setup the tdm channel masks for all chips */ | ||
| 741 | for (i = 0; i < 4; i++) | ||
| 742 | vpm_out(wc, x, 0x33 - i, (mask >> (i << 3)) & 0xff); | ||
| 743 | |||
| 744 | /* Setup convergence rate */ | ||
| 745 | printk(KERN_DEBUG "VPM: A-law mode\n"); | ||
| 746 | reg = 0x00 | 0x10 | 0x01; | ||
| 747 | vpm_out(wc, x, 0x20, reg); | ||
| 748 | printk(KERN_DEBUG "VPM reg 0x20 is %x\n", reg); | ||
| 749 | /*vpm_out(wc, x, 0x20, (0x00 | 0x08 | 0x20 | 0x10)); */ | ||
| 750 | |||
| 751 | vpm_out(wc, x, 0x24, 0x02); | ||
| 752 | reg = vpm_in(wc, x, 0x24); | ||
| 753 | printk(KERN_DEBUG "NLP Thresh is set to %d (0x%x)\n", reg, reg); | ||
| 754 | |||
| 755 | /* Initialize echo cans */ | ||
| 756 | for (i = 0; i < MAX_TDM_CHAN; i++) { | ||
| 757 | if (mask & (0x00000001 << i)) | ||
| 758 | vpm_out(wc, x, i, 0x00); | ||
| 759 | } | ||
| 760 | |||
| 761 | /* | ||
| 762 | * ARM arch at least disallows a udelay of | ||
| 763 | * more than 2ms... it gives a fake "__bad_udelay" | ||
| 764 | * reference at link-time. | ||
| 765 | * long delays in kernel code are pretty sucky anyway | ||
| 766 | * for now work around it using 5 x 2ms instead of 1 x 10ms | ||
| 767 | */ | ||
| 768 | |||
| 769 | udelay(2000); | ||
| 770 | udelay(2000); | ||
| 771 | udelay(2000); | ||
| 772 | udelay(2000); | ||
| 773 | udelay(2000); | ||
| 774 | |||
| 775 | /* Put in bypass mode */ | ||
| 776 | for (i = 0; i < MAX_TDM_CHAN; i++) { | ||
| 777 | if (mask & (0x00000001 << i)) | ||
| 778 | vpm_out(wc, x, i, 0x01); | ||
| 779 | } | ||
| 780 | |||
| 781 | /* Enable bypass */ | ||
| 782 | for (i = 0; i < MAX_TDM_CHAN; i++) { | ||
| 783 | if (mask & (0x00000001 << i)) | ||
| 784 | vpm_out(wc, x, 0x78 + i, 0x01); | ||
| 785 | } | ||
| 786 | |||
| 787 | } | ||
| 788 | } | ||
| 789 | |||
| 790 | void | ||
| 791 | vpm_check(struct hfc_multi *hctmp) | ||
| 792 | { | ||
| 793 | unsigned char gpi2; | ||
| 794 | |||
| 795 | gpi2 = HFC_inb(hctmp, R_GPI_IN2); | ||
| 796 | |||
| 797 | if ((gpi2 & 0x3) != 0x3) | ||
| 798 | printk(KERN_DEBUG "Got interrupt 0x%x from VPM!\n", gpi2); | ||
| 799 | } | ||
| 800 | |||
| 801 | |||
| 802 | /* | ||
| 803 | * Interface to enable/disable the HW Echocan | ||
| 804 | * | ||
| 805 | * these functions are called within a spin_lock_irqsave on | ||
| 806 | * the channel instance lock, so we are not disturbed by irqs | ||
| 807 | * | ||
| 808 | * we can later easily change the interface to make other | ||
| 809 | * things configurable, for now we configure the taps | ||
| 810 | * | ||
| 811 | */ | ||
| 812 | |||
| 813 | void | ||
| 814 | vpm_echocan_on(struct hfc_multi *hc, int ch, int taps) | ||
| 815 | { | ||
| 816 | unsigned int timeslot; | ||
| 817 | unsigned int unit; | ||
| 818 | struct bchannel *bch = hc->chan[ch].bch; | ||
| 819 | #ifdef TXADJ | ||
| 820 | int txadj = -4; | ||
| 821 | struct sk_buff *skb; | ||
| 822 | #endif | ||
| 823 | if (hc->chan[ch].protocol != ISDN_P_B_RAW) | ||
| 824 | return; | ||
| 825 | |||
| 826 | if (!bch) | ||
| 827 | return; | ||
| 828 | |||
| 829 | #ifdef TXADJ | ||
| 830 | skb = _alloc_mISDN_skb(PH_CONTROL_IND, HFC_VOL_CHANGE_TX, | ||
| 831 | sizeof(int), &txadj, GFP_ATOMIC); | ||
| 832 | if (skb) | ||
| 833 | recv_Bchannel_skb(bch, skb); | ||
| 834 | #endif | ||
| 835 | |||
| 836 | timeslot = ((ch/4)*8) + ((ch%4)*4) + 1; | ||
| 837 | unit = ch % 4; | ||
| 838 | |||
| 839 | printk(KERN_NOTICE "vpm_echocan_on called taps [%d] on timeslot %d\n", | ||
| 840 | taps, timeslot); | ||
| 841 | |||
| 842 | vpm_out(hc, unit, timeslot, 0x7e); | ||
| 843 | } | ||
| 844 | |||
| 845 | void | ||
| 846 | vpm_echocan_off(struct hfc_multi *hc, int ch) | ||
| 847 | { | ||
| 848 | unsigned int timeslot; | ||
| 849 | unsigned int unit; | ||
| 850 | struct bchannel *bch = hc->chan[ch].bch; | ||
| 851 | #ifdef TXADJ | ||
| 852 | int txadj = 0; | ||
| 853 | struct sk_buff *skb; | ||
| 854 | #endif | ||
| 855 | |||
| 856 | if (hc->chan[ch].protocol != ISDN_P_B_RAW) | ||
| 857 | return; | ||
| 858 | |||
| 859 | if (!bch) | ||
| 860 | return; | ||
| 861 | |||
| 862 | #ifdef TXADJ | ||
| 863 | skb = _alloc_mISDN_skb(PH_CONTROL_IND, HFC_VOL_CHANGE_TX, | ||
| 864 | sizeof(int), &txadj, GFP_ATOMIC); | ||
| 865 | if (skb) | ||
| 866 | recv_Bchannel_skb(bch, skb); | ||
| 867 | #endif | ||
| 868 | |||
| 869 | timeslot = ((ch/4)*8) + ((ch%4)*4) + 1; | ||
| 870 | unit = ch % 4; | ||
| 871 | |||
| 872 | printk(KERN_NOTICE "vpm_echocan_off called on timeslot %d\n", | ||
| 873 | timeslot); | ||
| 874 | /* FILLME */ | ||
| 875 | vpm_out(hc, unit, timeslot, 0x01); | ||
| 876 | } | ||
| 877 | |||
| 878 | |||
| 879 | /* | ||
| 880 | * Speech Design resync feature | ||
| 881 | * NOTE: This is called sometimes outside interrupt handler. | ||
| 882 | * We must lock irqsave, so no other interrupt (other card) will occurr! | ||
| 883 | * Also multiple interrupts may nest, so must lock each access (lists, card)! | ||
| 884 | */ | ||
| 885 | static inline void | ||
| 886 | hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) | ||
| 887 | { | ||
| 888 | struct hfc_multi *hc, *next, *pcmmaster = 0; | ||
| 889 | u_int *plx_acc_32, pv; | ||
| 890 | u_long flags; | ||
| 891 | |||
| 892 | spin_lock_irqsave(&HFClock, flags); | ||
| 893 | spin_lock(&plx_lock); /* must be locked inside other locks */ | ||
| 894 | |||
| 895 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
| 896 | printk(KERN_DEBUG "%s: RESYNC(syncmaster=0x%p)\n", | ||
| 897 | __func__, syncmaster); | ||
| 898 | |||
| 899 | /* select new master */ | ||
| 900 | if (newmaster) { | ||
| 901 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
| 902 | printk(KERN_DEBUG "using provided controller\n"); | ||
| 903 | } else { | ||
| 904 | list_for_each_entry_safe(hc, next, &HFClist, list) { | ||
| 905 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
| 906 | if (hc->syncronized) { | ||
| 907 | newmaster = hc; | ||
| 908 | break; | ||
| 909 | } | ||
| 910 | } | ||
| 911 | } | ||
| 912 | } | ||
| 913 | |||
| 914 | /* Disable sync of all cards */ | ||
| 915 | list_for_each_entry_safe(hc, next, &HFClist, list) { | ||
| 916 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
| 917 | plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); | ||
| 918 | pv = readl(plx_acc_32); | ||
| 919 | pv &= ~PLX_SYNC_O_EN; | ||
| 920 | writel(pv, plx_acc_32); | ||
| 921 | if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) { | ||
| 922 | pcmmaster = hc; | ||
| 923 | if (hc->type == 1) { | ||
| 924 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
| 925 | printk(KERN_DEBUG | ||
| 926 | "Schedule SYNC_I\n"); | ||
| 927 | hc->e1_resync |= 1; /* get SYNC_I */ | ||
| 928 | } | ||
| 929 | } | ||
| 930 | } | ||
| 931 | } | ||
| 932 | |||
| 933 | if (newmaster) { | ||
| 934 | hc = newmaster; | ||
| 935 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
| 936 | printk(KERN_DEBUG "id=%d (0x%p) = syncronized with " | ||
| 937 | "interface.\n", hc->id, hc); | ||
| 938 | /* Enable new sync master */ | ||
| 939 | plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); | ||
| 940 | pv = readl(plx_acc_32); | ||
| 941 | pv |= PLX_SYNC_O_EN; | ||
| 942 | writel(pv, plx_acc_32); | ||
| 943 | /* switch to jatt PLL, if not disabled by RX_SYNC */ | ||
| 944 | if (hc->type == 1 && !test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) { | ||
| 945 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
| 946 | printk(KERN_DEBUG "Schedule jatt PLL\n"); | ||
| 947 | hc->e1_resync |= 2; /* switch to jatt */ | ||
| 948 | } | ||
| 949 | } else { | ||
| 950 | if (pcmmaster) { | ||
| 951 | hc = pcmmaster; | ||
| 952 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
| 953 | printk(KERN_DEBUG | ||
| 954 | "id=%d (0x%p) = PCM master syncronized " | ||
| 955 | "with QUARTZ\n", hc->id, hc); | ||
| 956 | if (hc->type == 1) { | ||
| 957 | /* Use the crystal clock for the PCM | ||
| 958 | master card */ | ||
| 959 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
| 960 | printk(KERN_DEBUG | ||
| 961 | "Schedule QUARTZ for HFC-E1\n"); | ||
| 962 | hc->e1_resync |= 4; /* switch quartz */ | ||
| 963 | } else { | ||
| 964 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
| 965 | printk(KERN_DEBUG | ||
| 966 | "QUARTZ is automatically " | ||
| 967 | "enabled by HFC-%dS\n", hc->type); | ||
| 968 | } | ||
| 969 | plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); | ||
| 970 | pv = readl(plx_acc_32); | ||
| 971 | pv |= PLX_SYNC_O_EN; | ||
| 972 | writel(pv, plx_acc_32); | ||
| 973 | } else | ||
| 974 | if (!rm) | ||
| 975 | printk(KERN_ERR "%s no pcm master, this MUST " | ||
| 976 | "not happen!\n", __func__); | ||
| 977 | } | ||
| 978 | syncmaster = newmaster; | ||
| 979 | |||
| 980 | spin_unlock(&plx_lock); | ||
| 981 | spin_unlock_irqrestore(&HFClock, flags); | ||
| 982 | } | ||
| 983 | |||
| 984 | /* This must be called AND hc must be locked irqsave!!! */ | ||
| 985 | inline void | ||
| 986 | plxsd_checksync(struct hfc_multi *hc, int rm) | ||
| 987 | { | ||
| 988 | if (hc->syncronized) { | ||
| 989 | if (syncmaster == NULL) { | ||
| 990 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
| 991 | printk(KERN_WARNING "%s: GOT sync on card %d" | ||
| 992 | " (id=%d)\n", __func__, hc->id + 1, | ||
| 993 | hc->id); | ||
| 994 | hfcmulti_resync(hc, hc, rm); | ||
| 995 | } | ||
| 996 | } else { | ||
| 997 | if (syncmaster == hc) { | ||
| 998 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
| 999 | printk(KERN_WARNING "%s: LOST sync on card %d" | ||
| 1000 | " (id=%d)\n", __func__, hc->id + 1, | ||
| 1001 | hc->id); | ||
| 1002 | hfcmulti_resync(hc, NULL, rm); | ||
| 1003 | } | ||
| 1004 | } | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | |||
| 1008 | /* | ||
| 1009 | * free hardware resources used by driver | ||
| 1010 | */ | ||
| 1011 | static void | ||
| 1012 | release_io_hfcmulti(struct hfc_multi *hc) | ||
| 1013 | { | ||
| 1014 | u_int *plx_acc_32, pv; | ||
| 1015 | u_long plx_flags; | ||
| 1016 | |||
| 1017 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1018 | printk(KERN_DEBUG "%s: entered\n", __func__); | ||
| 1019 | |||
| 1020 | /* soft reset also masks all interrupts */ | ||
| 1021 | hc->hw.r_cirm |= V_SRES; | ||
| 1022 | HFC_outb(hc, R_CIRM, hc->hw.r_cirm); | ||
| 1023 | udelay(1000); | ||
| 1024 | hc->hw.r_cirm &= ~V_SRES; | ||
| 1025 | HFC_outb(hc, R_CIRM, hc->hw.r_cirm); | ||
| 1026 | udelay(1000); /* instead of 'wait' that may cause locking */ | ||
| 1027 | |||
| 1028 | /* release Speech Design card, if PLX was initialized */ | ||
| 1029 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip) && hc->plx_membase) { | ||
| 1030 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
| 1031 | printk(KERN_DEBUG "%s: release PLXSD card %d\n", | ||
| 1032 | __func__, hc->id + 1); | ||
| 1033 | spin_lock_irqsave(&plx_lock, plx_flags); | ||
| 1034 | plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); | ||
| 1035 | writel(PLX_GPIOC_INIT, plx_acc_32); | ||
| 1036 | pv = readl(plx_acc_32); | ||
| 1037 | /* Termination off */ | ||
| 1038 | pv &= ~PLX_TERM_ON; | ||
| 1039 | /* Disconnect the PCM */ | ||
| 1040 | pv |= PLX_SLAVE_EN_N; | ||
| 1041 | pv &= ~PLX_MASTER_EN; | ||
| 1042 | pv &= ~PLX_SYNC_O_EN; | ||
| 1043 | /* Put the DSP in Reset */ | ||
| 1044 | pv &= ~PLX_DSP_RES_N; | ||
| 1045 | writel(pv, plx_acc_32); | ||
| 1046 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1047 | printk(KERN_WARNING "%s: PCM off: PLX_GPIO=%x\n", | ||
| 1048 | __func__, pv); | ||
| 1049 | spin_unlock_irqrestore(&plx_lock, plx_flags); | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | /* disable memory mapped ports / io ports */ | ||
| 1053 | test_and_clear_bit(HFC_CHIP_PLXSD, &hc->chip); /* prevent resync */ | ||
| 1054 | pci_write_config_word(hc->pci_dev, PCI_COMMAND, 0); | ||
| 1055 | if (hc->pci_membase) | ||
| 1056 | iounmap((void *)hc->pci_membase); | ||
| 1057 | if (hc->plx_membase) | ||
| 1058 | iounmap((void *)hc->plx_membase); | ||
| 1059 | if (hc->pci_iobase) | ||
| 1060 | release_region(hc->pci_iobase, 8); | ||
| 1061 | |||
| 1062 | if (hc->pci_dev) { | ||
| 1063 | pci_disable_device(hc->pci_dev); | ||
| 1064 | pci_set_drvdata(hc->pci_dev, NULL); | ||
| 1065 | } | ||
| 1066 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1067 | printk(KERN_DEBUG "%s: done\n", __func__); | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | /* | ||
| 1071 | * function called to reset the HFC chip. A complete software reset of chip | ||
| 1072 | * and fifos is done. All configuration of the chip is done. | ||
| 1073 | */ | ||
| 1074 | |||
| 1075 | static int | ||
| 1076 | init_chip(struct hfc_multi *hc) | ||
| 1077 | { | ||
| 1078 | u_long flags, val, val2 = 0, rev; | ||
| 1079 | int i, err = 0; | ||
| 1080 | u_char r_conf_en, rval; | ||
| 1081 | u_int *plx_acc_32, pv; | ||
| 1082 | u_long plx_flags, hfc_flags; | ||
| 1083 | int plx_count; | ||
| 1084 | struct hfc_multi *pos, *next, *plx_last_hc; | ||
| 1085 | |||
| 1086 | spin_lock_irqsave(&hc->lock, flags); | ||
| 1087 | /* reset all registers */ | ||
| 1088 | memset(&hc->hw, 0, sizeof(struct hfcm_hw)); | ||
| 1089 | |||
| 1090 | /* revision check */ | ||
| 1091 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1092 | printk(KERN_DEBUG "%s: entered\n", __func__); | ||
| 1093 | val = HFC_inb(hc, R_CHIP_ID)>>4; | ||
| 1094 | if (val != 0x8 && val != 0xc && val != 0xe) { | ||
| 1095 | printk(KERN_INFO "HFC_multi: unknown CHIP_ID:%x\n", (u_int)val); | ||
| 1096 | err = -EIO; | ||
| 1097 | goto out; | ||
| 1098 | } | ||
| 1099 | rev = HFC_inb(hc, R_CHIP_RV); | ||
| 1100 | printk(KERN_INFO | ||
| 1101 | "HFC_multi: detected HFC with chip ID=0x%lx revision=%ld%s\n", | ||
| 1102 | val, rev, (rev == 0) ? " (old FIFO handling)" : ""); | ||
| 1103 | if (rev == 0) { | ||
| 1104 | test_and_set_bit(HFC_CHIP_REVISION0, &hc->chip); | ||
| 1105 | printk(KERN_WARNING | ||
| 1106 | "HFC_multi: NOTE: Your chip is revision 0, " | ||
| 1107 | "ask Cologne Chip for update. Newer chips " | ||
| 1108 | "have a better FIFO handling. Old chips " | ||
| 1109 | "still work but may have slightly lower " | ||
| 1110 | "HDLC transmit performance.\n"); | ||
| 1111 | } | ||
| 1112 | if (rev > 1) { | ||
| 1113 | printk(KERN_WARNING "HFC_multi: WARNING: This driver doesn't " | ||
| 1114 | "consider chip revision = %ld. The chip / " | ||
| 1115 | "bridge may not work.\n", rev); | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | /* set s-ram size */ | ||
| 1119 | hc->Flen = 0x10; | ||
| 1120 | hc->Zmin = 0x80; | ||
| 1121 | hc->Zlen = 384; | ||
| 1122 | hc->DTMFbase = 0x1000; | ||
| 1123 | if (test_bit(HFC_CHIP_EXRAM_128, &hc->chip)) { | ||
| 1124 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1125 | printk(KERN_DEBUG "%s: changing to 128K extenal RAM\n", | ||
| 1126 | __func__); | ||
| 1127 | hc->hw.r_ctrl |= V_EXT_RAM; | ||
| 1128 | hc->hw.r_ram_sz = 1; | ||
| 1129 | hc->Flen = 0x20; | ||
| 1130 | hc->Zmin = 0xc0; | ||
| 1131 | hc->Zlen = 1856; | ||
| 1132 | hc->DTMFbase = 0x2000; | ||
| 1133 | } | ||
| 1134 | if (test_bit(HFC_CHIP_EXRAM_512, &hc->chip)) { | ||
| 1135 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1136 | printk(KERN_DEBUG "%s: changing to 512K extenal RAM\n", | ||
| 1137 | __func__); | ||
| 1138 | hc->hw.r_ctrl |= V_EXT_RAM; | ||
| 1139 | hc->hw.r_ram_sz = 2; | ||
| 1140 | hc->Flen = 0x20; | ||
| 1141 | hc->Zmin = 0xc0; | ||
| 1142 | hc->Zlen = 8000; | ||
| 1143 | hc->DTMFbase = 0x2000; | ||
| 1144 | } | ||
| 1145 | hc->max_trans = poll << 1; | ||
| 1146 | if (hc->max_trans > hc->Zlen) | ||
| 1147 | hc->max_trans = hc->Zlen; | ||
| 1148 | |||
| 1149 | /* Speech Design PLX bridge */ | ||
| 1150 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
| 1151 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
| 1152 | printk(KERN_DEBUG "%s: initializing PLXSD card %d\n", | ||
| 1153 | __func__, hc->id + 1); | ||
| 1154 | spin_lock_irqsave(&plx_lock, plx_flags); | ||
| 1155 | plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); | ||
| 1156 | writel(PLX_GPIOC_INIT, plx_acc_32); | ||
| 1157 | pv = readl(plx_acc_32); | ||
| 1158 | /* The first and the last cards are terminating the PCM bus */ | ||
| 1159 | pv |= PLX_TERM_ON; /* hc is currently the last */ | ||
| 1160 | /* Disconnect the PCM */ | ||
| 1161 | pv |= PLX_SLAVE_EN_N; | ||
| 1162 | pv &= ~PLX_MASTER_EN; | ||
| 1163 | pv &= ~PLX_SYNC_O_EN; | ||
| 1164 | /* Put the DSP in Reset */ | ||
| 1165 | pv &= ~PLX_DSP_RES_N; | ||
| 1166 | writel(pv, plx_acc_32); | ||
| 1167 | spin_unlock_irqrestore(&plx_lock, plx_flags); | ||
| 1168 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1169 | printk(KERN_WARNING "%s: slave/term: PLX_GPIO=%x\n", | ||
| 1170 | __func__, pv); | ||
| 1171 | /* | ||
| 1172 | * If we are the 3rd PLXSD card or higher, we must turn | ||
| 1173 | * termination of last PLXSD card off. | ||
| 1174 | */ | ||
| 1175 | spin_lock_irqsave(&HFClock, hfc_flags); | ||
| 1176 | plx_count = 0; | ||
| 1177 | plx_last_hc = NULL; | ||
| 1178 | list_for_each_entry_safe(pos, next, &HFClist, list) { | ||
| 1179 | if (test_bit(HFC_CHIP_PLXSD, &pos->chip)) { | ||
| 1180 | plx_count++; | ||
| 1181 | if (pos != hc) | ||
| 1182 | plx_last_hc = pos; | ||
| 1183 | } | ||
| 1184 | } | ||
| 1185 | if (plx_count >= 3) { | ||
| 1186 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
| 1187 | printk(KERN_DEBUG "%s: card %d is between, so " | ||
| 1188 | "we disable termination\n", | ||
| 1189 | __func__, plx_last_hc->id + 1); | ||
| 1190 | spin_lock_irqsave(&plx_lock, plx_flags); | ||
| 1191 | plx_acc_32 = (u_int *)(plx_last_hc->plx_membase | ||
| 1192 | + PLX_GPIOC); | ||
| 1193 | pv = readl(plx_acc_32); | ||
| 1194 | pv &= ~PLX_TERM_ON; | ||
| 1195 | writel(pv, plx_acc_32); | ||
| 1196 | spin_unlock_irqrestore(&plx_lock, plx_flags); | ||
| 1197 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1198 | printk(KERN_WARNING "%s: term off: PLX_GPIO=%x\n", | ||
| 1199 | __func__, pv); | ||
| 1200 | } | ||
| 1201 | spin_unlock_irqrestore(&HFClock, hfc_flags); | ||
| 1202 | hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */ | ||
| 1203 | } | ||
| 1204 | |||
| 1205 | /* we only want the real Z2 read-pointer for revision > 0 */ | ||
| 1206 | if (!test_bit(HFC_CHIP_REVISION0, &hc->chip)) | ||
| 1207 | hc->hw.r_ram_sz |= V_FZ_MD; | ||
| 1208 | |||
| 1209 | /* select pcm mode */ | ||
| 1210 | if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { | ||
| 1211 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1212 | printk(KERN_DEBUG "%s: setting PCM into slave mode\n", | ||
| 1213 | __func__); | ||
| 1214 | } else | ||
| 1215 | if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip) && !plxsd_master) { | ||
| 1216 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1217 | printk(KERN_DEBUG "%s: setting PCM into master mode\n", | ||
| 1218 | __func__); | ||
| 1219 | hc->hw.r_pcm_md0 |= V_PCM_MD; | ||
| 1220 | } else { | ||
| 1221 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1222 | printk(KERN_DEBUG "%s: performing PCM auto detect\n", | ||
| 1223 | __func__); | ||
| 1224 | } | ||
| 1225 | |||
| 1226 | /* soft reset */ | ||
| 1227 | HFC_outb(hc, R_CTRL, hc->hw.r_ctrl); | ||
| 1228 | HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); | ||
| 1229 | HFC_outb(hc, R_FIFO_MD, 0); | ||
| 1230 | hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES | V_RLD_EPR; | ||
| 1231 | HFC_outb(hc, R_CIRM, hc->hw.r_cirm); | ||
| 1232 | udelay(100); | ||
| 1233 | hc->hw.r_cirm = 0; | ||
| 1234 | HFC_outb(hc, R_CIRM, hc->hw.r_cirm); | ||
| 1235 | udelay(100); | ||
| 1236 | HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); | ||
| 1237 | |||
| 1238 | /* Speech Design PLX bridge pcm and sync mode */ | ||
| 1239 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
| 1240 | spin_lock_irqsave(&plx_lock, plx_flags); | ||
| 1241 | plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); | ||
| 1242 | pv = readl(plx_acc_32); | ||
| 1243 | /* Connect PCM */ | ||
| 1244 | if (hc->hw.r_pcm_md0 & V_PCM_MD) { | ||
| 1245 | pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N; | ||
| 1246 | pv |= PLX_SYNC_O_EN; | ||
| 1247 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1248 | printk(KERN_WARNING "%s: master: PLX_GPIO=%x\n", | ||
| 1249 | __func__, pv); | ||
| 1250 | } else { | ||
| 1251 | pv &= ~(PLX_MASTER_EN | PLX_SLAVE_EN_N); | ||
| 1252 | pv &= ~PLX_SYNC_O_EN; | ||
| 1253 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1254 | printk(KERN_WARNING "%s: slave: PLX_GPIO=%x\n", | ||
| 1255 | __func__, pv); | ||
| 1256 | } | ||
| 1257 | writel(pv, plx_acc_32); | ||
| 1258 | spin_unlock_irqrestore(&plx_lock, plx_flags); | ||
| 1259 | } | ||
| 1260 | |||
| 1261 | /* PCM setup */ | ||
| 1262 | HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x90); | ||
| 1263 | if (hc->slots == 32) | ||
| 1264 | HFC_outb(hc, R_PCM_MD1, 0x00); | ||
| 1265 | if (hc->slots == 64) | ||
| 1266 | HFC_outb(hc, R_PCM_MD1, 0x10); | ||
| 1267 | if (hc->slots == 128) | ||
| 1268 | HFC_outb(hc, R_PCM_MD1, 0x20); | ||
| 1269 | HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0xa0); | ||
| 1270 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) | ||
| 1271 | HFC_outb(hc, R_PCM_MD2, V_SYNC_SRC); /* sync via SYNC_I / O */ | ||
| 1272 | else | ||
| 1273 | HFC_outb(hc, R_PCM_MD2, 0x00); /* sync from interface */ | ||
| 1274 | HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00); | ||
| 1275 | for (i = 0; i < 256; i++) { | ||
| 1276 | HFC_outb_nodebug(hc, R_SLOT, i); | ||
| 1277 | HFC_outb_nodebug(hc, A_SL_CFG, 0); | ||
| 1278 | HFC_outb_nodebug(hc, A_CONF, 0); | ||
| 1279 | hc->slot_owner[i] = -1; | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | /* set clock speed */ | ||
| 1283 | if (test_bit(HFC_CHIP_CLOCK2, &hc->chip)) { | ||
| 1284 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1285 | printk(KERN_DEBUG | ||
| 1286 | "%s: setting double clock\n", __func__); | ||
| 1287 | HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK); | ||
| 1288 | } | ||
| 1289 | |||
| 1290 | /* B410P GPIO */ | ||
| 1291 | if (test_bit(HFC_CHIP_B410P, &hc->chip)) { | ||
| 1292 | printk(KERN_NOTICE "Setting GPIOs\n"); | ||
| 1293 | HFC_outb(hc, R_GPIO_SEL, 0x30); | ||
| 1294 | HFC_outb(hc, R_GPIO_EN1, 0x3); | ||
| 1295 | udelay(1000); | ||
| 1296 | printk(KERN_NOTICE "calling vpm_init\n"); | ||
| 1297 | vpm_init(hc); | ||
| 1298 | } | ||
| 1299 | |||
| 1300 | /* check if R_F0_CNT counts (8 kHz frame count) */ | ||
| 1301 | val = HFC_inb(hc, R_F0_CNTL); | ||
| 1302 | val += HFC_inb(hc, R_F0_CNTH) << 8; | ||
| 1303 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1304 | printk(KERN_DEBUG | ||
| 1305 | "HFC_multi F0_CNT %ld after reset\n", val); | ||
| 1306 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 1307 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
| 1308 | schedule_timeout((HZ/100)?:1); /* Timeout minimum 10ms */ | ||
| 1309 | spin_lock_irqsave(&hc->lock, flags); | ||
| 1310 | val2 = HFC_inb(hc, R_F0_CNTL); | ||
| 1311 | val2 += HFC_inb(hc, R_F0_CNTH) << 8; | ||
| 1312 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1313 | printk(KERN_DEBUG | ||
| 1314 | "HFC_multi F0_CNT %ld after 10 ms (1st try)\n", | ||
| 1315 | val2); | ||
| 1316 | if (val2 >= val+8) { /* 1 ms */ | ||
| 1317 | /* it counts, so we keep the pcm mode */ | ||
| 1318 | if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) | ||
| 1319 | printk(KERN_INFO "controller is PCM bus MASTER\n"); | ||
| 1320 | else | ||
| 1321 | if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) | ||
| 1322 | printk(KERN_INFO "controller is PCM bus SLAVE\n"); | ||
| 1323 | else { | ||
| 1324 | test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); | ||
| 1325 | printk(KERN_INFO "controller is PCM bus SLAVE " | ||
| 1326 | "(auto detected)\n"); | ||
| 1327 | } | ||
| 1328 | } else { | ||
| 1329 | /* does not count */ | ||
| 1330 | if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) { | ||
| 1331 | controller_fail: | ||
| 1332 | printk(KERN_ERR "HFC_multi ERROR, getting no 125us " | ||
| 1333 | "pulse. Seems that controller fails.\n"); | ||
| 1334 | err = -EIO; | ||
| 1335 | goto out; | ||
| 1336 | } | ||
| 1337 | if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { | ||
| 1338 | printk(KERN_INFO "controller is PCM bus SLAVE " | ||
| 1339 | "(ignoring missing PCM clock)\n"); | ||
| 1340 | } else { | ||
| 1341 | /* only one pcm master */ | ||
| 1342 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip) | ||
| 1343 | && plxsd_master) { | ||
| 1344 | printk(KERN_ERR "HFC_multi ERROR, no clock " | ||
| 1345 | "on another Speech Design card found. " | ||
| 1346 | "Please be sure to connect PCM cable.\n"); | ||
| 1347 | err = -EIO; | ||
| 1348 | goto out; | ||
| 1349 | } | ||
| 1350 | /* retry with master clock */ | ||
| 1351 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
| 1352 | spin_lock_irqsave(&plx_lock, plx_flags); | ||
| 1353 | plx_acc_32 = (u_int *)(hc->plx_membase + | ||
| 1354 | PLX_GPIOC); | ||
| 1355 | pv = readl(plx_acc_32); | ||
| 1356 | pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N; | ||
| 1357 | pv |= PLX_SYNC_O_EN; | ||
| 1358 | writel(pv, plx_acc_32); | ||
| 1359 | spin_unlock_irqrestore(&plx_lock, plx_flags); | ||
| 1360 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1361 | printk(KERN_WARNING "%s: master: PLX_GPIO" | ||
| 1362 | "=%x\n", __func__, pv); | ||
| 1363 | } | ||
| 1364 | hc->hw.r_pcm_md0 |= V_PCM_MD; | ||
| 1365 | HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00); | ||
| 1366 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 1367 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
| 1368 | schedule_timeout((HZ/100)?:1); /* Timeout min. 10ms */ | ||
| 1369 | spin_lock_irqsave(&hc->lock, flags); | ||
| 1370 | val2 = HFC_inb(hc, R_F0_CNTL); | ||
| 1371 | val2 += HFC_inb(hc, R_F0_CNTH) << 8; | ||
| 1372 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1373 | printk(KERN_DEBUG "HFC_multi F0_CNT %ld after " | ||
| 1374 | "10 ms (2nd try)\n", val2); | ||
| 1375 | if (val2 >= val+8) { /* 1 ms */ | ||
| 1376 | test_and_set_bit(HFC_CHIP_PCM_MASTER, | ||
| 1377 | &hc->chip); | ||
| 1378 | printk(KERN_INFO "controller is PCM bus MASTER " | ||
| 1379 | "(auto detected)\n"); | ||
| 1380 | } else | ||
| 1381 | goto controller_fail; | ||
| 1382 | } | ||
| 1383 | } | ||
| 1384 | |||
| 1385 | /* Release the DSP Reset */ | ||
| 1386 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
| 1387 | if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) | ||
| 1388 | plxsd_master = 1; | ||
| 1389 | spin_lock_irqsave(&plx_lock, plx_flags); | ||
| 1390 | plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); | ||
| 1391 | pv = readl(plx_acc_32); | ||
| 1392 | pv |= PLX_DSP_RES_N; | ||
| 1393 | writel(pv, plx_acc_32); | ||
| 1394 | spin_unlock_irqrestore(&plx_lock, plx_flags); | ||
| 1395 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1396 | printk(KERN_WARNING "%s: reset off: PLX_GPIO=%x\n", | ||
| 1397 | __func__, pv); | ||
| 1398 | } | ||
| 1399 | |||
| 1400 | /* pcm id */ | ||
| 1401 | if (hc->pcm) | ||
| 1402 | printk(KERN_INFO "controller has given PCM BUS ID %d\n", | ||
| 1403 | hc->pcm); | ||
| 1404 | else { | ||
| 1405 | if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip) | ||
| 1406 | || test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
| 1407 | PCM_cnt++; /* SD has proprietary bridging */ | ||
| 1408 | } | ||
| 1409 | hc->pcm = PCM_cnt; | ||
| 1410 | printk(KERN_INFO "controller has PCM BUS ID %d " | ||
| 1411 | "(auto selected)\n", hc->pcm); | ||
| 1412 | } | ||
| 1413 | |||
| 1414 | /* set up timer */ | ||
| 1415 | HFC_outb(hc, R_TI_WD, poll_timer); | ||
| 1416 | hc->hw.r_irqmsk_misc |= V_TI_IRQMSK; | ||
| 1417 | |||
| 1418 | /* | ||
| 1419 | * set up 125us interrupt, only if function pointer is available | ||
| 1420 | * and module parameter timer is set | ||
| 1421 | */ | ||
| 1422 | if (timer && hfc_interrupt && register_interrupt) { | ||
| 1423 | /* only one chip should use this interrupt */ | ||
| 1424 | timer = 0; | ||
| 1425 | interrupt_registered = 1; | ||
| 1426 | hc->hw.r_irqmsk_misc |= V_PROC_IRQMSK; | ||
| 1427 | /* deactivate other interrupts in ztdummy */ | ||
| 1428 | register_interrupt(); | ||
| 1429 | } | ||
| 1430 | |||
| 1431 | /* set E1 state machine IRQ */ | ||
| 1432 | if (hc->type == 1) | ||
| 1433 | hc->hw.r_irqmsk_misc |= V_STA_IRQMSK; | ||
| 1434 | |||
| 1435 | /* set DTMF detection */ | ||
| 1436 | if (test_bit(HFC_CHIP_DTMF, &hc->chip)) { | ||
| 1437 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1438 | printk(KERN_DEBUG "%s: enabling DTMF detection " | ||
| 1439 | "for all B-channel\n", __func__); | ||
| 1440 | hc->hw.r_dtmf = V_DTMF_EN | V_DTMF_STOP; | ||
| 1441 | if (test_bit(HFC_CHIP_ULAW, &hc->chip)) | ||
| 1442 | hc->hw.r_dtmf |= V_ULAW_SEL; | ||
| 1443 | HFC_outb(hc, R_DTMF_N, 102 - 1); | ||
| 1444 | hc->hw.r_irqmsk_misc |= V_DTMF_IRQMSK; | ||
| 1445 | } | ||
| 1446 | |||
| 1447 | /* conference engine */ | ||
| 1448 | if (test_bit(HFC_CHIP_ULAW, &hc->chip)) | ||
| 1449 | r_conf_en = V_CONF_EN | V_ULAW; | ||
| 1450 | else | ||
| 1451 | r_conf_en = V_CONF_EN; | ||
| 1452 | HFC_outb(hc, R_CONF_EN, r_conf_en); | ||
| 1453 | |||
| 1454 | /* setting leds */ | ||
| 1455 | switch (hc->leds) { | ||
| 1456 | case 1: /* HFC-E1 OEM */ | ||
| 1457 | if (test_bit(HFC_CHIP_WATCHDOG, &hc->chip)) | ||
| 1458 | HFC_outb(hc, R_GPIO_SEL, 0x32); | ||
| 1459 | else | ||
| 1460 | HFC_outb(hc, R_GPIO_SEL, 0x30); | ||
| 1461 | |||
| 1462 | HFC_outb(hc, R_GPIO_EN1, 0x0f); | ||
| 1463 | HFC_outb(hc, R_GPIO_OUT1, 0x00); | ||
| 1464 | |||
| 1465 | HFC_outb(hc, R_GPIO_EN0, V_GPIO_EN2 | V_GPIO_EN3); | ||
| 1466 | break; | ||
| 1467 | |||
| 1468 | case 2: /* HFC-4S OEM */ | ||
| 1469 | case 3: | ||
| 1470 | HFC_outb(hc, R_GPIO_SEL, 0xf0); | ||
| 1471 | HFC_outb(hc, R_GPIO_EN1, 0xff); | ||
| 1472 | HFC_outb(hc, R_GPIO_OUT1, 0x00); | ||
| 1473 | break; | ||
| 1474 | } | ||
| 1475 | |||
| 1476 | /* set master clock */ | ||
| 1477 | if (hc->masterclk >= 0) { | ||
| 1478 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1479 | printk(KERN_DEBUG "%s: setting ST master clock " | ||
| 1480 | "to port %d (0..%d)\n", | ||
| 1481 | __func__, hc->masterclk, hc->ports-1); | ||
| 1482 | hc->hw.r_st_sync = hc->masterclk | V_AUTO_SYNC; | ||
| 1483 | HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync); | ||
| 1484 | } | ||
| 1485 | |||
| 1486 | /* setting misc irq */ | ||
| 1487 | HFC_outb(hc, R_IRQMSK_MISC, hc->hw.r_irqmsk_misc); | ||
| 1488 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1489 | printk(KERN_DEBUG "r_irqmsk_misc.2: 0x%x\n", | ||
| 1490 | hc->hw.r_irqmsk_misc); | ||
| 1491 | |||
| 1492 | /* RAM access test */ | ||
| 1493 | HFC_outb(hc, R_RAM_ADDR0, 0); | ||
| 1494 | HFC_outb(hc, R_RAM_ADDR1, 0); | ||
| 1495 | HFC_outb(hc, R_RAM_ADDR2, 0); | ||
| 1496 | for (i = 0; i < 256; i++) { | ||
| 1497 | HFC_outb_nodebug(hc, R_RAM_ADDR0, i); | ||
| 1498 | HFC_outb_nodebug(hc, R_RAM_DATA, ((i*3)&0xff)); | ||
| 1499 | } | ||
| 1500 | for (i = 0; i < 256; i++) { | ||
| 1501 | HFC_outb_nodebug(hc, R_RAM_ADDR0, i); | ||
| 1502 | HFC_inb_nodebug(hc, R_RAM_DATA); | ||
| 1503 | rval = HFC_inb_nodebug(hc, R_INT_DATA); | ||
| 1504 | if (rval != ((i * 3) & 0xff)) { | ||
| 1505 | printk(KERN_DEBUG | ||
| 1506 | "addr:%x val:%x should:%x\n", i, rval, | ||
| 1507 | (i * 3) & 0xff); | ||
| 1508 | err++; | ||
| 1509 | } | ||
| 1510 | } | ||
| 1511 | if (err) { | ||
| 1512 | printk(KERN_DEBUG "aborting - %d RAM access errors\n", err); | ||
| 1513 | err = -EIO; | ||
| 1514 | goto out; | ||
| 1515 | } | ||
| 1516 | |||
| 1517 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 1518 | printk(KERN_DEBUG "%s: done\n", __func__); | ||
| 1519 | out: | ||
| 1520 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 1521 | return err; | ||
| 1522 | } | ||
| 1523 | |||
| 1524 | |||
| 1525 | /* | ||
| 1526 | * control the watchdog | ||
| 1527 | */ | ||
| 1528 | static void | ||
| 1529 | hfcmulti_watchdog(struct hfc_multi *hc) | ||
| 1530 | { | ||
| 1531 | hc->wdcount++; | ||
| 1532 | |||
| 1533 | if (hc->wdcount > 10) { | ||
| 1534 | hc->wdcount = 0; | ||
| 1535 | hc->wdbyte = hc->wdbyte == V_GPIO_OUT2 ? | ||
| 1536 | V_GPIO_OUT3 : V_GPIO_OUT2; | ||
| 1537 | |||
| 1538 | /* printk("Sending Watchdog Kill %x\n",hc->wdbyte); */ | ||
| 1539 | HFC_outb(hc, R_GPIO_EN0, V_GPIO_EN2 | V_GPIO_EN3); | ||
| 1540 | HFC_outb(hc, R_GPIO_OUT0, hc->wdbyte); | ||
| 1541 | } | ||
| 1542 | } | ||
| 1543 | |||
| 1544 | |||
| 1545 | |||
| 1546 | /* | ||
| 1547 | * output leds | ||
| 1548 | */ | ||
| 1549 | static void | ||
| 1550 | hfcmulti_leds(struct hfc_multi *hc) | ||
| 1551 | { | ||
| 1552 | unsigned long lled; | ||
| 1553 | unsigned long leddw; | ||
| 1554 | int i, state, active, leds; | ||
| 1555 | struct dchannel *dch; | ||
| 1556 | int led[4]; | ||
| 1557 | |||
| 1558 | hc->ledcount += poll; | ||
| 1559 | if (hc->ledcount > 4096) { | ||
| 1560 | hc->ledcount -= 4096; | ||
| 1561 | hc->ledstate = 0xAFFEAFFE; | ||
| 1562 | } | ||
| 1563 | |||
| 1564 | switch (hc->leds) { | ||
| 1565 | case 1: /* HFC-E1 OEM */ | ||
| 1566 | /* 2 red blinking: NT mode deactivate | ||
| 1567 | * 2 red steady: TE mode deactivate | ||
| 1568 | * left green: L1 active | ||
| 1569 | * left red: frame sync, but no L1 | ||
| 1570 | * right green: L2 active | ||
| 1571 | */ | ||
| 1572 | if (hc->chan[hc->dslot].sync != 2) { /* no frame sync */ | ||
| 1573 | if (hc->chan[hc->dslot].dch->dev.D.protocol | ||
| 1574 | != ISDN_P_NT_E1) { | ||
| 1575 | led[0] = 1; | ||
| 1576 | led[1] = 1; | ||
| 1577 | } else if (hc->ledcount>>11) { | ||
| 1578 | led[0] = 1; | ||
| 1579 | led[1] = 1; | ||
| 1580 | } else { | ||
| 1581 | led[0] = 0; | ||
| 1582 | led[1] = 0; | ||
| 1583 | } | ||
| 1584 | led[2] = 0; | ||
| 1585 | led[3] = 0; | ||
| 1586 | } else { /* with frame sync */ | ||
| 1587 | /* TODO make it work */ | ||
| 1588 | led[0] = 0; | ||
| 1589 | led[1] = 0; | ||
| 1590 | led[2] = 0; | ||
| 1591 | led[3] = 1; | ||
| 1592 | } | ||
| 1593 | leds = (led[0] | (led[1]<<2) | (led[2]<<1) | (led[3]<<3))^0xF; | ||
| 1594 | /* leds are inverted */ | ||
| 1595 | if (leds != (int)hc->ledstate) { | ||
| 1596 | HFC_outb_nodebug(hc, R_GPIO_OUT1, leds); | ||
| 1597 | hc->ledstate = leds; | ||
| 1598 | } | ||
| 1599 | break; | ||
| 1600 | |||
| 1601 | case 2: /* HFC-4S OEM */ | ||
| 1602 | /* red blinking = PH_DEACTIVATE NT Mode | ||
| 1603 | * red steady = PH_DEACTIVATE TE Mode | ||
| 1604 | * green steady = PH_ACTIVATE | ||
| 1605 | */ | ||
| 1606 | for (i = 0; i < 4; i++) { | ||
| 1607 | state = 0; | ||
| 1608 | active = -1; | ||
| 1609 | dch = hc->chan[(i << 2) | 2].dch; | ||
| 1610 | if (dch) { | ||
| 1611 | state = dch->state; | ||
| 1612 | if (dch->dev.D.protocol == ISDN_P_NT_S0) | ||
| 1613 | active = 3; | ||
| 1614 | else | ||
| 1615 | active = 7; | ||
| 1616 | } | ||
| 1617 | if (state) { | ||
| 1618 | if (state == active) { | ||
| 1619 | led[i] = 1; /* led green */ | ||
| 1620 | } else | ||
| 1621 | if (dch->dev.D.protocol == ISDN_P_TE_S0) | ||
| 1622 | /* TE mode: led red */ | ||
| 1623 | led[i] = 2; | ||
| 1624 | else | ||
| 1625 | if (hc->ledcount>>11) | ||
| 1626 | /* led red */ | ||
| 1627 | led[i] = 2; | ||
| 1628 | else | ||
| 1629 | /* led off */ | ||
| 1630 | led[i] = 0; | ||
| 1631 | } else | ||
| 1632 | led[i] = 0; /* led off */ | ||
| 1633 | } | ||
| 1634 | if (test_bit(HFC_CHIP_B410P, &hc->chip)) { | ||
| 1635 | leds = 0; | ||
| 1636 | for (i = 0; i < 4; i++) { | ||
| 1637 | if (led[i] == 1) { | ||
| 1638 | /*green*/ | ||
| 1639 | leds |= (0x2 << (i * 2)); | ||
| 1640 | } else if (led[i] == 2) { | ||
| 1641 | /*red*/ | ||
| 1642 | leds |= (0x1 << (i * 2)); | ||
| 1643 | } | ||
| 1644 | } | ||
| 1645 | if (leds != (int)hc->ledstate) { | ||
| 1646 | vpm_out(hc, 0, 0x1a8 + 3, leds); | ||
| 1647 | hc->ledstate = leds; | ||
| 1648 | } | ||
| 1649 | } else { | ||
| 1650 | leds = ((led[3] > 0) << 0) | ((led[1] > 0) << 1) | | ||
| 1651 | ((led[0] > 0) << 2) | ((led[2] > 0) << 3) | | ||
| 1652 | ((led[3] & 1) << 4) | ((led[1] & 1) << 5) | | ||
| 1653 | ((led[0] & 1) << 6) | ((led[2] & 1) << 7); | ||
| 1654 | if (leds != (int)hc->ledstate) { | ||
| 1655 | HFC_outb_nodebug(hc, R_GPIO_EN1, leds & 0x0F); | ||
| 1656 | HFC_outb_nodebug(hc, R_GPIO_OUT1, leds >> 4); | ||
| 1657 | hc->ledstate = leds; | ||
| 1658 | } | ||
| 1659 | } | ||
| 1660 | break; | ||
| 1661 | |||
| 1662 | case 3: /* HFC 1S/2S Beronet */ | ||
| 1663 | /* red blinking = PH_DEACTIVATE NT Mode | ||
| 1664 | * red steady = PH_DEACTIVATE TE Mode | ||
| 1665 | * green steady = PH_ACTIVATE | ||
| 1666 | */ | ||
| 1667 | for (i = 0; i < 2; i++) { | ||
| 1668 | state = 0; | ||
| 1669 | active = -1; | ||
| 1670 | dch = hc->chan[(i << 2) | 2].dch; | ||
| 1671 | if (dch) { | ||
| 1672 | state = dch->state; | ||
| 1673 | if (dch->dev.D.protocol == ISDN_P_NT_S0) | ||
| 1674 | active = 3; | ||
| 1675 | else | ||
| 1676 | active = 7; | ||
| 1677 | } | ||
| 1678 | if (state) { | ||
| 1679 | if (state == active) { | ||
| 1680 | led[i] = 1; /* led green */ | ||
| 1681 | } else | ||
| 1682 | if (dch->dev.D.protocol == ISDN_P_TE_S0) | ||
| 1683 | /* TE mode: led red */ | ||
| 1684 | led[i] = 2; | ||
| 1685 | else | ||
| 1686 | if (hc->ledcount >> 11) | ||
| 1687 | /* led red */ | ||
| 1688 | led[i] = 2; | ||
| 1689 | else | ||
| 1690 | /* led off */ | ||
| 1691 | led[i] = 0; | ||
| 1692 | } else | ||
| 1693 | led[i] = 0; /* led off */ | ||
| 1694 | } | ||
| 1695 | |||
| 1696 | |||
| 1697 | leds = (led[0] > 0) | ((led[1] > 0)<<1) | ((led[0]&1)<<2) | ||
| 1698 | | ((led[1]&1)<<3); | ||
| 1699 | if (leds != (int)hc->ledstate) { | ||
| 1700 | HFC_outb_nodebug(hc, R_GPIO_EN1, | ||
| 1701 | ((led[0] > 0) << 2) | ((led[1] > 0) << 3)); | ||
| 1702 | HFC_outb_nodebug(hc, R_GPIO_OUT1, | ||
| 1703 | ((led[0] & 1) << 2) | ((led[1] & 1) << 3)); | ||
| 1704 | hc->ledstate = leds; | ||
| 1705 | } | ||
| 1706 | break; | ||
| 1707 | case 8: /* HFC 8S+ Beronet */ | ||
| 1708 | lled = 0; | ||
| 1709 | |||
| 1710 | for (i = 0; i < 8; i++) { | ||
| 1711 | state = 0; | ||
| 1712 | active = -1; | ||
| 1713 | dch = hc->chan[(i << 2) | 2].dch; | ||
| 1714 | if (dch) { | ||
| 1715 | state = dch->state; | ||
| 1716 | if (dch->dev.D.protocol == ISDN_P_NT_S0) | ||
| 1717 | active = 3; | ||
| 1718 | else | ||
| 1719 | active = 7; | ||
| 1720 | } | ||
| 1721 | if (state) { | ||
| 1722 | if (state == active) { | ||
| 1723 | lled |= 0 << i; | ||
| 1724 | } else | ||
| 1725 | if (hc->ledcount >> 11) | ||
| 1726 | lled |= 0 << i; | ||
| 1727 | else | ||
| 1728 | lled |= 1 << i; | ||
| 1729 | } else | ||
| 1730 | lled |= 1 << i; | ||
| 1731 | } | ||
| 1732 | leddw = lled << 24 | lled << 16 | lled << 8 | lled; | ||
| 1733 | if (leddw != hc->ledstate) { | ||
| 1734 | /* HFC_outb(hc, R_BRG_PCM_CFG, 1); | ||
| 1735 | HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x3); */ | ||
| 1736 | /* was _io before */ | ||
| 1737 | HFC_outb_nodebug(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK); | ||
| 1738 | outw(0x4000, hc->pci_iobase + 4); | ||
| 1739 | outl(leddw, hc->pci_iobase); | ||
| 1740 | HFC_outb_nodebug(hc, R_BRG_PCM_CFG, V_PCM_CLK); | ||
| 1741 | hc->ledstate = leddw; | ||
| 1742 | } | ||
| 1743 | break; | ||
| 1744 | } | ||
| 1745 | } | ||
| 1746 | /* | ||
| 1747 | * read dtmf coefficients | ||
| 1748 | */ | ||
| 1749 | |||
| 1750 | static void | ||
| 1751 | hfcmulti_dtmf(struct hfc_multi *hc) | ||
| 1752 | { | ||
| 1753 | s32 *coeff; | ||
| 1754 | u_int mantissa; | ||
| 1755 | int co, ch; | ||
| 1756 | struct bchannel *bch = NULL; | ||
| 1757 | u8 exponent; | ||
| 1758 | int dtmf = 0; | ||
| 1759 | int addr; | ||
| 1760 | u16 w_float; | ||
| 1761 | struct sk_buff *skb; | ||
| 1762 | struct mISDNhead *hh; | ||
| 1763 | |||
| 1764 | if (debug & DEBUG_HFCMULTI_DTMF) | ||
| 1765 | printk(KERN_DEBUG "%s: dtmf detection irq\n", __func__); | ||
| 1766 | for (ch = 0; ch <= 31; ch++) { | ||
| 1767 | /* only process enabled B-channels */ | ||
| 1768 | bch = hc->chan[ch].bch; | ||
| 1769 | if (!bch) | ||
| 1770 | continue; | ||
| 1771 | if (!hc->created[hc->chan[ch].port]) | ||
| 1772 | continue; | ||
| 1773 | if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
| 1774 | continue; | ||
| 1775 | if (debug & DEBUG_HFCMULTI_DTMF) | ||
| 1776 | printk(KERN_DEBUG "%s: dtmf channel %d:", | ||
| 1777 | __func__, ch); | ||
| 1778 | coeff = &(hc->chan[ch].coeff[hc->chan[ch].coeff_count * 16]); | ||
| 1779 | dtmf = 1; | ||
| 1780 | for (co = 0; co < 8; co++) { | ||
| 1781 | /* read W(n-1) coefficient */ | ||
| 1782 | addr = hc->DTMFbase + ((co<<7) | (ch<<2)); | ||
| 1783 | HFC_outb_nodebug(hc, R_RAM_ADDR0, addr); | ||
| 1784 | HFC_outb_nodebug(hc, R_RAM_ADDR1, addr>>8); | ||
| 1785 | HFC_outb_nodebug(hc, R_RAM_ADDR2, (addr>>16) | ||
| 1786 | | V_ADDR_INC); | ||
| 1787 | w_float = HFC_inb_nodebug(hc, R_RAM_DATA); | ||
| 1788 | w_float |= (HFC_inb_nodebug(hc, R_RAM_DATA) << 8); | ||
| 1789 | if (debug & DEBUG_HFCMULTI_DTMF) | ||
| 1790 | printk(" %04x", w_float); | ||
| 1791 | |||
| 1792 | /* decode float (see chip doc) */ | ||
| 1793 | mantissa = w_float & 0x0fff; | ||
| 1794 | if (w_float & 0x8000) | ||
| 1795 | mantissa |= 0xfffff000; | ||
| 1796 | exponent = (w_float>>12) & 0x7; | ||
| 1797 | if (exponent) { | ||
| 1798 | mantissa ^= 0x1000; | ||
| 1799 | mantissa <<= (exponent-1); | ||
| 1800 | } | ||
| 1801 | |||
| 1802 | /* store coefficient */ | ||
| 1803 | coeff[co<<1] = mantissa; | ||
| 1804 | |||
| 1805 | /* read W(n) coefficient */ | ||
| 1806 | w_float = HFC_inb_nodebug(hc, R_RAM_DATA); | ||
| 1807 | w_float |= (HFC_inb_nodebug(hc, R_RAM_DATA) << 8); | ||
| 1808 | if (debug & DEBUG_HFCMULTI_DTMF) | ||
| 1809 | printk(" %04x", w_float); | ||
| 1810 | |||
| 1811 | /* decode float (see chip doc) */ | ||
| 1812 | mantissa = w_float & 0x0fff; | ||
| 1813 | if (w_float & 0x8000) | ||
| 1814 | mantissa |= 0xfffff000; | ||
| 1815 | exponent = (w_float>>12) & 0x7; | ||
| 1816 | if (exponent) { | ||
| 1817 | mantissa ^= 0x1000; | ||
| 1818 | mantissa <<= (exponent-1); | ||
| 1819 | } | ||
| 1820 | |||
| 1821 | /* store coefficient */ | ||
| 1822 | coeff[(co<<1)|1] = mantissa; | ||
| 1823 | } | ||
| 1824 | if (debug & DEBUG_HFCMULTI_DTMF) | ||
| 1825 | printk("%s: DTMF ready %08x %08x %08x %08x " | ||
| 1826 | "%08x %08x %08x %08x\n", __func__, | ||
| 1827 | coeff[0], coeff[1], coeff[2], coeff[3], | ||
| 1828 | coeff[4], coeff[5], coeff[6], coeff[7]); | ||
| 1829 | hc->chan[ch].coeff_count++; | ||
| 1830 | if (hc->chan[ch].coeff_count == 8) { | ||
| 1831 | hc->chan[ch].coeff_count = 0; | ||
| 1832 | skb = mI_alloc_skb(512, GFP_ATOMIC); | ||
| 1833 | if (!skb) { | ||
| 1834 | printk(KERN_WARNING "%s: No memory for skb\n", | ||
| 1835 | __func__); | ||
| 1836 | continue; | ||
| 1837 | } | ||
| 1838 | hh = mISDN_HEAD_P(skb); | ||
| 1839 | hh->prim = PH_CONTROL_IND; | ||
| 1840 | hh->id = DTMF_HFC_COEF; | ||
| 1841 | memcpy(skb_put(skb, 512), hc->chan[ch].coeff, 512); | ||
| 1842 | recv_Bchannel_skb(bch, skb); | ||
| 1843 | } | ||
| 1844 | } | ||
| 1845 | |||
| 1846 | /* restart DTMF processing */ | ||
| 1847 | hc->dtmf = dtmf; | ||
| 1848 | if (dtmf) | ||
| 1849 | HFC_outb_nodebug(hc, R_DTMF, hc->hw.r_dtmf | V_RST_DTMF); | ||
| 1850 | } | ||
| 1851 | |||
| 1852 | |||
| 1853 | /* | ||
| 1854 | * fill fifo as much as possible | ||
| 1855 | */ | ||
| 1856 | |||
| 1857 | static void | ||
| 1858 | hfcmulti_tx(struct hfc_multi *hc, int ch) | ||
| 1859 | { | ||
| 1860 | int i, ii, temp, len = 0; | ||
| 1861 | int Zspace, z1, z2; /* must be int for calculation */ | ||
| 1862 | int Fspace, f1, f2; | ||
| 1863 | u_char *d; | ||
| 1864 | int *txpending, slot_tx; | ||
| 1865 | struct bchannel *bch; | ||
| 1866 | struct dchannel *dch; | ||
| 1867 | struct sk_buff **sp = NULL; | ||
| 1868 | int *idxp; | ||
| 1869 | |||
| 1870 | bch = hc->chan[ch].bch; | ||
| 1871 | dch = hc->chan[ch].dch; | ||
| 1872 | if ((!dch) && (!bch)) | ||
| 1873 | return; | ||
| 1874 | |||
| 1875 | txpending = &hc->chan[ch].txpending; | ||
| 1876 | slot_tx = hc->chan[ch].slot_tx; | ||
| 1877 | if (dch) { | ||
| 1878 | if (!test_bit(FLG_ACTIVE, &dch->Flags)) | ||
| 1879 | return; | ||
| 1880 | sp = &dch->tx_skb; | ||
| 1881 | idxp = &dch->tx_idx; | ||
| 1882 | } else { | ||
| 1883 | if (!test_bit(FLG_ACTIVE, &bch->Flags)) | ||
| 1884 | return; | ||
| 1885 | sp = &bch->tx_skb; | ||
| 1886 | idxp = &bch->tx_idx; | ||
| 1887 | } | ||
| 1888 | if (*sp) | ||
| 1889 | len = (*sp)->len; | ||
| 1890 | |||
| 1891 | if ((!len) && *txpending != 1) | ||
| 1892 | return; /* no data */ | ||
| 1893 | |||
| 1894 | if (test_bit(HFC_CHIP_B410P, &hc->chip) && | ||
| 1895 | (hc->chan[ch].protocol == ISDN_P_B_RAW) && | ||
| 1896 | (hc->chan[ch].slot_rx < 0) && | ||
| 1897 | (hc->chan[ch].slot_tx < 0)) | ||
| 1898 | HFC_outb_nodebug(hc, R_FIFO, 0x20 | (ch << 1)); | ||
| 1899 | else | ||
| 1900 | HFC_outb_nodebug(hc, R_FIFO, ch << 1); | ||
| 1901 | HFC_wait_nodebug(hc); | ||
| 1902 | |||
| 1903 | if (*txpending == 2) { | ||
| 1904 | /* reset fifo */ | ||
| 1905 | HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F); | ||
| 1906 | HFC_wait_nodebug(hc); | ||
| 1907 | HFC_outb(hc, A_SUBCH_CFG, 0); | ||
| 1908 | *txpending = 1; | ||
| 1909 | } | ||
| 1910 | next_frame: | ||
| 1911 | if (dch || test_bit(FLG_HDLC, &bch->Flags)) { | ||
| 1912 | f1 = HFC_inb_nodebug(hc, A_F1); | ||
| 1913 | f2 = HFC_inb_nodebug(hc, A_F2); | ||
| 1914 | while (f2 != (temp = HFC_inb_nodebug(hc, A_F2))) { | ||
| 1915 | if (debug & DEBUG_HFCMULTI_FIFO) | ||
| 1916 | printk(KERN_DEBUG | ||
| 1917 | "%s(card %d): reread f2 because %d!=%d\n", | ||
| 1918 | __func__, hc->id + 1, temp, f2); | ||
| 1919 | f2 = temp; /* repeat until F2 is equal */ | ||
| 1920 | } | ||
| 1921 | Fspace = f2 - f1 - 1; | ||
| 1922 | if (Fspace < 0) | ||
| 1923 | Fspace += hc->Flen; | ||
| 1924 | /* | ||
| 1925 | * Old FIFO handling doesn't give us the current Z2 read | ||
| 1926 | * pointer, so we cannot send the next frame before the fifo | ||
| 1927 | * is empty. It makes no difference except for a slightly | ||
| 1928 | * lower performance. | ||
| 1929 | */ | ||
| 1930 | if (test_bit(HFC_CHIP_REVISION0, &hc->chip)) { | ||
| 1931 | if (f1 != f2) | ||
| 1932 | Fspace = 0; | ||
| 1933 | else | ||
| 1934 | Fspace = 1; | ||
| 1935 | } | ||
| 1936 | /* one frame only for ST D-channels, to allow resending */ | ||
| 1937 | if (hc->type != 1 && dch) { | ||
| 1938 | if (f1 != f2) | ||
| 1939 | Fspace = 0; | ||
| 1940 | } | ||
| 1941 | /* F-counter full condition */ | ||
| 1942 | if (Fspace == 0) | ||
| 1943 | return; | ||
| 1944 | } | ||
| 1945 | z1 = HFC_inw_nodebug(hc, A_Z1) - hc->Zmin; | ||
| 1946 | z2 = HFC_inw_nodebug(hc, A_Z2) - hc->Zmin; | ||
| 1947 | while (z2 != (temp = (HFC_inw_nodebug(hc, A_Z2) - hc->Zmin))) { | ||
| 1948 | if (debug & DEBUG_HFCMULTI_FIFO) | ||
| 1949 | printk(KERN_DEBUG "%s(card %d): reread z2 because " | ||
| 1950 | "%d!=%d\n", __func__, hc->id + 1, temp, z2); | ||
| 1951 | z2 = temp; /* repeat unti Z2 is equal */ | ||
| 1952 | } | ||
| 1953 | Zspace = z2 - z1; | ||
| 1954 | if (Zspace <= 0) | ||
| 1955 | Zspace += hc->Zlen; | ||
| 1956 | Zspace -= 4; /* keep not too full, so pointers will not overrun */ | ||
| 1957 | /* fill transparent data only to maxinum transparent load (minus 4) */ | ||
| 1958 | if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
| 1959 | Zspace = Zspace - hc->Zlen + hc->max_trans; | ||
| 1960 | if (Zspace <= 0) /* no space of 4 bytes */ | ||
| 1961 | return; | ||
| 1962 | |||
| 1963 | /* if no data */ | ||
| 1964 | if (!len) { | ||
| 1965 | if (z1 == z2) { /* empty */ | ||
| 1966 | /* if done with FIFO audio data during PCM connection */ | ||
| 1967 | if (bch && (!test_bit(FLG_HDLC, &bch->Flags)) && | ||
| 1968 | *txpending && slot_tx >= 0) { | ||
| 1969 | if (debug & DEBUG_HFCMULTI_MODE) | ||
| 1970 | printk(KERN_DEBUG | ||
| 1971 | "%s: reconnecting PCM due to no " | ||
| 1972 | "more FIFO data: channel %d " | ||
| 1973 | "slot_tx %d\n", | ||
| 1974 | __func__, ch, slot_tx); | ||
| 1975 | /* connect slot */ | ||
| 1976 | HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | | ||
| 1977 | V_HDLC_TRP | V_IFF); | ||
| 1978 | HFC_outb_nodebug(hc, R_FIFO, ch<<1 | 1); | ||
| 1979 | HFC_wait_nodebug(hc); | ||
| 1980 | HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | | ||
| 1981 | V_HDLC_TRP | V_IFF); | ||
| 1982 | HFC_outb_nodebug(hc, R_FIFO, ch<<1); | ||
| 1983 | HFC_wait_nodebug(hc); | ||
| 1984 | } | ||
| 1985 | *txpending = 0; | ||
| 1986 | } | ||
| 1987 | return; /* no data */ | ||
| 1988 | } | ||
| 1989 | |||
| 1990 | /* if audio data and connected slot */ | ||
| 1991 | if (bch && (!test_bit(FLG_HDLC, &bch->Flags)) && (!*txpending) | ||
| 1992 | && slot_tx >= 0) { | ||
| 1993 | if (debug & DEBUG_HFCMULTI_MODE) | ||
| 1994 | printk(KERN_DEBUG "%s: disconnecting PCM due to " | ||
| 1995 | "FIFO data: channel %d slot_tx %d\n", | ||
| 1996 | __func__, ch, slot_tx); | ||
| 1997 | /* disconnect slot */ | ||
| 1998 | HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | V_HDLC_TRP | V_IFF); | ||
| 1999 | HFC_outb_nodebug(hc, R_FIFO, ch<<1 | 1); | ||
| 2000 | HFC_wait_nodebug(hc); | ||
| 2001 | HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | V_HDLC_TRP | V_IFF); | ||
| 2002 | HFC_outb_nodebug(hc, R_FIFO, ch<<1); | ||
| 2003 | HFC_wait_nodebug(hc); | ||
| 2004 | } | ||
| 2005 | *txpending = 1; | ||
| 2006 | |||
| 2007 | /* show activity */ | ||
| 2008 | hc->activity[hc->chan[ch].port] = 1; | ||
| 2009 | |||
| 2010 | /* fill fifo to what we have left */ | ||
| 2011 | ii = len; | ||
| 2012 | if (dch || test_bit(FLG_HDLC, &bch->Flags)) | ||
| 2013 | temp = 1; | ||
| 2014 | else | ||
| 2015 | temp = 0; | ||
| 2016 | i = *idxp; | ||
| 2017 | d = (*sp)->data + i; | ||
| 2018 | if (ii - i > Zspace) | ||
| 2019 | ii = Zspace + i; | ||
| 2020 | if (debug & DEBUG_HFCMULTI_FIFO) | ||
| 2021 | printk(KERN_DEBUG "%s(card %d): fifo(%d) has %d bytes space " | ||
| 2022 | "left (z1=%04x, z2=%04x) sending %d of %d bytes %s\n", | ||
| 2023 | __func__, hc->id + 1, ch, Zspace, z1, z2, ii-i, len-i, | ||
| 2024 | temp ? "HDLC":"TRANS"); | ||
| 2025 | |||
| 2026 | |||
| 2027 | /* Have to prep the audio data */ | ||
| 2028 | hc->write_fifo(hc, d, ii - i); | ||
| 2029 | *idxp = ii; | ||
| 2030 | |||
| 2031 | /* if not all data has been written */ | ||
| 2032 | if (ii != len) { | ||
| 2033 | /* NOTE: fifo is started by the calling function */ | ||
| 2034 | return; | ||
| 2035 | } | ||
| 2036 | |||
| 2037 | /* if all data has been written, terminate frame */ | ||
| 2038 | if (dch || test_bit(FLG_HDLC, &bch->Flags)) { | ||
| 2039 | /* increment f-counter */ | ||
| 2040 | HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_INC_F); | ||
| 2041 | HFC_wait_nodebug(hc); | ||
| 2042 | } | ||
| 2043 | |||
| 2044 | /* send confirm, since get_net_bframe will not do it with trans */ | ||
| 2045 | if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
| 2046 | confirm_Bsend(bch); | ||
| 2047 | |||
| 2048 | /* check for next frame */ | ||
| 2049 | dev_kfree_skb(*sp); | ||
| 2050 | if (bch && get_next_bframe(bch)) { /* hdlc is confirmed here */ | ||
| 2051 | len = (*sp)->len; | ||
| 2052 | goto next_frame; | ||
| 2053 | } | ||
| 2054 | if (dch && get_next_dframe(dch)) { | ||
| 2055 | len = (*sp)->len; | ||
| 2056 | goto next_frame; | ||
| 2057 | } | ||
| 2058 | |||
| 2059 | /* | ||
| 2060 | * now we have no more data, so in case of transparent, | ||
| 2061 | * we set the last byte in fifo to 'silence' in case we will get | ||
| 2062 | * no more data at all. this prevents sending an undefined value. | ||
| 2063 | */ | ||
| 2064 | if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
| 2065 | HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, silence); | ||
| 2066 | } | ||
| 2067 | |||
| 2068 | |||
| 2069 | /* NOTE: only called if E1 card is in active state */ | ||
| 2070 | static void | ||
| 2071 | hfcmulti_rx(struct hfc_multi *hc, int ch) | ||
| 2072 | { | ||
| 2073 | int temp; | ||
| 2074 | int Zsize, z1, z2 = 0; /* = 0, to make GCC happy */ | ||
| 2075 | int f1 = 0, f2 = 0; /* = 0, to make GCC happy */ | ||
| 2076 | int again = 0; | ||
| 2077 | struct bchannel *bch; | ||
| 2078 | struct dchannel *dch; | ||
| 2079 | struct sk_buff *skb, **sp = NULL; | ||
| 2080 | int maxlen; | ||
| 2081 | |||
| 2082 | bch = hc->chan[ch].bch; | ||
| 2083 | dch = hc->chan[ch].dch; | ||
| 2084 | if ((!dch) && (!bch)) | ||
| 2085 | return; | ||
| 2086 | if (dch) { | ||
| 2087 | if (!test_bit(FLG_ACTIVE, &dch->Flags)) | ||
| 2088 | return; | ||
| 2089 | sp = &dch->rx_skb; | ||
| 2090 | maxlen = dch->maxlen; | ||
| 2091 | } else { | ||
| 2092 | if (!test_bit(FLG_ACTIVE, &bch->Flags)) | ||
| 2093 | return; | ||
| 2094 | sp = &bch->rx_skb; | ||
| 2095 | maxlen = bch->maxlen; | ||
| 2096 | } | ||
| 2097 | next_frame: | ||
| 2098 | /* on first AND before getting next valid frame, R_FIFO must be written | ||
| 2099 | to. */ | ||
| 2100 | if (test_bit(HFC_CHIP_B410P, &hc->chip) && | ||
| 2101 | (hc->chan[ch].protocol == ISDN_P_B_RAW) && | ||
| 2102 | (hc->chan[ch].slot_rx < 0) && | ||
| 2103 | (hc->chan[ch].slot_tx < 0)) | ||
| 2104 | HFC_outb_nodebug(hc, R_FIFO, 0x20 | (ch<<1) | 1); | ||
| 2105 | else | ||
| 2106 | HFC_outb_nodebug(hc, R_FIFO, (ch<<1)|1); | ||
| 2107 | HFC_wait_nodebug(hc); | ||
| 2108 | |||
| 2109 | /* ignore if rx is off BUT change fifo (above) to start pending TX */ | ||
| 2110 | if (hc->chan[ch].rx_off) | ||
| 2111 | return; | ||
| 2112 | |||
| 2113 | if (dch || test_bit(FLG_HDLC, &bch->Flags)) { | ||
| 2114 | f1 = HFC_inb_nodebug(hc, A_F1); | ||
| 2115 | while (f1 != (temp = HFC_inb_nodebug(hc, A_F1))) { | ||
| 2116 | if (debug & DEBUG_HFCMULTI_FIFO) | ||
| 2117 | printk(KERN_DEBUG | ||
| 2118 | "%s(card %d): reread f1 because %d!=%d\n", | ||
| 2119 | __func__, hc->id + 1, temp, f1); | ||
| 2120 | f1 = temp; /* repeat until F1 is equal */ | ||
| 2121 | } | ||
| 2122 | f2 = HFC_inb_nodebug(hc, A_F2); | ||
| 2123 | } | ||
| 2124 | z1 = HFC_inw_nodebug(hc, A_Z1) - hc->Zmin; | ||
| 2125 | while (z1 != (temp = (HFC_inw_nodebug(hc, A_Z1) - hc->Zmin))) { | ||
| 2126 | if (debug & DEBUG_HFCMULTI_FIFO) | ||
| 2127 | printk(KERN_DEBUG "%s(card %d): reread z2 because " | ||
| 2128 | "%d!=%d\n", __func__, hc->id + 1, temp, z2); | ||
| 2129 | z1 = temp; /* repeat until Z1 is equal */ | ||
| 2130 | } | ||
| 2131 | z2 = HFC_inw_nodebug(hc, A_Z2) - hc->Zmin; | ||
| 2132 | Zsize = z1 - z2; | ||
| 2133 | if ((dch || test_bit(FLG_HDLC, &bch->Flags)) && f1 != f2) | ||
| 2134 | /* complete hdlc frame */ | ||
| 2135 | Zsize++; | ||
| 2136 | if (Zsize < 0) | ||
| 2137 | Zsize += hc->Zlen; | ||
| 2138 | /* if buffer is empty */ | ||
| 2139 | if (Zsize <= 0) | ||
| 2140 | return; | ||
| 2141 | |||
| 2142 | if (*sp == NULL) { | ||
| 2143 | *sp = mI_alloc_skb(maxlen + 3, GFP_ATOMIC); | ||
| 2144 | if (*sp == NULL) { | ||
| 2145 | printk(KERN_DEBUG "%s: No mem for rx_skb\n", | ||
| 2146 | __func__); | ||
| 2147 | return; | ||
| 2148 | } | ||
| 2149 | } | ||
| 2150 | /* show activity */ | ||
| 2151 | hc->activity[hc->chan[ch].port] = 1; | ||
| 2152 | |||
| 2153 | /* empty fifo with what we have */ | ||
| 2154 | if (dch || test_bit(FLG_HDLC, &bch->Flags)) { | ||
| 2155 | if (debug & DEBUG_HFCMULTI_FIFO) | ||
| 2156 | printk(KERN_DEBUG "%s(card %d): fifo(%d) reading %d " | ||
| 2157 | "bytes (z1=%04x, z2=%04x) HDLC %s (f1=%d, f2=%d) " | ||
| 2158 | "got=%d (again %d)\n", __func__, hc->id + 1, ch, | ||
| 2159 | Zsize, z1, z2, (f1 == f2) ? "fragment" : "COMPLETE", | ||
| 2160 | f1, f2, Zsize + (*sp)->len, again); | ||
| 2161 | /* HDLC */ | ||
| 2162 | if ((Zsize + (*sp)->len) > (maxlen + 3)) { | ||
| 2163 | if (debug & DEBUG_HFCMULTI_FIFO) | ||
| 2164 | printk(KERN_DEBUG | ||
| 2165 | "%s(card %d): hdlc-frame too large.\n", | ||
| 2166 | __func__, hc->id + 1); | ||
| 2167 | skb_trim(*sp, 0); | ||
| 2168 | HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F); | ||
| 2169 | HFC_wait_nodebug(hc); | ||
| 2170 | return; | ||
| 2171 | } | ||
| 2172 | |||
| 2173 | hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize); | ||
| 2174 | |||
| 2175 | if (f1 != f2) { | ||
| 2176 | /* increment Z2,F2-counter */ | ||
| 2177 | HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_INC_F); | ||
| 2178 | HFC_wait_nodebug(hc); | ||
| 2179 | /* check size */ | ||
| 2180 | if ((*sp)->len < 4) { | ||
| 2181 | if (debug & DEBUG_HFCMULTI_FIFO) | ||
| 2182 | printk(KERN_DEBUG | ||
| 2183 | "%s(card %d): Frame below minimum " | ||
| 2184 | "size\n", __func__, hc->id + 1); | ||
| 2185 | skb_trim(*sp, 0); | ||
| 2186 | goto next_frame; | ||
| 2187 | } | ||
| 2188 | /* there is at least one complete frame, check crc */ | ||
| 2189 | if ((*sp)->data[(*sp)->len - 1]) { | ||
| 2190 | if (debug & DEBUG_HFCMULTI_CRC) | ||
| 2191 | printk(KERN_DEBUG | ||
| 2192 | "%s: CRC-error\n", __func__); | ||
| 2193 | skb_trim(*sp, 0); | ||
| 2194 | goto next_frame; | ||
| 2195 | } | ||
| 2196 | skb_trim(*sp, (*sp)->len - 3); | ||
| 2197 | if ((*sp)->len < MISDN_COPY_SIZE) { | ||
| 2198 | skb = *sp; | ||
| 2199 | *sp = mI_alloc_skb(skb->len, GFP_ATOMIC); | ||
| 2200 | if (*sp) { | ||
| 2201 | memcpy(skb_put(*sp, skb->len), | ||
| 2202 | skb->data, skb->len); | ||
| 2203 | skb_trim(skb, 0); | ||
| 2204 | } else { | ||
| 2205 | printk(KERN_DEBUG "%s: No mem\n", | ||
| 2206 | __func__); | ||
| 2207 | *sp = skb; | ||
| 2208 | skb = NULL; | ||
| 2209 | } | ||
| 2210 | } else { | ||
| 2211 | skb = NULL; | ||
| 2212 | } | ||
| 2213 | if (debug & DEBUG_HFCMULTI_FIFO) { | ||
| 2214 | printk(KERN_DEBUG "%s(card %d):", | ||
| 2215 | __func__, hc->id + 1); | ||
| 2216 | temp = 0; | ||
| 2217 | while (temp < (*sp)->len) | ||
| 2218 | printk(" %02x", (*sp)->data[temp++]); | ||
| 2219 | printk("\n"); | ||
| 2220 | } | ||
| 2221 | if (dch) | ||
| 2222 | recv_Dchannel(dch); | ||
| 2223 | else | ||
| 2224 | recv_Bchannel(bch); | ||
| 2225 | *sp = skb; | ||
| 2226 | again++; | ||
| 2227 | goto next_frame; | ||
| 2228 | } | ||
| 2229 | /* there is an incomplete frame */ | ||
| 2230 | } else { | ||
| 2231 | /* transparent */ | ||
| 2232 | if (Zsize > skb_tailroom(*sp)) | ||
| 2233 | Zsize = skb_tailroom(*sp); | ||
| 2234 | hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize); | ||
| 2235 | if (((*sp)->len) < MISDN_COPY_SIZE) { | ||
| 2236 | skb = *sp; | ||
| 2237 | *sp = mI_alloc_skb(skb->len, GFP_ATOMIC); | ||
| 2238 | if (*sp) { | ||
| 2239 | memcpy(skb_put(*sp, skb->len), | ||
| 2240 | skb->data, skb->len); | ||
| 2241 | skb_trim(skb, 0); | ||
| 2242 | } else { | ||
| 2243 | printk(KERN_DEBUG "%s: No mem\n", __func__); | ||
| 2244 | *sp = skb; | ||
| 2245 | skb = NULL; | ||
| 2246 | } | ||
| 2247 | } else { | ||
| 2248 | skb = NULL; | ||
| 2249 | } | ||
| 2250 | if (debug & DEBUG_HFCMULTI_FIFO) | ||
| 2251 | printk(KERN_DEBUG | ||
| 2252 | "%s(card %d): fifo(%d) reading %d bytes " | ||
| 2253 | "(z1=%04x, z2=%04x) TRANS\n", | ||
| 2254 | __func__, hc->id + 1, ch, Zsize, z1, z2); | ||
| 2255 | /* only bch is transparent */ | ||
| 2256 | recv_Bchannel(bch); | ||
| 2257 | *sp = skb; | ||
| 2258 | } | ||
| 2259 | } | ||
| 2260 | |||
| 2261 | |||
| 2262 | /* | ||
| 2263 | * Interrupt handler | ||
| 2264 | */ | ||
| 2265 | static void | ||
| 2266 | signal_state_up(struct dchannel *dch, int info, char *msg) | ||
| 2267 | { | ||
| 2268 | struct sk_buff *skb; | ||
| 2269 | int id, data = info; | ||
| 2270 | |||
| 2271 | if (debug & DEBUG_HFCMULTI_STATE) | ||
| 2272 | printk(KERN_DEBUG "%s: %s\n", __func__, msg); | ||
| 2273 | |||
| 2274 | id = TEI_SAPI | (GROUP_TEI << 8); /* manager address */ | ||
| 2275 | |||
| 2276 | skb = _alloc_mISDN_skb(MPH_INFORMATION_IND, id, sizeof(data), &data, | ||
| 2277 | GFP_ATOMIC); | ||
| 2278 | if (!skb) | ||
| 2279 | return; | ||
| 2280 | recv_Dchannel_skb(dch, skb); | ||
| 2281 | } | ||
| 2282 | |||
| 2283 | static inline void | ||
| 2284 | handle_timer_irq(struct hfc_multi *hc) | ||
| 2285 | { | ||
| 2286 | int ch, temp; | ||
| 2287 | struct dchannel *dch; | ||
| 2288 | u_long flags; | ||
| 2289 | |||
| 2290 | /* process queued resync jobs */ | ||
| 2291 | if (hc->e1_resync) { | ||
| 2292 | /* lock, so e1_resync gets not changed */ | ||
| 2293 | spin_lock_irqsave(&HFClock, flags); | ||
| 2294 | if (hc->e1_resync & 1) { | ||
| 2295 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
| 2296 | printk(KERN_DEBUG "Enable SYNC_I\n"); | ||
| 2297 | HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC); | ||
| 2298 | /* disable JATT, if RX_SYNC is set */ | ||
| 2299 | if (test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) | ||
| 2300 | HFC_outb(hc, R_SYNC_OUT, V_SYNC_E1_RX); | ||
| 2301 | } | ||
| 2302 | if (hc->e1_resync & 2) { | ||
| 2303 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
| 2304 | printk(KERN_DEBUG "Enable jatt PLL\n"); | ||
| 2305 | HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS); | ||
| 2306 | } | ||
| 2307 | if (hc->e1_resync & 4) { | ||
| 2308 | if (debug & DEBUG_HFCMULTI_PLXSD) | ||
| 2309 | printk(KERN_DEBUG | ||
| 2310 | "Enable QUARTZ for HFC-E1\n"); | ||
| 2311 | /* set jatt to quartz */ | ||
| 2312 | HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | ||
| 2313 | | V_JATT_OFF); | ||
| 2314 | /* switch to JATT, in case it is not already */ | ||
| 2315 | HFC_outb(hc, R_SYNC_OUT, 0); | ||
| 2316 | } | ||
| 2317 | hc->e1_resync = 0; | ||
| 2318 | spin_unlock_irqrestore(&HFClock, flags); | ||
| 2319 | } | ||
| 2320 | |||
| 2321 | if (hc->type != 1 || hc->e1_state == 1) | ||
| 2322 | for (ch = 0; ch <= 31; ch++) { | ||
| 2323 | if (hc->created[hc->chan[ch].port]) { | ||
| 2324 | hfcmulti_tx(hc, ch); | ||
| 2325 | /* fifo is started when switching to rx-fifo */ | ||
| 2326 | hfcmulti_rx(hc, ch); | ||
| 2327 | if (hc->chan[ch].dch && | ||
| 2328 | hc->chan[ch].nt_timer > -1) { | ||
| 2329 | dch = hc->chan[ch].dch; | ||
| 2330 | if (!(--hc->chan[ch].nt_timer)) { | ||
| 2331 | schedule_event(dch, | ||
| 2332 | FLG_PHCHANGE); | ||
| 2333 | if (debug & | ||
| 2334 | DEBUG_HFCMULTI_STATE) | ||
| 2335 | printk(KERN_DEBUG | ||
| 2336 | "%s: nt_timer at " | ||
| 2337 | "state %x\n", | ||
| 2338 | __func__, | ||
| 2339 | dch->state); | ||
| 2340 | } | ||
| 2341 | } | ||
| 2342 | } | ||
| 2343 | } | ||
| 2344 | if (hc->type == 1 && hc->created[0]) { | ||
| 2345 | dch = hc->chan[hc->dslot].dch; | ||
| 2346 | if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dslot].cfg)) { | ||
| 2347 | /* LOS */ | ||
| 2348 | temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_SIG_LOS; | ||
| 2349 | if (!temp && hc->chan[hc->dslot].los) | ||
| 2350 | signal_state_up(dch, L1_SIGNAL_LOS_ON, | ||
| 2351 | "LOS detected"); | ||
| 2352 | if (temp && !hc->chan[hc->dslot].los) | ||
| 2353 | signal_state_up(dch, L1_SIGNAL_LOS_OFF, | ||
| 2354 | "LOS gone"); | ||
| 2355 | hc->chan[hc->dslot].los = temp; | ||
| 2356 | } | ||
| 2357 | if (test_bit(HFC_CFG_REPORT_AIS, &hc->chan[hc->dslot].cfg)) { | ||
| 2358 | /* AIS */ | ||
| 2359 | temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_AIS; | ||
| 2360 | if (!temp && hc->chan[hc->dslot].ais) | ||
| 2361 | signal_state_up(dch, L1_SIGNAL_AIS_ON, | ||
| 2362 | "AIS detected"); | ||
| 2363 | if (temp && !hc->chan[hc->dslot].ais) | ||
| 2364 | signal_state_up(dch, L1_SIGNAL_AIS_OFF, | ||
| 2365 | "AIS gone"); | ||
| 2366 | hc->chan[hc->dslot].ais = temp; | ||
| 2367 | } | ||
| 2368 | if (test_bit(HFC_CFG_REPORT_SLIP, &hc->chan[hc->dslot].cfg)) { | ||
| 2369 | /* SLIP */ | ||
| 2370 | temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_RX; | ||
| 2371 | if (!temp && hc->chan[hc->dslot].slip_rx) | ||
| 2372 | signal_state_up(dch, L1_SIGNAL_SLIP_RX, | ||
| 2373 | " bit SLIP detected RX"); | ||
| 2374 | hc->chan[hc->dslot].slip_rx = temp; | ||
| 2375 | temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_TX; | ||
| 2376 | if (!temp && hc->chan[hc->dslot].slip_tx) | ||
| 2377 | signal_state_up(dch, L1_SIGNAL_SLIP_TX, | ||
| 2378 | " bit SLIP detected TX"); | ||
| 2379 | hc->chan[hc->dslot].slip_tx = temp; | ||
| 2380 | } | ||
| 2381 | if (test_bit(HFC_CFG_REPORT_RDI, &hc->chan[hc->dslot].cfg)) { | ||
| 2382 | /* RDI */ | ||
| 2383 | temp = HFC_inb_nodebug(hc, R_RX_SL0_0) & V_A; | ||
| 2384 | if (!temp && hc->chan[hc->dslot].rdi) | ||
| 2385 | signal_state_up(dch, L1_SIGNAL_RDI_ON, | ||
| 2386 | "RDI detected"); | ||
| 2387 | if (temp && !hc->chan[hc->dslot].rdi) | ||
| 2388 | signal_state_up(dch, L1_SIGNAL_RDI_OFF, | ||
| 2389 | "RDI gone"); | ||
| 2390 | hc->chan[hc->dslot].rdi = temp; | ||
| 2391 | } | ||
| 2392 | temp = HFC_inb_nodebug(hc, R_JATT_DIR); | ||
| 2393 | switch (hc->chan[hc->dslot].sync) { | ||
| 2394 | case 0: | ||
| 2395 | if ((temp & 0x60) == 0x60) { | ||
| 2396 | if (debug & DEBUG_HFCMULTI_SYNC) | ||
| 2397 | printk(KERN_DEBUG | ||
| 2398 | "%s: (id=%d) E1 now " | ||
| 2399 | "in clock sync\n", | ||
| 2400 | __func__, hc->id); | ||
| 2401 | HFC_outb(hc, R_RX_OFF, | ||
| 2402 | hc->chan[hc->dslot].jitter | V_RX_INIT); | ||
| 2403 | HFC_outb(hc, R_TX_OFF, | ||
| 2404 | hc->chan[hc->dslot].jitter | V_RX_INIT); | ||
| 2405 | hc->chan[hc->dslot].sync = 1; | ||
| 2406 | goto check_framesync; | ||
| 2407 | } | ||
| 2408 | break; | ||
| 2409 | case 1: | ||
| 2410 | if ((temp & 0x60) != 0x60) { | ||
| 2411 | if (debug & DEBUG_HFCMULTI_SYNC) | ||
| 2412 | printk(KERN_DEBUG | ||
| 2413 | "%s: (id=%d) E1 " | ||
| 2414 | "lost clock sync\n", | ||
| 2415 | __func__, hc->id); | ||
| 2416 | hc->chan[hc->dslot].sync = 0; | ||
| 2417 | break; | ||
| 2418 | } | ||
| 2419 | check_framesync: | ||
| 2420 | temp = HFC_inb_nodebug(hc, R_SYNC_STA); | ||
| 2421 | if (temp == 0x27) { | ||
| 2422 | if (debug & DEBUG_HFCMULTI_SYNC) | ||
| 2423 | printk(KERN_DEBUG | ||
| 2424 | "%s: (id=%d) E1 " | ||
| 2425 | "now in frame sync\n", | ||
| 2426 | __func__, hc->id); | ||
| 2427 | hc->chan[hc->dslot].sync = 2; | ||
| 2428 | } | ||
| 2429 | break; | ||
| 2430 | case 2: | ||
| 2431 | if ((temp & 0x60) != 0x60) { | ||
| 2432 | if (debug & DEBUG_HFCMULTI_SYNC) | ||
| 2433 | printk(KERN_DEBUG | ||
| 2434 | "%s: (id=%d) E1 lost " | ||
| 2435 | "clock & frame sync\n", | ||
| 2436 | __func__, hc->id); | ||
| 2437 | hc->chan[hc->dslot].sync = 0; | ||
| 2438 | break; | ||
| 2439 | } | ||
| 2440 | temp = HFC_inb_nodebug(hc, R_SYNC_STA); | ||
| 2441 | if (temp != 0x27) { | ||
| 2442 | if (debug & DEBUG_HFCMULTI_SYNC) | ||
| 2443 | printk(KERN_DEBUG | ||
| 2444 | "%s: (id=%d) E1 " | ||
| 2445 | "lost frame sync\n", | ||
| 2446 | __func__, hc->id); | ||
| 2447 | hc->chan[hc->dslot].sync = 1; | ||
| 2448 | } | ||
| 2449 | break; | ||
| 2450 | } | ||
| 2451 | } | ||
| 2452 | |||
| 2453 | if (test_bit(HFC_CHIP_WATCHDOG, &hc->chip)) | ||
| 2454 | hfcmulti_watchdog(hc); | ||
| 2455 | |||
| 2456 | if (hc->leds) | ||
| 2457 | hfcmulti_leds(hc); | ||
| 2458 | } | ||
| 2459 | |||
| 2460 | static void | ||
| 2461 | ph_state_irq(struct hfc_multi *hc, u_char r_irq_statech) | ||
| 2462 | { | ||
| 2463 | struct dchannel *dch; | ||
| 2464 | int ch; | ||
| 2465 | int active; | ||
| 2466 | u_char st_status, temp; | ||
| 2467 | |||
| 2468 | /* state machine */ | ||
| 2469 | for (ch = 0; ch <= 31; ch++) { | ||
| 2470 | if (hc->chan[ch].dch) { | ||
| 2471 | dch = hc->chan[ch].dch; | ||
| 2472 | if (r_irq_statech & 1) { | ||
| 2473 | HFC_outb_nodebug(hc, R_ST_SEL, | ||
| 2474 | hc->chan[ch].port); | ||
| 2475 | /* undocumented: delay after R_ST_SEL */ | ||
| 2476 | udelay(1); | ||
| 2477 | /* undocumented: status changes during read */ | ||
| 2478 | st_status = HFC_inb_nodebug(hc, A_ST_RD_STATE); | ||
| 2479 | while (st_status != (temp = | ||
| 2480 | HFC_inb_nodebug(hc, A_ST_RD_STATE))) { | ||
| 2481 | if (debug & DEBUG_HFCMULTI_STATE) | ||
| 2482 | printk(KERN_DEBUG "%s: reread " | ||
| 2483 | "STATE because %d!=%d\n", | ||
| 2484 | __func__, temp, | ||
| 2485 | st_status); | ||
| 2486 | st_status = temp; /* repeat */ | ||
| 2487 | } | ||
| 2488 | |||
| 2489 | /* Speech Design TE-sync indication */ | ||
| 2490 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip) && | ||
| 2491 | dch->dev.D.protocol == ISDN_P_TE_S0) { | ||
| 2492 | if (st_status & V_FR_SYNC_ST) | ||
| 2493 | hc->syncronized |= | ||
| 2494 | (1 << hc->chan[ch].port); | ||
| 2495 | else | ||
| 2496 | hc->syncronized &= | ||
| 2497 | ~(1 << hc->chan[ch].port); | ||
| 2498 | } | ||
| 2499 | dch->state = st_status & 0x0f; | ||
| 2500 | if (dch->dev.D.protocol == ISDN_P_NT_S0) | ||
| 2501 | active = 3; | ||
| 2502 | else | ||
| 2503 | active = 7; | ||
| 2504 | if (dch->state == active) { | ||
| 2505 | HFC_outb_nodebug(hc, R_FIFO, | ||
| 2506 | (ch << 1) | 1); | ||
| 2507 | HFC_wait_nodebug(hc); | ||
| 2508 | HFC_outb_nodebug(hc, | ||
| 2509 | R_INC_RES_FIFO, V_RES_F); | ||
| 2510 | HFC_wait_nodebug(hc); | ||
| 2511 | dch->tx_idx = 0; | ||
| 2512 | } | ||
| 2513 | schedule_event(dch, FLG_PHCHANGE); | ||
| 2514 | if (debug & DEBUG_HFCMULTI_STATE) | ||
| 2515 | printk(KERN_DEBUG | ||
| 2516 | "%s: S/T newstate %x port %d\n", | ||
| 2517 | __func__, dch->state, | ||
| 2518 | hc->chan[ch].port); | ||
| 2519 | } | ||
| 2520 | r_irq_statech >>= 1; | ||
| 2521 | } | ||
| 2522 | } | ||
| 2523 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) | ||
| 2524 | plxsd_checksync(hc, 0); | ||
| 2525 | } | ||
| 2526 | |||
| 2527 | static void | ||
| 2528 | fifo_irq(struct hfc_multi *hc, int block) | ||
| 2529 | { | ||
| 2530 | int ch, j; | ||
| 2531 | struct dchannel *dch; | ||
| 2532 | struct bchannel *bch; | ||
| 2533 | u_char r_irq_fifo_bl; | ||
| 2534 | |||
| 2535 | r_irq_fifo_bl = HFC_inb_nodebug(hc, R_IRQ_FIFO_BL0 + block); | ||
| 2536 | j = 0; | ||
| 2537 | while (j < 8) { | ||
| 2538 | ch = (block << 2) + (j >> 1); | ||
| 2539 | dch = hc->chan[ch].dch; | ||
| 2540 | bch = hc->chan[ch].bch; | ||
| 2541 | if (((!dch) && (!bch)) || (!hc->created[hc->chan[ch].port])) { | ||
| 2542 | j += 2; | ||
| 2543 | continue; | ||
| 2544 | } | ||
| 2545 | if (dch && (r_irq_fifo_bl & (1 << j)) && | ||
| 2546 | test_bit(FLG_ACTIVE, &dch->Flags)) { | ||
| 2547 | hfcmulti_tx(hc, ch); | ||
| 2548 | /* start fifo */ | ||
| 2549 | HFC_outb_nodebug(hc, R_FIFO, 0); | ||
| 2550 | HFC_wait_nodebug(hc); | ||
| 2551 | } | ||
| 2552 | if (bch && (r_irq_fifo_bl & (1 << j)) && | ||
| 2553 | test_bit(FLG_ACTIVE, &bch->Flags)) { | ||
| 2554 | hfcmulti_tx(hc, ch); | ||
| 2555 | /* start fifo */ | ||
| 2556 | HFC_outb_nodebug(hc, R_FIFO, 0); | ||
| 2557 | HFC_wait_nodebug(hc); | ||
| 2558 | } | ||
| 2559 | j++; | ||
| 2560 | if (dch && (r_irq_fifo_bl & (1 << j)) && | ||
| 2561 | test_bit(FLG_ACTIVE, &dch->Flags)) { | ||
| 2562 | hfcmulti_rx(hc, ch); | ||
| 2563 | } | ||
| 2564 | if (bch && (r_irq_fifo_bl & (1 << j)) && | ||
| 2565 | test_bit(FLG_ACTIVE, &bch->Flags)) { | ||
| 2566 | hfcmulti_rx(hc, ch); | ||
| 2567 | } | ||
| 2568 | j++; | ||
| 2569 | } | ||
| 2570 | } | ||
| 2571 | |||
| 2572 | #ifdef IRQ_DEBUG | ||
| 2573 | int irqsem; | ||
| 2574 | #endif | ||
| 2575 | static irqreturn_t | ||
| 2576 | hfcmulti_interrupt(int intno, void *dev_id) | ||
| 2577 | { | ||
| 2578 | #ifdef IRQCOUNT_DEBUG | ||
| 2579 | static int iq1 = 0, iq2 = 0, iq3 = 0, iq4 = 0, | ||
| 2580 | iq5 = 0, iq6 = 0, iqcnt = 0; | ||
| 2581 | #endif | ||
| 2582 | static int count; | ||
| 2583 | struct hfc_multi *hc = dev_id; | ||
| 2584 | struct dchannel *dch; | ||
| 2585 | u_char r_irq_statech, status, r_irq_misc, r_irq_oview; | ||
| 2586 | int i; | ||
| 2587 | u_short *plx_acc, wval; | ||
| 2588 | u_char e1_syncsta, temp; | ||
| 2589 | u_long flags; | ||
| 2590 | |||
| 2591 | if (!hc) { | ||
| 2592 | printk(KERN_ERR "HFC-multi: Spurious interrupt!\n"); | ||
| 2593 | return IRQ_NONE; | ||
| 2594 | } | ||
| 2595 | |||
| 2596 | spin_lock(&hc->lock); | ||
| 2597 | |||
| 2598 | #ifdef IRQ_DEBUG | ||
| 2599 | if (irqsem) | ||
| 2600 | printk(KERN_ERR "irq for card %d during irq from " | ||
| 2601 | "card %d, this is no bug.\n", hc->id + 1, irqsem); | ||
| 2602 | irqsem = hc->id + 1; | ||
| 2603 | #endif | ||
| 2604 | |||
| 2605 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
| 2606 | spin_lock_irqsave(&plx_lock, flags); | ||
| 2607 | plx_acc = (u_short *)(hc->plx_membase + PLX_INTCSR); | ||
| 2608 | wval = readw(plx_acc); | ||
| 2609 | spin_unlock_irqrestore(&plx_lock, flags); | ||
| 2610 | if (!(wval & PLX_INTCSR_LINTI1_STATUS)) | ||
| 2611 | goto irq_notforus; | ||
| 2612 | } | ||
| 2613 | |||
| 2614 | status = HFC_inb_nodebug(hc, R_STATUS); | ||
| 2615 | r_irq_statech = HFC_inb_nodebug(hc, R_IRQ_STATECH); | ||
| 2616 | #ifdef IRQCOUNT_DEBUG | ||
| 2617 | if (r_irq_statech) | ||
| 2618 | iq1++; | ||
| 2619 | if (status & V_DTMF_STA) | ||
| 2620 | iq2++; | ||
| 2621 | if (status & V_LOST_STA) | ||
| 2622 | iq3++; | ||
| 2623 | if (status & V_EXT_IRQSTA) | ||
| 2624 | iq4++; | ||
| 2625 | if (status & V_MISC_IRQSTA) | ||
| 2626 | iq5++; | ||
| 2627 | if (status & V_FR_IRQSTA) | ||
| 2628 | iq6++; | ||
| 2629 | if (iqcnt++ > 5000) { | ||
| 2630 | printk(KERN_ERR "iq1:%x iq2:%x iq3:%x iq4:%x iq5:%x iq6:%x\n", | ||
| 2631 | iq1, iq2, iq3, iq4, iq5, iq6); | ||
| 2632 | iqcnt = 0; | ||
| 2633 | } | ||
| 2634 | #endif | ||
| 2635 | if (!r_irq_statech && | ||
| 2636 | !(status & (V_DTMF_STA | V_LOST_STA | V_EXT_IRQSTA | | ||
| 2637 | V_MISC_IRQSTA | V_FR_IRQSTA))) { | ||
| 2638 | /* irq is not for us */ | ||
| 2639 | goto irq_notforus; | ||
| 2640 | } | ||
| 2641 | hc->irqcnt++; | ||
| 2642 | if (r_irq_statech) { | ||
| 2643 | if (hc->type != 1) | ||
| 2644 | ph_state_irq(hc, r_irq_statech); | ||
| 2645 | } | ||
| 2646 | if (status & V_EXT_IRQSTA) | ||
| 2647 | ; /* external IRQ */ | ||
| 2648 | if (status & V_LOST_STA) { | ||
| 2649 | /* LOST IRQ */ | ||
| 2650 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_LOST); /* clear irq! */ | ||
| 2651 | } | ||
| 2652 | if (status & V_MISC_IRQSTA) { | ||
| 2653 | /* misc IRQ */ | ||
| 2654 | r_irq_misc = HFC_inb_nodebug(hc, R_IRQ_MISC); | ||
| 2655 | if (r_irq_misc & V_STA_IRQ) { | ||
| 2656 | if (hc->type == 1) { | ||
| 2657 | /* state machine */ | ||
| 2658 | dch = hc->chan[hc->dslot].dch; | ||
| 2659 | e1_syncsta = HFC_inb_nodebug(hc, R_SYNC_STA); | ||
| 2660 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip) | ||
| 2661 | && hc->e1_getclock) { | ||
| 2662 | if (e1_syncsta & V_FR_SYNC_E1) | ||
| 2663 | hc->syncronized = 1; | ||
| 2664 | else | ||
| 2665 | hc->syncronized = 0; | ||
| 2666 | } | ||
| 2667 | /* undocumented: status changes during read */ | ||
| 2668 | dch->state = HFC_inb_nodebug(hc, R_E1_RD_STA); | ||
| 2669 | while (dch->state != (temp = | ||
| 2670 | HFC_inb_nodebug(hc, R_E1_RD_STA))) { | ||
| 2671 | if (debug & DEBUG_HFCMULTI_STATE) | ||
| 2672 | printk(KERN_DEBUG "%s: reread " | ||
| 2673 | "STATE because %d!=%d\n", | ||
| 2674 | __func__, temp, | ||
| 2675 | dch->state); | ||
| 2676 | dch->state = temp; /* repeat */ | ||
| 2677 | } | ||
| 2678 | dch->state = HFC_inb_nodebug(hc, R_E1_RD_STA) | ||
| 2679 | & 0x7; | ||
| 2680 | schedule_event(dch, FLG_PHCHANGE); | ||
| 2681 | if (debug & DEBUG_HFCMULTI_STATE) | ||
| 2682 | printk(KERN_DEBUG | ||
| 2683 | "%s: E1 (id=%d) newstate %x\n", | ||
| 2684 | __func__, hc->id, dch->state); | ||
| 2685 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) | ||
| 2686 | plxsd_checksync(hc, 0); | ||
| 2687 | } | ||
| 2688 | } | ||
| 2689 | if (r_irq_misc & V_TI_IRQ) | ||
| 2690 | handle_timer_irq(hc); | ||
| 2691 | |||
| 2692 | if (r_irq_misc & V_DTMF_IRQ) { | ||
| 2693 | /* -> DTMF IRQ */ | ||
| 2694 | hfcmulti_dtmf(hc); | ||
| 2695 | } | ||
| 2696 | /* TODO: REPLACE !!!! 125 us Interrupts are not acceptable */ | ||
| 2697 | if (r_irq_misc & V_IRQ_PROC) { | ||
| 2698 | /* IRQ every 125us */ | ||
| 2699 | count++; | ||
| 2700 | /* generate 1kHz signal */ | ||
| 2701 | if (count == 8) { | ||
| 2702 | if (hfc_interrupt) | ||
| 2703 | hfc_interrupt(); | ||
| 2704 | count = 0; | ||
| 2705 | } | ||
| 2706 | } | ||
| 2707 | |||
| 2708 | } | ||
| 2709 | if (status & V_FR_IRQSTA) { | ||
| 2710 | /* FIFO IRQ */ | ||
| 2711 | r_irq_oview = HFC_inb_nodebug(hc, R_IRQ_OVIEW); | ||
| 2712 | for (i = 0; i < 8; i++) { | ||
| 2713 | if (r_irq_oview & (1 << i)) | ||
| 2714 | fifo_irq(hc, i); | ||
| 2715 | } | ||
| 2716 | } | ||
| 2717 | |||
| 2718 | #ifdef IRQ_DEBUG | ||
| 2719 | irqsem = 0; | ||
| 2720 | #endif | ||
| 2721 | spin_unlock(&hc->lock); | ||
| 2722 | return IRQ_HANDLED; | ||
| 2723 | |||
| 2724 | irq_notforus: | ||
| 2725 | #ifdef IRQ_DEBUG | ||
| 2726 | irqsem = 0; | ||
| 2727 | #endif | ||
| 2728 | spin_unlock(&hc->lock); | ||
| 2729 | return IRQ_NONE; | ||
| 2730 | } | ||
| 2731 | |||
| 2732 | |||
| 2733 | /* | ||
| 2734 | * timer callback for D-chan busy resolution. Currently no function | ||
| 2735 | */ | ||
| 2736 | |||
| 2737 | static void | ||
| 2738 | hfcmulti_dbusy_timer(struct hfc_multi *hc) | ||
| 2739 | { | ||
| 2740 | } | ||
| 2741 | |||
| 2742 | |||
| 2743 | /* | ||
| 2744 | * activate/deactivate hardware for selected channels and mode | ||
| 2745 | * | ||
| 2746 | * configure B-channel with the given protocol | ||
| 2747 | * ch eqals to the HFC-channel (0-31) | ||
| 2748 | * ch is the number of channel (0-4,4-7,8-11,12-15,16-19,20-23,24-27,28-31 | ||
| 2749 | * for S/T, 1-31 for E1) | ||
| 2750 | * the hdlc interrupts will be set/unset | ||
| 2751 | */ | ||
| 2752 | static int | ||
| 2753 | mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, | ||
| 2754 | int bank_tx, int slot_rx, int bank_rx) | ||
| 2755 | { | ||
| 2756 | int flow_tx = 0, flow_rx = 0, routing = 0; | ||
| 2757 | int oslot_tx, oslot_rx; | ||
| 2758 | int conf; | ||
| 2759 | |||
| 2760 | if (ch < 0 || ch > 31) | ||
| 2761 | return EINVAL; | ||
| 2762 | oslot_tx = hc->chan[ch].slot_tx; | ||
| 2763 | oslot_rx = hc->chan[ch].slot_rx; | ||
| 2764 | conf = hc->chan[ch].conf; | ||
| 2765 | |||
| 2766 | if (debug & DEBUG_HFCMULTI_MODE) | ||
| 2767 | printk(KERN_DEBUG | ||
| 2768 | "%s: card %d channel %d protocol %x slot old=%d new=%d " | ||
| 2769 | "bank new=%d (TX) slot old=%d new=%d bank new=%d (RX)\n", | ||
| 2770 | __func__, hc->id, ch, protocol, oslot_tx, slot_tx, | ||
| 2771 | bank_tx, oslot_rx, slot_rx, bank_rx); | ||
| 2772 | |||
| 2773 | if (oslot_tx >= 0 && slot_tx != oslot_tx) { | ||
| 2774 | /* remove from slot */ | ||
| 2775 | if (debug & DEBUG_HFCMULTI_MODE) | ||
| 2776 | printk(KERN_DEBUG "%s: remove from slot %d (TX)\n", | ||
| 2777 | __func__, oslot_tx); | ||
| 2778 | if (hc->slot_owner[oslot_tx<<1] == ch) { | ||
| 2779 | HFC_outb(hc, R_SLOT, oslot_tx << 1); | ||
| 2780 | HFC_outb(hc, A_SL_CFG, 0); | ||
| 2781 | HFC_outb(hc, A_CONF, 0); | ||
| 2782 | hc->slot_owner[oslot_tx<<1] = -1; | ||
| 2783 | } else { | ||
| 2784 | if (debug & DEBUG_HFCMULTI_MODE) | ||
| 2785 | printk(KERN_DEBUG | ||
| 2786 | "%s: we are not owner of this tx slot " | ||
| 2787 | "anymore, channel %d is.\n", | ||
| 2788 | __func__, hc->slot_owner[oslot_tx<<1]); | ||
| 2789 | } | ||
| 2790 | } | ||
| 2791 | |||
| 2792 | if (oslot_rx >= 0 && slot_rx != oslot_rx) { | ||
| 2793 | /* remove from slot */ | ||
| 2794 | if (debug & DEBUG_HFCMULTI_MODE) | ||
| 2795 | printk(KERN_DEBUG | ||
| 2796 | "%s: remove from slot %d (RX)\n", | ||
| 2797 | __func__, oslot_rx); | ||
| 2798 | if (hc->slot_owner[(oslot_rx << 1) | 1] == ch) { | ||
| 2799 | HFC_outb(hc, R_SLOT, (oslot_rx << 1) | V_SL_DIR); | ||
| 2800 | HFC_outb(hc, A_SL_CFG, 0); | ||
| 2801 | hc->slot_owner[(oslot_rx << 1) | 1] = -1; | ||
| 2802 | } else { | ||
| 2803 | if (debug & DEBUG_HFCMULTI_MODE) | ||
| 2804 | printk(KERN_DEBUG | ||
| 2805 | "%s: we are not owner of this rx slot " | ||
| 2806 | "anymore, channel %d is.\n", | ||
| 2807 | __func__, | ||
| 2808 | hc->slot_owner[(oslot_rx << 1) | 1]); | ||
| 2809 | } | ||
| 2810 | } | ||
| 2811 | |||
| 2812 | if (slot_tx < 0) { | ||
| 2813 | flow_tx = 0x80; /* FIFO->ST */ | ||
| 2814 | /* disable pcm slot */ | ||
| 2815 | hc->chan[ch].slot_tx = -1; | ||
| 2816 | hc->chan[ch].bank_tx = 0; | ||
| 2817 | } else { | ||
| 2818 | /* set pcm slot */ | ||
| 2819 | if (hc->chan[ch].txpending) | ||
| 2820 | flow_tx = 0x80; /* FIFO->ST */ | ||
| 2821 | else | ||
| 2822 | flow_tx = 0xc0; /* PCM->ST */ | ||
| 2823 | /* put on slot */ | ||
| 2824 | routing = bank_tx ? 0xc0 : 0x80; | ||
| 2825 | if (conf >= 0 || bank_tx > 1) | ||
| 2826 | routing = 0x40; /* loop */ | ||
| 2827 | if (debug & DEBUG_HFCMULTI_MODE) | ||
| 2828 | printk(KERN_DEBUG "%s: put channel %d to slot %d bank" | ||
| 2829 | " %d flow %02x routing %02x conf %d (TX)\n", | ||
| 2830 | __func__, ch, slot_tx, bank_tx, | ||
| 2831 | flow_tx, routing, conf); | ||
| 2832 | HFC_outb(hc, R_SLOT, slot_tx << 1); | ||
| 2833 | HFC_outb(hc, A_SL_CFG, (ch<<1) | routing); | ||
| 2834 | HFC_outb(hc, A_CONF, (conf < 0) ? 0 : (conf | V_CONF_SL)); | ||
| 2835 | hc->slot_owner[slot_tx << 1] = ch; | ||
| 2836 | hc->chan[ch].slot_tx = slot_tx; | ||
| 2837 | hc->chan[ch].bank_tx = bank_tx; | ||
| 2838 | } | ||
| 2839 | if (slot_rx < 0) { | ||
| 2840 | /* disable pcm slot */ | ||
| 2841 | flow_rx = 0x80; /* ST->FIFO */ | ||
| 2842 | hc->chan[ch].slot_rx = -1; | ||
| 2843 | hc->chan[ch].bank_rx = 0; | ||
| 2844 | } else { | ||
| 2845 | /* set pcm slot */ | ||
| 2846 | if (hc->chan[ch].txpending) | ||
| 2847 | flow_rx = 0x80; /* ST->FIFO */ | ||
| 2848 | else | ||
| 2849 | flow_rx = 0xc0; /* ST->(FIFO,PCM) */ | ||
| 2850 | /* put on slot */ | ||
| 2851 | routing = bank_rx?0x80:0xc0; /* reversed */ | ||
| 2852 | if (conf >= 0 || bank_rx > 1) | ||
| 2853 | routing = 0x40; /* loop */ | ||
| 2854 | if (debug & DEBUG_HFCMULTI_MODE) | ||
| 2855 | printk(KERN_DEBUG "%s: put channel %d to slot %d bank" | ||
| 2856 | " %d flow %02x routing %02x conf %d (RX)\n", | ||
| 2857 | __func__, ch, slot_rx, bank_rx, | ||
| 2858 | flow_rx, routing, conf); | ||
| 2859 | HFC_outb(hc, R_SLOT, (slot_rx<<1) | V_SL_DIR); | ||
| 2860 | HFC_outb(hc, A_SL_CFG, (ch<<1) | V_CH_DIR | routing); | ||
| 2861 | hc->slot_owner[(slot_rx<<1)|1] = ch; | ||
| 2862 | hc->chan[ch].slot_rx = slot_rx; | ||
| 2863 | hc->chan[ch].bank_rx = bank_rx; | ||
| 2864 | } | ||
| 2865 | |||
| 2866 | switch (protocol) { | ||
| 2867 | case (ISDN_P_NONE): | ||
| 2868 | /* disable TX fifo */ | ||
| 2869 | HFC_outb(hc, R_FIFO, ch << 1); | ||
| 2870 | HFC_wait(hc); | ||
| 2871 | HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | V_IFF); | ||
| 2872 | HFC_outb(hc, A_SUBCH_CFG, 0); | ||
| 2873 | HFC_outb(hc, A_IRQ_MSK, 0); | ||
| 2874 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | ||
| 2875 | HFC_wait(hc); | ||
| 2876 | /* disable RX fifo */ | ||
| 2877 | HFC_outb(hc, R_FIFO, (ch<<1)|1); | ||
| 2878 | HFC_wait(hc); | ||
| 2879 | HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00); | ||
| 2880 | HFC_outb(hc, A_SUBCH_CFG, 0); | ||
| 2881 | HFC_outb(hc, A_IRQ_MSK, 0); | ||
| 2882 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | ||
| 2883 | HFC_wait(hc); | ||
| 2884 | if (hc->chan[ch].bch && hc->type != 1) { | ||
| 2885 | hc->hw.a_st_ctrl0[hc->chan[ch].port] &= | ||
| 2886 | ((ch & 0x3) == 0)? ~V_B1_EN: ~V_B2_EN; | ||
| 2887 | HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); | ||
| 2888 | /* undocumented: delay after R_ST_SEL */ | ||
| 2889 | udelay(1); | ||
| 2890 | HFC_outb(hc, A_ST_CTRL0, | ||
| 2891 | hc->hw.a_st_ctrl0[hc->chan[ch].port]); | ||
| 2892 | } | ||
| 2893 | if (hc->chan[ch].bch) { | ||
| 2894 | test_and_clear_bit(FLG_HDLC, &hc->chan[ch].bch->Flags); | ||
| 2895 | test_and_clear_bit(FLG_TRANSPARENT, | ||
| 2896 | &hc->chan[ch].bch->Flags); | ||
| 2897 | } | ||
| 2898 | break; | ||
| 2899 | case (ISDN_P_B_RAW): /* B-channel */ | ||
| 2900 | |||
| 2901 | if (test_bit(HFC_CHIP_B410P, &hc->chip) && | ||
| 2902 | (hc->chan[ch].slot_rx < 0) && | ||
| 2903 | (hc->chan[ch].slot_tx < 0)) { | ||
| 2904 | |||
| 2905 | printk(KERN_DEBUG | ||
| 2906 | "Setting B-channel %d to echo cancelable " | ||
| 2907 | "state on PCM slot %d\n", ch, | ||
| 2908 | ((ch / 4) * 8) + ((ch % 4) * 4) + 1); | ||
| 2909 | printk(KERN_DEBUG | ||
| 2910 | "Enabling pass through for channel\n"); | ||
| 2911 | vpm_out(hc, ch, ((ch / 4) * 8) + | ||
| 2912 | ((ch % 4) * 4) + 1, 0x01); | ||
| 2913 | /* rx path */ | ||
| 2914 | /* S/T -> PCM */ | ||
| 2915 | HFC_outb(hc, R_FIFO, (ch << 1)); | ||
| 2916 | HFC_wait(hc); | ||
| 2917 | HFC_outb(hc, A_CON_HDLC, 0xc0 | V_HDLC_TRP | V_IFF); | ||
| 2918 | HFC_outb(hc, R_SLOT, (((ch / 4) * 8) + | ||
| 2919 | ((ch % 4) * 4) + 1) << 1); | ||
| 2920 | HFC_outb(hc, A_SL_CFG, 0x80 | (ch << 1)); | ||
| 2921 | |||
| 2922 | /* PCM -> FIFO */ | ||
| 2923 | HFC_outb(hc, R_FIFO, 0x20 | (ch << 1) | 1); | ||
| 2924 | HFC_wait(hc); | ||
| 2925 | HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF); | ||
| 2926 | HFC_outb(hc, A_SUBCH_CFG, 0); | ||
| 2927 | HFC_outb(hc, A_IRQ_MSK, 0); | ||
| 2928 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | ||
| 2929 | HFC_wait(hc); | ||
| 2930 | HFC_outb(hc, R_SLOT, ((((ch / 4) * 8) + | ||
| 2931 | ((ch % 4) * 4) + 1) << 1) | 1); | ||
| 2932 | HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1) | 1); | ||
| 2933 | |||
| 2934 | /* tx path */ | ||
| 2935 | /* PCM -> S/T */ | ||
| 2936 | HFC_outb(hc, R_FIFO, (ch << 1) | 1); | ||
| 2937 | HFC_wait(hc); | ||
| 2938 | HFC_outb(hc, A_CON_HDLC, 0xc0 | V_HDLC_TRP | V_IFF); | ||
| 2939 | HFC_outb(hc, R_SLOT, ((((ch / 4) * 8) + | ||
| 2940 | ((ch % 4) * 4)) << 1) | 1); | ||
| 2941 | HFC_outb(hc, A_SL_CFG, 0x80 | 0x40 | (ch << 1) | 1); | ||
| 2942 | |||
| 2943 | /* FIFO -> PCM */ | ||
| 2944 | HFC_outb(hc, R_FIFO, 0x20 | (ch << 1)); | ||
| 2945 | HFC_wait(hc); | ||
| 2946 | HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF); | ||
| 2947 | HFC_outb(hc, A_SUBCH_CFG, 0); | ||
| 2948 | HFC_outb(hc, A_IRQ_MSK, 0); | ||
| 2949 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | ||
| 2950 | HFC_wait(hc); | ||
| 2951 | /* tx silence */ | ||
| 2952 | HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, silence); | ||
| 2953 | HFC_outb(hc, R_SLOT, (((ch / 4) * 8) + | ||
| 2954 | ((ch % 4) * 4)) << 1); | ||
| 2955 | HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1)); | ||
| 2956 | } else { | ||
| 2957 | /* enable TX fifo */ | ||
| 2958 | HFC_outb(hc, R_FIFO, ch << 1); | ||
| 2959 | HFC_wait(hc); | ||
| 2960 | HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | | ||
| 2961 | V_HDLC_TRP | V_IFF); | ||
| 2962 | HFC_outb(hc, A_SUBCH_CFG, 0); | ||
| 2963 | HFC_outb(hc, A_IRQ_MSK, 0); | ||
| 2964 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | ||
| 2965 | HFC_wait(hc); | ||
| 2966 | /* tx silence */ | ||
| 2967 | HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, silence); | ||
| 2968 | /* enable RX fifo */ | ||
| 2969 | HFC_outb(hc, R_FIFO, (ch<<1)|1); | ||
| 2970 | HFC_wait(hc); | ||
| 2971 | HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00 | V_HDLC_TRP); | ||
| 2972 | HFC_outb(hc, A_SUBCH_CFG, 0); | ||
| 2973 | HFC_outb(hc, A_IRQ_MSK, 0); | ||
| 2974 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | ||
| 2975 | HFC_wait(hc); | ||
| 2976 | } | ||
| 2977 | if (hc->type != 1) { | ||
| 2978 | hc->hw.a_st_ctrl0[hc->chan[ch].port] |= | ||
| 2979 | ((ch & 0x3) == 0) ? V_B1_EN : V_B2_EN; | ||
| 2980 | HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); | ||
| 2981 | /* undocumented: delay after R_ST_SEL */ | ||
| 2982 | udelay(1); | ||
| 2983 | HFC_outb(hc, A_ST_CTRL0, | ||
| 2984 | hc->hw.a_st_ctrl0[hc->chan[ch].port]); | ||
| 2985 | } | ||
| 2986 | if (hc->chan[ch].bch) | ||
| 2987 | test_and_set_bit(FLG_TRANSPARENT, | ||
| 2988 | &hc->chan[ch].bch->Flags); | ||
| 2989 | break; | ||
| 2990 | case (ISDN_P_B_HDLC): /* B-channel */ | ||
| 2991 | case (ISDN_P_TE_S0): /* D-channel */ | ||
| 2992 | case (ISDN_P_NT_S0): | ||
| 2993 | case (ISDN_P_TE_E1): | ||
| 2994 | case (ISDN_P_NT_E1): | ||
| 2995 | /* enable TX fifo */ | ||
| 2996 | HFC_outb(hc, R_FIFO, ch<<1); | ||
| 2997 | HFC_wait(hc); | ||
| 2998 | if (hc->type == 1 || hc->chan[ch].bch) { | ||
| 2999 | /* E1 or B-channel */ | ||
| 3000 | HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04); | ||
| 3001 | HFC_outb(hc, A_SUBCH_CFG, 0); | ||
| 3002 | } else { | ||
| 3003 | /* D-Channel without HDLC fill flags */ | ||
| 3004 | HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04 | V_IFF); | ||
| 3005 | HFC_outb(hc, A_SUBCH_CFG, 2); | ||
| 3006 | } | ||
| 3007 | HFC_outb(hc, A_IRQ_MSK, V_IRQ); | ||
| 3008 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | ||
| 3009 | HFC_wait(hc); | ||
| 3010 | /* enable RX fifo */ | ||
| 3011 | HFC_outb(hc, R_FIFO, (ch<<1)|1); | ||
| 3012 | HFC_wait(hc); | ||
| 3013 | HFC_outb(hc, A_CON_HDLC, flow_rx | 0x04); | ||
| 3014 | if (hc->type == 1 || hc->chan[ch].bch) | ||
| 3015 | HFC_outb(hc, A_SUBCH_CFG, 0); /* full 8 bits */ | ||
| 3016 | else | ||
| 3017 | HFC_outb(hc, A_SUBCH_CFG, 2); /* 2 bits dchannel */ | ||
| 3018 | HFC_outb(hc, A_IRQ_MSK, V_IRQ); | ||
| 3019 | HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); | ||
| 3020 | HFC_wait(hc); | ||
| 3021 | if (hc->chan[ch].bch) { | ||
| 3022 | test_and_set_bit(FLG_HDLC, &hc->chan[ch].bch->Flags); | ||
| 3023 | if (hc->type != 1) { | ||
| 3024 | hc->hw.a_st_ctrl0[hc->chan[ch].port] |= | ||
| 3025 | ((ch&0x3) == 0) ? V_B1_EN : V_B2_EN; | ||
| 3026 | HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); | ||
| 3027 | /* undocumented: delay after R_ST_SEL */ | ||
| 3028 | udelay(1); | ||
| 3029 | HFC_outb(hc, A_ST_CTRL0, | ||
| 3030 | hc->hw.a_st_ctrl0[hc->chan[ch].port]); | ||
| 3031 | } | ||
| 3032 | } | ||
| 3033 | break; | ||
| 3034 | default: | ||
| 3035 | printk(KERN_DEBUG "%s: protocol not known %x\n", | ||
| 3036 | __func__, protocol); | ||
| 3037 | hc->chan[ch].protocol = ISDN_P_NONE; | ||
| 3038 | return -ENOPROTOOPT; | ||
| 3039 | } | ||
| 3040 | hc->chan[ch].protocol = protocol; | ||
| 3041 | return 0; | ||
| 3042 | } | ||
| 3043 | |||
| 3044 | |||
| 3045 | /* | ||
| 3046 | * connect/disconnect PCM | ||
| 3047 | */ | ||
| 3048 | |||
| 3049 | static void | ||
| 3050 | hfcmulti_pcm(struct hfc_multi *hc, int ch, int slot_tx, int bank_tx, | ||
| 3051 | int slot_rx, int bank_rx) | ||
| 3052 | { | ||
| 3053 | if (slot_rx < 0 || slot_rx < 0 || bank_tx < 0 || bank_rx < 0) { | ||
| 3054 | /* disable PCM */ | ||
| 3055 | mode_hfcmulti(hc, ch, hc->chan[ch].protocol, -1, 0, -1, 0); | ||
| 3056 | return; | ||
| 3057 | } | ||
| 3058 | |||
| 3059 | /* enable pcm */ | ||
| 3060 | mode_hfcmulti(hc, ch, hc->chan[ch].protocol, slot_tx, bank_tx, | ||
| 3061 | slot_rx, bank_rx); | ||
| 3062 | } | ||
| 3063 | |||
| 3064 | /* | ||
| 3065 | * set/disable conference | ||
| 3066 | */ | ||
| 3067 | |||
| 3068 | static void | ||
| 3069 | hfcmulti_conf(struct hfc_multi *hc, int ch, int num) | ||
| 3070 | { | ||
| 3071 | if (num >= 0 && num <= 7) | ||
| 3072 | hc->chan[ch].conf = num; | ||
| 3073 | else | ||
| 3074 | hc->chan[ch].conf = -1; | ||
| 3075 | mode_hfcmulti(hc, ch, hc->chan[ch].protocol, hc->chan[ch].slot_tx, | ||
| 3076 | hc->chan[ch].bank_tx, hc->chan[ch].slot_rx, | ||
| 3077 | hc->chan[ch].bank_rx); | ||
| 3078 | } | ||
| 3079 | |||
| 3080 | |||
| 3081 | /* | ||
| 3082 | * set/disable sample loop | ||
| 3083 | */ | ||
| 3084 | |||
| 3085 | /* NOTE: this function is experimental and therefore disabled */ | ||
| 3086 | |||
| 3087 | /* | ||
| 3088 | * Layer 1 callback function | ||
| 3089 | */ | ||
| 3090 | static int | ||
| 3091 | hfcm_l1callback(struct dchannel *dch, u_int cmd) | ||
| 3092 | { | ||
| 3093 | struct hfc_multi *hc = dch->hw; | ||
| 3094 | u_long flags; | ||
| 3095 | |||
| 3096 | switch (cmd) { | ||
| 3097 | case INFO3_P8: | ||
| 3098 | case INFO3_P10: | ||
| 3099 | break; | ||
| 3100 | case HW_RESET_REQ: | ||
| 3101 | /* start activation */ | ||
| 3102 | spin_lock_irqsave(&hc->lock, flags); | ||
| 3103 | if (hc->type == 1) { | ||
| 3104 | if (debug & DEBUG_HFCMULTI_MSG) | ||
| 3105 | printk(KERN_DEBUG | ||
| 3106 | "%s: HW_RESET_REQ no BRI\n", | ||
| 3107 | __func__); | ||
| 3108 | } else { | ||
| 3109 | HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port); | ||
| 3110 | /* undocumented: delay after R_ST_SEL */ | ||
| 3111 | udelay(1); | ||
| 3112 | HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 3); /* F3 */ | ||
| 3113 | udelay(6); /* wait at least 5,21us */ | ||
| 3114 | HFC_outb(hc, A_ST_WR_STATE, 3); | ||
| 3115 | HFC_outb(hc, A_ST_WR_STATE, 3 | (V_ST_ACT*3)); | ||
| 3116 | /* activate */ | ||
| 3117 | } | ||
| 3118 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 3119 | l1_event(dch->l1, HW_POWERUP_IND); | ||
| 3120 | break; | ||
| 3121 | case HW_DEACT_REQ: | ||
| 3122 | /* start deactivation */ | ||
| 3123 | spin_lock_irqsave(&hc->lock, flags); | ||
| 3124 | if (hc->type == 1) { | ||
| 3125 | if (debug & DEBUG_HFCMULTI_MSG) | ||
| 3126 | printk(KERN_DEBUG | ||
| 3127 | "%s: HW_DEACT_REQ no BRI\n", | ||
| 3128 | __func__); | ||
| 3129 | } else { | ||
| 3130 | HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port); | ||
| 3131 | /* undocumented: delay after R_ST_SEL */ | ||
| 3132 | udelay(1); | ||
| 3133 | HFC_outb(hc, A_ST_WR_STATE, V_ST_ACT*2); | ||
| 3134 | /* deactivate */ | ||
| 3135 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
| 3136 | hc->syncronized &= | ||
| 3137 | ~(1 << hc->chan[dch->slot].port); | ||
| 3138 | plxsd_checksync(hc, 0); | ||
| 3139 | } | ||
| 3140 | } | ||
| 3141 | skb_queue_purge(&dch->squeue); | ||
| 3142 | if (dch->tx_skb) { | ||
| 3143 | dev_kfree_skb(dch->tx_skb); | ||
| 3144 | dch->tx_skb = NULL; | ||
| 3145 | } | ||
| 3146 | dch->tx_idx = 0; | ||
| 3147 | if (dch->rx_skb) { | ||
| 3148 | dev_kfree_skb(dch->rx_skb); | ||
| 3149 | dch->rx_skb = NULL; | ||
| 3150 | } | ||
| 3151 | test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); | ||
| 3152 | if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) | ||
| 3153 | del_timer(&dch->timer); | ||
| 3154 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 3155 | break; | ||
| 3156 | case HW_POWERUP_REQ: | ||
| 3157 | spin_lock_irqsave(&hc->lock, flags); | ||
| 3158 | if (hc->type == 1) { | ||
| 3159 | if (debug & DEBUG_HFCMULTI_MSG) | ||
| 3160 | printk(KERN_DEBUG | ||
| 3161 | "%s: HW_POWERUP_REQ no BRI\n", | ||
| 3162 | __func__); | ||
| 3163 | } else { | ||
| 3164 | HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port); | ||
| 3165 | /* undocumented: delay after R_ST_SEL */ | ||
| 3166 | udelay(1); | ||
| 3167 | HFC_outb(hc, A_ST_WR_STATE, 3 | 0x10); /* activate */ | ||
| 3168 | udelay(6); /* wait at least 5,21us */ | ||
| 3169 | HFC_outb(hc, A_ST_WR_STATE, 3); /* activate */ | ||
| 3170 | } | ||
| 3171 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 3172 | break; | ||
| 3173 | case PH_ACTIVATE_IND: | ||
| 3174 | test_and_set_bit(FLG_ACTIVE, &dch->Flags); | ||
| 3175 | _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, | ||
| 3176 | GFP_ATOMIC); | ||
| 3177 | break; | ||
| 3178 | case PH_DEACTIVATE_IND: | ||
| 3179 | test_and_clear_bit(FLG_ACTIVE, &dch->Flags); | ||
| 3180 | _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, | ||
| 3181 | GFP_ATOMIC); | ||
| 3182 | break; | ||
| 3183 | default: | ||
| 3184 | if (dch->debug & DEBUG_HW) | ||
| 3185 | printk(KERN_DEBUG "%s: unknown command %x\n", | ||
| 3186 | __func__, cmd); | ||
| 3187 | return -1; | ||
| 3188 | } | ||
| 3189 | return 0; | ||
| 3190 | } | ||
| 3191 | |||
| 3192 | /* | ||
| 3193 | * Layer2 -> Layer 1 Transfer | ||
| 3194 | */ | ||
| 3195 | |||
| 3196 | static int | ||
| 3197 | handle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb) | ||
| 3198 | { | ||
| 3199 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
| 3200 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
| 3201 | struct hfc_multi *hc = dch->hw; | ||
| 3202 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
| 3203 | int ret = -EINVAL; | ||
| 3204 | unsigned int id; | ||
| 3205 | u_long flags; | ||
| 3206 | |||
| 3207 | switch (hh->prim) { | ||
| 3208 | case PH_DATA_REQ: | ||
| 3209 | if (skb->len < 1) | ||
| 3210 | break; | ||
| 3211 | spin_lock_irqsave(&hc->lock, flags); | ||
| 3212 | ret = dchannel_senddata(dch, skb); | ||
| 3213 | if (ret > 0) { /* direct TX */ | ||
| 3214 | id = hh->id; /* skb can be freed */ | ||
| 3215 | hfcmulti_tx(hc, dch->slot); | ||
| 3216 | ret = 0; | ||
| 3217 | /* start fifo */ | ||
| 3218 | HFC_outb(hc, R_FIFO, 0); | ||
| 3219 | HFC_wait(hc); | ||
| 3220 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 3221 | queue_ch_frame(ch, PH_DATA_CNF, id, NULL); | ||
| 3222 | } else | ||
| 3223 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 3224 | return ret; | ||
| 3225 | case PH_ACTIVATE_REQ: | ||
| 3226 | if (dch->dev.D.protocol != ISDN_P_TE_S0) { | ||
| 3227 | spin_lock_irqsave(&hc->lock, flags); | ||
| 3228 | ret = 0; | ||
| 3229 | if (debug & DEBUG_HFCMULTI_MSG) | ||
| 3230 | printk(KERN_DEBUG | ||
| 3231 | "%s: PH_ACTIVATE port %d (0..%d)\n", | ||
| 3232 | __func__, hc->chan[dch->slot].port, | ||
| 3233 | hc->ports-1); | ||
| 3234 | /* start activation */ | ||
| 3235 | if (hc->type == 1) { | ||
| 3236 | ph_state_change(dch); | ||
| 3237 | if (debug & DEBUG_HFCMULTI_STATE) | ||
| 3238 | printk(KERN_DEBUG | ||
| 3239 | "%s: E1 report state %x \n", | ||
| 3240 | __func__, dch->state); | ||
| 3241 | } else { | ||
| 3242 | HFC_outb(hc, R_ST_SEL, | ||
| 3243 | hc->chan[dch->slot].port); | ||
| 3244 | /* undocumented: delay after R_ST_SEL */ | ||
| 3245 | udelay(1); | ||
| 3246 | HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 1); | ||
| 3247 | /* G1 */ | ||
| 3248 | udelay(6); /* wait at least 5,21us */ | ||
| 3249 | HFC_outb(hc, A_ST_WR_STATE, 1); | ||
| 3250 | HFC_outb(hc, A_ST_WR_STATE, 1 | | ||
| 3251 | (V_ST_ACT*3)); /* activate */ | ||
| 3252 | dch->state = 1; | ||
| 3253 | } | ||
| 3254 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 3255 | } else | ||
| 3256 | ret = l1_event(dch->l1, hh->prim); | ||
| 3257 | break; | ||
| 3258 | case PH_DEACTIVATE_REQ: | ||
| 3259 | test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); | ||
| 3260 | if (dch->dev.D.protocol != ISDN_P_TE_S0) { | ||
| 3261 | spin_lock_irqsave(&hc->lock, flags); | ||
| 3262 | if (debug & DEBUG_HFCMULTI_MSG) | ||
| 3263 | printk(KERN_DEBUG | ||
| 3264 | "%s: PH_DEACTIVATE port %d (0..%d)\n", | ||
| 3265 | __func__, hc->chan[dch->slot].port, | ||
| 3266 | hc->ports-1); | ||
| 3267 | /* start deactivation */ | ||
| 3268 | if (hc->type == 1) { | ||
| 3269 | if (debug & DEBUG_HFCMULTI_MSG) | ||
| 3270 | printk(KERN_DEBUG | ||
| 3271 | "%s: PH_DEACTIVATE no BRI\n", | ||
| 3272 | __func__); | ||
| 3273 | } else { | ||
| 3274 | HFC_outb(hc, R_ST_SEL, | ||
| 3275 | hc->chan[dch->slot].port); | ||
| 3276 | /* undocumented: delay after R_ST_SEL */ | ||
| 3277 | udelay(1); | ||
| 3278 | HFC_outb(hc, A_ST_WR_STATE, V_ST_ACT * 2); | ||
| 3279 | /* deactivate */ | ||
| 3280 | dch->state = 1; | ||
| 3281 | } | ||
| 3282 | skb_queue_purge(&dch->squeue); | ||
| 3283 | if (dch->tx_skb) { | ||
| 3284 | dev_kfree_skb(dch->tx_skb); | ||
| 3285 | dch->tx_skb = NULL; | ||
| 3286 | } | ||
| 3287 | dch->tx_idx = 0; | ||
| 3288 | if (dch->rx_skb) { | ||
| 3289 | dev_kfree_skb(dch->rx_skb); | ||
| 3290 | dch->rx_skb = NULL; | ||
| 3291 | } | ||
| 3292 | test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); | ||
| 3293 | if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) | ||
| 3294 | del_timer(&dch->timer); | ||
| 3295 | #ifdef FIXME | ||
| 3296 | if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) | ||
| 3297 | dchannel_sched_event(&hc->dch, D_CLEARBUSY); | ||
| 3298 | #endif | ||
| 3299 | ret = 0; | ||
| 3300 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 3301 | } else | ||
| 3302 | ret = l1_event(dch->l1, hh->prim); | ||
| 3303 | break; | ||
| 3304 | } | ||
| 3305 | if (!ret) | ||
| 3306 | dev_kfree_skb(skb); | ||
| 3307 | return ret; | ||
| 3308 | } | ||
| 3309 | |||
| 3310 | static void | ||
| 3311 | deactivate_bchannel(struct bchannel *bch) | ||
| 3312 | { | ||
| 3313 | struct hfc_multi *hc = bch->hw; | ||
| 3314 | u_long flags; | ||
| 3315 | |||
| 3316 | spin_lock_irqsave(&hc->lock, flags); | ||
| 3317 | if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) { | ||
| 3318 | dev_kfree_skb(bch->next_skb); | ||
| 3319 | bch->next_skb = NULL; | ||
| 3320 | } | ||
| 3321 | if (bch->tx_skb) { | ||
| 3322 | dev_kfree_skb(bch->tx_skb); | ||
| 3323 | bch->tx_skb = NULL; | ||
| 3324 | } | ||
| 3325 | bch->tx_idx = 0; | ||
| 3326 | if (bch->rx_skb) { | ||
| 3327 | dev_kfree_skb(bch->rx_skb); | ||
| 3328 | bch->rx_skb = NULL; | ||
| 3329 | } | ||
| 3330 | hc->chan[bch->slot].coeff_count = 0; | ||
| 3331 | test_and_clear_bit(FLG_ACTIVE, &bch->Flags); | ||
| 3332 | test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); | ||
| 3333 | hc->chan[bch->slot].rx_off = 0; | ||
| 3334 | hc->chan[bch->slot].conf = -1; | ||
| 3335 | mode_hfcmulti(hc, bch->slot, ISDN_P_NONE, -1, 0, -1, 0); | ||
| 3336 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 3337 | } | ||
| 3338 | |||
| 3339 | static int | ||
| 3340 | handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) | ||
| 3341 | { | ||
| 3342 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
| 3343 | struct hfc_multi *hc = bch->hw; | ||
| 3344 | int ret = -EINVAL; | ||
| 3345 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
| 3346 | unsigned int id; | ||
| 3347 | u_long flags; | ||
| 3348 | |||
| 3349 | switch (hh->prim) { | ||
| 3350 | case PH_DATA_REQ: | ||
| 3351 | if (!skb->len) | ||
| 3352 | break; | ||
| 3353 | spin_lock_irqsave(&hc->lock, flags); | ||
| 3354 | ret = bchannel_senddata(bch, skb); | ||
| 3355 | if (ret > 0) { /* direct TX */ | ||
| 3356 | id = hh->id; /* skb can be freed */ | ||
| 3357 | hfcmulti_tx(hc, bch->slot); | ||
| 3358 | ret = 0; | ||
| 3359 | /* start fifo */ | ||
| 3360 | HFC_outb_nodebug(hc, R_FIFO, 0); | ||
| 3361 | HFC_wait_nodebug(hc); | ||
| 3362 | if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) { | ||
| 3363 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 3364 | queue_ch_frame(ch, PH_DATA_CNF, id, NULL); | ||
| 3365 | } else | ||
| 3366 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 3367 | } else | ||
| 3368 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 3369 | return ret; | ||
| 3370 | case PH_ACTIVATE_REQ: | ||
| 3371 | if (debug & DEBUG_HFCMULTI_MSG) | ||
| 3372 | printk(KERN_DEBUG "%s: PH_ACTIVATE ch %d (0..32)\n", | ||
| 3373 | __func__, bch->slot); | ||
| 3374 | spin_lock_irqsave(&hc->lock, flags); | ||
| 3375 | /* activate B-channel if not already activated */ | ||
| 3376 | if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) { | ||
| 3377 | hc->chan[bch->slot].txpending = 0; | ||
| 3378 | ret = mode_hfcmulti(hc, bch->slot, | ||
| 3379 | ch->protocol, | ||
| 3380 | hc->chan[bch->slot].slot_tx, | ||
| 3381 | hc->chan[bch->slot].bank_tx, | ||
| 3382 | hc->chan[bch->slot].slot_rx, | ||
| 3383 | hc->chan[bch->slot].bank_rx); | ||
| 3384 | if (!ret) { | ||
| 3385 | if (ch->protocol == ISDN_P_B_RAW && !hc->dtmf | ||
| 3386 | && test_bit(HFC_CHIP_DTMF, &hc->chip)) { | ||
| 3387 | /* start decoder */ | ||
| 3388 | hc->dtmf = 1; | ||
| 3389 | if (debug & DEBUG_HFCMULTI_DTMF) | ||
| 3390 | printk(KERN_DEBUG | ||
| 3391 | "%s: start dtmf decoder\n", | ||
| 3392 | __func__); | ||
| 3393 | HFC_outb(hc, R_DTMF, hc->hw.r_dtmf | | ||
| 3394 | V_RST_DTMF); | ||
| 3395 | } | ||
| 3396 | } | ||
| 3397 | } else | ||
| 3398 | ret = 0; | ||
| 3399 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 3400 | if (!ret) | ||
| 3401 | _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, NULL, | ||
| 3402 | GFP_KERNEL); | ||
| 3403 | break; | ||
| 3404 | case PH_CONTROL_REQ: | ||
| 3405 | spin_lock_irqsave(&hc->lock, flags); | ||
| 3406 | switch (hh->id) { | ||
| 3407 | case HFC_SPL_LOOP_ON: /* set sample loop */ | ||
| 3408 | if (debug & DEBUG_HFCMULTI_MSG) | ||
| 3409 | printk(KERN_DEBUG | ||
| 3410 | "%s: HFC_SPL_LOOP_ON (len = %d)\n", | ||
| 3411 | __func__, skb->len); | ||
| 3412 | ret = 0; | ||
| 3413 | break; | ||
| 3414 | case HFC_SPL_LOOP_OFF: /* set silence */ | ||
| 3415 | if (debug & DEBUG_HFCMULTI_MSG) | ||
| 3416 | printk(KERN_DEBUG "%s: HFC_SPL_LOOP_OFF\n", | ||
| 3417 | __func__); | ||
| 3418 | ret = 0; | ||
| 3419 | break; | ||
| 3420 | default: | ||
| 3421 | printk(KERN_ERR | ||
| 3422 | "%s: unknown PH_CONTROL_REQ info %x\n", | ||
| 3423 | __func__, hh->id); | ||
| 3424 | ret = -EINVAL; | ||
| 3425 | } | ||
| 3426 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 3427 | break; | ||
| 3428 | case PH_DEACTIVATE_REQ: | ||
| 3429 | deactivate_bchannel(bch); /* locked there */ | ||
| 3430 | _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, NULL, | ||
| 3431 | GFP_KERNEL); | ||
| 3432 | ret = 0; | ||
| 3433 | break; | ||
| 3434 | } | ||
| 3435 | if (!ret) | ||
| 3436 | dev_kfree_skb(skb); | ||
| 3437 | return ret; | ||
| 3438 | } | ||
| 3439 | |||
| 3440 | /* | ||
| 3441 | * bchannel control function | ||
| 3442 | */ | ||
| 3443 | static int | ||
| 3444 | channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) | ||
| 3445 | { | ||
| 3446 | int ret = 0; | ||
| 3447 | struct dsp_features *features = | ||
| 3448 | (struct dsp_features *)(*((u_long *)&cq->p1)); | ||
| 3449 | struct hfc_multi *hc = bch->hw; | ||
| 3450 | int slot_tx; | ||
| 3451 | int bank_tx; | ||
| 3452 | int slot_rx; | ||
| 3453 | int bank_rx; | ||
| 3454 | int num; | ||
| 3455 | |||
| 3456 | switch (cq->op) { | ||
| 3457 | case MISDN_CTRL_GETOP: | ||
| 3458 | cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP | ||
| 3459 | | MISDN_CTRL_RX_OFF; | ||
| 3460 | break; | ||
| 3461 | case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */ | ||
| 3462 | hc->chan[bch->slot].rx_off = !!cq->p1; | ||
| 3463 | if (!hc->chan[bch->slot].rx_off) { | ||
| 3464 | /* reset fifo on rx on */ | ||
| 3465 | HFC_outb_nodebug(hc, R_FIFO, (bch->slot << 1) | 1); | ||
| 3466 | HFC_wait_nodebug(hc); | ||
| 3467 | HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F); | ||
| 3468 | HFC_wait_nodebug(hc); | ||
| 3469 | } | ||
| 3470 | if (debug & DEBUG_HFCMULTI_MSG) | ||
| 3471 | printk(KERN_DEBUG "%s: RX_OFF request (nr=%d off=%d)\n", | ||
| 3472 | __func__, bch->nr, hc->chan[bch->slot].rx_off); | ||
| 3473 | break; | ||
| 3474 | case MISDN_CTRL_HW_FEATURES: /* fill features structure */ | ||
| 3475 | if (debug & DEBUG_HFCMULTI_MSG) | ||
| 3476 | printk(KERN_DEBUG "%s: HW_FEATURE request\n", | ||
| 3477 | __func__); | ||
| 3478 | /* create confirm */ | ||
| 3479 | features->hfc_id = hc->id; | ||
| 3480 | if (test_bit(HFC_CHIP_DTMF, &hc->chip)) | ||
| 3481 | features->hfc_dtmf = 1; | ||
| 3482 | features->hfc_loops = 0; | ||
| 3483 | if (test_bit(HFC_CHIP_B410P, &hc->chip)) { | ||
| 3484 | features->hfc_echocanhw = 1; | ||
| 3485 | } else { | ||
| 3486 | features->pcm_id = hc->pcm; | ||
| 3487 | features->pcm_slots = hc->slots; | ||
| 3488 | features->pcm_banks = 2; | ||
| 3489 | } | ||
| 3490 | break; | ||
| 3491 | case MISDN_CTRL_HFC_PCM_CONN: /* connect to pcm timeslot (0..N) */ | ||
| 3492 | slot_tx = cq->p1 & 0xff; | ||
| 3493 | bank_tx = cq->p1 >> 8; | ||
| 3494 | slot_rx = cq->p2 & 0xff; | ||
| 3495 | bank_rx = cq->p2 >> 8; | ||
| 3496 | if (debug & DEBUG_HFCMULTI_MSG) | ||
| 3497 | printk(KERN_DEBUG | ||
| 3498 | "%s: HFC_PCM_CONN slot %d bank %d (TX) " | ||
| 3499 | "slot %d bank %d (RX)\n", | ||
| 3500 | __func__, slot_tx, bank_tx, | ||
| 3501 | slot_rx, bank_rx); | ||
| 3502 | if (slot_tx < hc->slots && bank_tx <= 2 && | ||
| 3503 | slot_rx < hc->slots && bank_rx <= 2) | ||
| 3504 | hfcmulti_pcm(hc, bch->slot, | ||
| 3505 | slot_tx, bank_tx, slot_rx, bank_rx); | ||
| 3506 | else { | ||
| 3507 | printk(KERN_WARNING | ||
| 3508 | "%s: HFC_PCM_CONN slot %d bank %d (TX) " | ||
| 3509 | "slot %d bank %d (RX) out of range\n", | ||
| 3510 | __func__, slot_tx, bank_tx, | ||
| 3511 | slot_rx, bank_rx); | ||
| 3512 | ret = -EINVAL; | ||
| 3513 | } | ||
| 3514 | break; | ||
| 3515 | case MISDN_CTRL_HFC_PCM_DISC: /* release interface from pcm timeslot */ | ||
| 3516 | if (debug & DEBUG_HFCMULTI_MSG) | ||
| 3517 | printk(KERN_DEBUG "%s: HFC_PCM_DISC\n", | ||
| 3518 | __func__); | ||
| 3519 | hfcmulti_pcm(hc, bch->slot, -1, 0, -1, 0); | ||
| 3520 | break; | ||
| 3521 | case MISDN_CTRL_HFC_CONF_JOIN: /* join conference (0..7) */ | ||
| 3522 | num = cq->p1 & 0xff; | ||
| 3523 | if (debug & DEBUG_HFCMULTI_MSG) | ||
| 3524 | printk(KERN_DEBUG "%s: HFC_CONF_JOIN conf %d\n", | ||
| 3525 | __func__, num); | ||
| 3526 | if (num <= 7) | ||
| 3527 | hfcmulti_conf(hc, bch->slot, num); | ||
| 3528 | else { | ||
| 3529 | printk(KERN_WARNING | ||
| 3530 | "%s: HW_CONF_JOIN conf %d out of range\n", | ||
| 3531 | __func__, num); | ||
| 3532 | ret = -EINVAL; | ||
| 3533 | } | ||
| 3534 | break; | ||
| 3535 | case MISDN_CTRL_HFC_CONF_SPLIT: /* split conference */ | ||
| 3536 | if (debug & DEBUG_HFCMULTI_MSG) | ||
| 3537 | printk(KERN_DEBUG "%s: HFC_CONF_SPLIT\n", __func__); | ||
| 3538 | hfcmulti_conf(hc, bch->slot, -1); | ||
| 3539 | break; | ||
| 3540 | case MISDN_CTRL_HFC_ECHOCAN_ON: | ||
| 3541 | if (debug & DEBUG_HFCMULTI_MSG) | ||
| 3542 | printk(KERN_DEBUG "%s: HFC_ECHOCAN_ON\n", __func__); | ||
| 3543 | if (test_bit(HFC_CHIP_B410P, &hc->chip)) | ||
| 3544 | vpm_echocan_on(hc, bch->slot, cq->p1); | ||
| 3545 | else | ||
| 3546 | ret = -EINVAL; | ||
| 3547 | break; | ||
| 3548 | |||
| 3549 | case MISDN_CTRL_HFC_ECHOCAN_OFF: | ||
| 3550 | if (debug & DEBUG_HFCMULTI_MSG) | ||
| 3551 | printk(KERN_DEBUG "%s: HFC_ECHOCAN_OFF\n", | ||
| 3552 | __func__); | ||
| 3553 | if (test_bit(HFC_CHIP_B410P, &hc->chip)) | ||
| 3554 | vpm_echocan_off(hc, bch->slot); | ||
| 3555 | else | ||
| 3556 | ret = -EINVAL; | ||
| 3557 | break; | ||
| 3558 | default: | ||
| 3559 | printk(KERN_WARNING "%s: unknown Op %x\n", | ||
| 3560 | __func__, cq->op); | ||
| 3561 | ret = -EINVAL; | ||
| 3562 | break; | ||
| 3563 | } | ||
| 3564 | return ret; | ||
| 3565 | } | ||
| 3566 | |||
| 3567 | static int | ||
| 3568 | hfcm_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
| 3569 | { | ||
| 3570 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
| 3571 | struct hfc_multi *hc = bch->hw; | ||
| 3572 | int err = -EINVAL; | ||
| 3573 | u_long flags; | ||
| 3574 | |||
| 3575 | if (bch->debug & DEBUG_HW) | ||
| 3576 | printk(KERN_DEBUG "%s: cmd:%x %p\n", | ||
| 3577 | __func__, cmd, arg); | ||
| 3578 | switch (cmd) { | ||
| 3579 | case CLOSE_CHANNEL: | ||
| 3580 | test_and_clear_bit(FLG_OPEN, &bch->Flags); | ||
| 3581 | if (test_bit(FLG_ACTIVE, &bch->Flags)) | ||
| 3582 | deactivate_bchannel(bch); /* locked there */ | ||
| 3583 | ch->protocol = ISDN_P_NONE; | ||
| 3584 | ch->peer = NULL; | ||
| 3585 | module_put(THIS_MODULE); | ||
| 3586 | err = 0; | ||
| 3587 | break; | ||
| 3588 | case CONTROL_CHANNEL: | ||
| 3589 | spin_lock_irqsave(&hc->lock, flags); | ||
| 3590 | err = channel_bctrl(bch, arg); | ||
| 3591 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 3592 | break; | ||
| 3593 | default: | ||
| 3594 | printk(KERN_WARNING "%s: unknown prim(%x)\n", | ||
| 3595 | __func__, cmd); | ||
| 3596 | } | ||
| 3597 | return err; | ||
| 3598 | } | ||
| 3599 | |||
| 3600 | /* | ||
| 3601 | * handle D-channel events | ||
| 3602 | * | ||
| 3603 | * handle state change event | ||
| 3604 | */ | ||
| 3605 | static void | ||
| 3606 | ph_state_change(struct dchannel *dch) | ||
| 3607 | { | ||
| 3608 | struct hfc_multi *hc = dch->hw; | ||
| 3609 | int ch, i; | ||
| 3610 | |||
| 3611 | if (!dch) { | ||
| 3612 | printk(KERN_WARNING "%s: ERROR given dch is NULL\n", | ||
| 3613 | __func__); | ||
| 3614 | return; | ||
| 3615 | } | ||
| 3616 | ch = dch->slot; | ||
| 3617 | |||
| 3618 | if (hc->type == 1) { | ||
| 3619 | if (dch->dev.D.protocol == ISDN_P_TE_E1) { | ||
| 3620 | if (debug & DEBUG_HFCMULTI_STATE) | ||
| 3621 | printk(KERN_DEBUG | ||
| 3622 | "%s: E1 TE (id=%d) newstate %x\n", | ||
| 3623 | __func__, hc->id, dch->state); | ||
| 3624 | } else { | ||
| 3625 | if (debug & DEBUG_HFCMULTI_STATE) | ||
| 3626 | printk(KERN_DEBUG | ||
| 3627 | "%s: E1 NT (id=%d) newstate %x\n", | ||
| 3628 | __func__, hc->id, dch->state); | ||
| 3629 | } | ||
| 3630 | switch (dch->state) { | ||
| 3631 | case (1): | ||
| 3632 | if (hc->e1_state != 1) { | ||
| 3633 | for (i = 1; i <= 31; i++) { | ||
| 3634 | /* reset fifos on e1 activation */ | ||
| 3635 | HFC_outb_nodebug(hc, R_FIFO, (i << 1) | 1); | ||
| 3636 | HFC_wait_nodebug(hc); | ||
| 3637 | HFC_outb_nodebug(hc, | ||
| 3638 | R_INC_RES_FIFO, V_RES_F); | ||
| 3639 | HFC_wait_nodebug(hc); | ||
| 3640 | } | ||
| 3641 | } | ||
| 3642 | test_and_set_bit(FLG_ACTIVE, &dch->Flags); | ||
| 3643 | _queue_data(&dch->dev.D, PH_ACTIVATE_IND, | ||
| 3644 | MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); | ||
| 3645 | break; | ||
| 3646 | |||
| 3647 | default: | ||
| 3648 | if (hc->e1_state != 1) | ||
| 3649 | return; | ||
| 3650 | test_and_clear_bit(FLG_ACTIVE, &dch->Flags); | ||
| 3651 | _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, | ||
| 3652 | MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); | ||
| 3653 | } | ||
| 3654 | hc->e1_state = dch->state; | ||
| 3655 | } else { | ||
| 3656 | if (dch->dev.D.protocol == ISDN_P_TE_S0) { | ||
| 3657 | if (debug & DEBUG_HFCMULTI_STATE) | ||
| 3658 | printk(KERN_DEBUG | ||
| 3659 | "%s: S/T TE newstate %x\n", | ||
| 3660 | __func__, dch->state); | ||
| 3661 | switch (dch->state) { | ||
| 3662 | case (0): | ||
| 3663 | l1_event(dch->l1, HW_RESET_IND); | ||
| 3664 | break; | ||
| 3665 | case (3): | ||
| 3666 | l1_event(dch->l1, HW_DEACT_IND); | ||
| 3667 | break; | ||
| 3668 | case (5): | ||
| 3669 | case (8): | ||
| 3670 | l1_event(dch->l1, ANYSIGNAL); | ||
| 3671 | break; | ||
| 3672 | case (6): | ||
| 3673 | l1_event(dch->l1, INFO2); | ||
| 3674 | break; | ||
| 3675 | case (7): | ||
| 3676 | l1_event(dch->l1, INFO4_P8); | ||
| 3677 | break; | ||
| 3678 | } | ||
| 3679 | } else { | ||
| 3680 | if (debug & DEBUG_HFCMULTI_STATE) | ||
| 3681 | printk(KERN_DEBUG "%s: S/T NT newstate %x\n", | ||
| 3682 | __func__, dch->state); | ||
| 3683 | switch (dch->state) { | ||
| 3684 | case (2): | ||
| 3685 | if (hc->chan[ch].nt_timer == 0) { | ||
| 3686 | hc->chan[ch].nt_timer = -1; | ||
| 3687 | HFC_outb(hc, R_ST_SEL, | ||
| 3688 | hc->chan[ch].port); | ||
| 3689 | /* undocumented: delay after R_ST_SEL */ | ||
| 3690 | udelay(1); | ||
| 3691 | HFC_outb(hc, A_ST_WR_STATE, 4 | | ||
| 3692 | V_ST_LD_STA); /* G4 */ | ||
| 3693 | udelay(6); /* wait at least 5,21us */ | ||
| 3694 | HFC_outb(hc, A_ST_WR_STATE, 4); | ||
| 3695 | dch->state = 4; | ||
| 3696 | } else { | ||
| 3697 | /* one extra count for the next event */ | ||
| 3698 | hc->chan[ch].nt_timer = | ||
| 3699 | nt_t1_count[poll_timer] + 1; | ||
| 3700 | HFC_outb(hc, R_ST_SEL, | ||
| 3701 | hc->chan[ch].port); | ||
| 3702 | /* undocumented: delay after R_ST_SEL */ | ||
| 3703 | udelay(1); | ||
| 3704 | /* allow G2 -> G3 transition */ | ||
| 3705 | HFC_outb(hc, A_ST_WR_STATE, 2 | | ||
| 3706 | V_SET_G2_G3); | ||
| 3707 | } | ||
| 3708 | break; | ||
| 3709 | case (1): | ||
| 3710 | hc->chan[ch].nt_timer = -1; | ||
| 3711 | test_and_clear_bit(FLG_ACTIVE, &dch->Flags); | ||
| 3712 | _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, | ||
| 3713 | MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); | ||
| 3714 | break; | ||
| 3715 | case (4): | ||
| 3716 | hc->chan[ch].nt_timer = -1; | ||
| 3717 | break; | ||
| 3718 | case (3): | ||
| 3719 | hc->chan[ch].nt_timer = -1; | ||
| 3720 | test_and_set_bit(FLG_ACTIVE, &dch->Flags); | ||
| 3721 | _queue_data(&dch->dev.D, PH_ACTIVATE_IND, | ||
| 3722 | MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); | ||
| 3723 | break; | ||
| 3724 | } | ||
| 3725 | } | ||
| 3726 | } | ||
| 3727 | } | ||
| 3728 | |||
| 3729 | /* | ||
| 3730 | * called for card mode init message | ||
| 3731 | */ | ||
| 3732 | |||
| 3733 | static void | ||
| 3734 | hfcmulti_initmode(struct dchannel *dch) | ||
| 3735 | { | ||
| 3736 | struct hfc_multi *hc = dch->hw; | ||
| 3737 | u_char a_st_wr_state, r_e1_wr_sta; | ||
| 3738 | int i, pt; | ||
| 3739 | |||
| 3740 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 3741 | printk(KERN_DEBUG "%s: entered\n", __func__); | ||
| 3742 | |||
| 3743 | if (hc->type == 1) { | ||
| 3744 | hc->chan[hc->dslot].slot_tx = -1; | ||
| 3745 | hc->chan[hc->dslot].slot_rx = -1; | ||
| 3746 | hc->chan[hc->dslot].conf = -1; | ||
| 3747 | if (hc->dslot) { | ||
| 3748 | mode_hfcmulti(hc, hc->dslot, dch->dev.D.protocol, | ||
| 3749 | -1, 0, -1, 0); | ||
| 3750 | dch->timer.function = (void *) hfcmulti_dbusy_timer; | ||
| 3751 | dch->timer.data = (long) dch; | ||
| 3752 | init_timer(&dch->timer); | ||
| 3753 | } | ||
| 3754 | for (i = 1; i <= 31; i++) { | ||
| 3755 | if (i == hc->dslot) | ||
| 3756 | continue; | ||
| 3757 | hc->chan[i].slot_tx = -1; | ||
| 3758 | hc->chan[i].slot_rx = -1; | ||
| 3759 | hc->chan[i].conf = -1; | ||
| 3760 | mode_hfcmulti(hc, i, ISDN_P_NONE, -1, 0, -1, 0); | ||
| 3761 | } | ||
| 3762 | /* E1 */ | ||
| 3763 | if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dslot].cfg)) { | ||
| 3764 | HFC_outb(hc, R_LOS0, 255); /* 2 ms */ | ||
| 3765 | HFC_outb(hc, R_LOS1, 255); /* 512 ms */ | ||
| 3766 | } | ||
| 3767 | if (test_bit(HFC_CFG_OPTICAL, &hc->chan[hc->dslot].cfg)) { | ||
| 3768 | HFC_outb(hc, R_RX0, 0); | ||
| 3769 | hc->hw.r_tx0 = 0 | V_OUT_EN; | ||
| 3770 | } else { | ||
| 3771 | HFC_outb(hc, R_RX0, 1); | ||
| 3772 | hc->hw.r_tx0 = 1 | V_OUT_EN; | ||
| 3773 | } | ||
| 3774 | hc->hw.r_tx1 = V_ATX | V_NTRI; | ||
| 3775 | HFC_outb(hc, R_TX0, hc->hw.r_tx0); | ||
| 3776 | HFC_outb(hc, R_TX1, hc->hw.r_tx1); | ||
| 3777 | HFC_outb(hc, R_TX_FR0, 0x00); | ||
| 3778 | HFC_outb(hc, R_TX_FR1, 0xf8); | ||
| 3779 | |||
| 3780 | if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dslot].cfg)) | ||
| 3781 | HFC_outb(hc, R_TX_FR2, V_TX_MF | V_TX_E | V_NEG_E); | ||
| 3782 | |||
| 3783 | HFC_outb(hc, R_RX_FR0, V_AUTO_RESYNC | V_AUTO_RECO | 0); | ||
| 3784 | |||
| 3785 | if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dslot].cfg)) | ||
| 3786 | HFC_outb(hc, R_RX_FR1, V_RX_MF | V_RX_MF_SYNC); | ||
| 3787 | |||
| 3788 | if (dch->dev.D.protocol == ISDN_P_NT_E1) { | ||
| 3789 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 3790 | printk(KERN_DEBUG "%s: E1 port is NT-mode\n", | ||
| 3791 | __func__); | ||
| 3792 | r_e1_wr_sta = 0; /* G0 */ | ||
| 3793 | hc->e1_getclock = 0; | ||
| 3794 | } else { | ||
| 3795 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 3796 | printk(KERN_DEBUG "%s: E1 port is TE-mode\n", | ||
| 3797 | __func__); | ||
| 3798 | r_e1_wr_sta = 0; /* F0 */ | ||
| 3799 | hc->e1_getclock = 1; | ||
| 3800 | } | ||
| 3801 | if (test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) | ||
| 3802 | HFC_outb(hc, R_SYNC_OUT, V_SYNC_E1_RX); | ||
| 3803 | else | ||
| 3804 | HFC_outb(hc, R_SYNC_OUT, 0); | ||
| 3805 | if (test_bit(HFC_CHIP_E1CLOCK_GET, &hc->chip)) | ||
| 3806 | hc->e1_getclock = 1; | ||
| 3807 | if (test_bit(HFC_CHIP_E1CLOCK_PUT, &hc->chip)) | ||
| 3808 | hc->e1_getclock = 0; | ||
| 3809 | if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { | ||
| 3810 | /* SLAVE (clock master) */ | ||
| 3811 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 3812 | printk(KERN_DEBUG | ||
| 3813 | "%s: E1 port is clock master " | ||
| 3814 | "(clock from PCM)\n", __func__); | ||
| 3815 | HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | V_PCM_SYNC); | ||
| 3816 | } else { | ||
| 3817 | if (hc->e1_getclock) { | ||
| 3818 | /* MASTER (clock slave) */ | ||
| 3819 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 3820 | printk(KERN_DEBUG | ||
| 3821 | "%s: E1 port is clock slave " | ||
| 3822 | "(clock to PCM)\n", __func__); | ||
| 3823 | HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS); | ||
| 3824 | } else { | ||
| 3825 | /* MASTER (clock master) */ | ||
| 3826 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 3827 | printk(KERN_DEBUG "%s: E1 port is " | ||
| 3828 | "clock master " | ||
| 3829 | "(clock from QUARTZ)\n", | ||
| 3830 | __func__); | ||
| 3831 | HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | | ||
| 3832 | V_PCM_SYNC | V_JATT_OFF); | ||
| 3833 | HFC_outb(hc, R_SYNC_OUT, 0); | ||
| 3834 | } | ||
| 3835 | } | ||
| 3836 | HFC_outb(hc, R_JATT_ATT, 0x9c); /* undoc register */ | ||
| 3837 | HFC_outb(hc, R_PWM_MD, V_PWM0_MD); | ||
| 3838 | HFC_outb(hc, R_PWM0, 0x50); | ||
| 3839 | HFC_outb(hc, R_PWM1, 0xff); | ||
| 3840 | /* state machine setup */ | ||
| 3841 | HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta | V_E1_LD_STA); | ||
| 3842 | udelay(6); /* wait at least 5,21us */ | ||
| 3843 | HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta); | ||
| 3844 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
| 3845 | hc->syncronized = 0; | ||
| 3846 | plxsd_checksync(hc, 0); | ||
| 3847 | } | ||
| 3848 | } else { | ||
| 3849 | i = dch->slot; | ||
| 3850 | hc->chan[i].slot_tx = -1; | ||
| 3851 | hc->chan[i].slot_rx = -1; | ||
| 3852 | hc->chan[i].conf = -1; | ||
| 3853 | mode_hfcmulti(hc, i, dch->dev.D.protocol, -1, 0, -1, 0); | ||
| 3854 | dch->timer.function = (void *)hfcmulti_dbusy_timer; | ||
| 3855 | dch->timer.data = (long) dch; | ||
| 3856 | init_timer(&dch->timer); | ||
| 3857 | hc->chan[i - 2].slot_tx = -1; | ||
| 3858 | hc->chan[i - 2].slot_rx = -1; | ||
| 3859 | hc->chan[i - 2].conf = -1; | ||
| 3860 | mode_hfcmulti(hc, i - 2, ISDN_P_NONE, -1, 0, -1, 0); | ||
| 3861 | hc->chan[i - 1].slot_tx = -1; | ||
| 3862 | hc->chan[i - 1].slot_rx = -1; | ||
| 3863 | hc->chan[i - 1].conf = -1; | ||
| 3864 | mode_hfcmulti(hc, i - 1, ISDN_P_NONE, -1, 0, -1, 0); | ||
| 3865 | /* ST */ | ||
| 3866 | pt = hc->chan[i].port; | ||
| 3867 | /* select interface */ | ||
| 3868 | HFC_outb(hc, R_ST_SEL, pt); | ||
| 3869 | /* undocumented: delay after R_ST_SEL */ | ||
| 3870 | udelay(1); | ||
| 3871 | if (dch->dev.D.protocol == ISDN_P_NT_S0) { | ||
| 3872 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 3873 | printk(KERN_DEBUG | ||
| 3874 | "%s: ST port %d is NT-mode\n", | ||
| 3875 | __func__, pt); | ||
| 3876 | /* clock delay */ | ||
| 3877 | HFC_outb(hc, A_ST_CLK_DLY, clockdelay_nt); | ||
| 3878 | a_st_wr_state = 1; /* G1 */ | ||
| 3879 | hc->hw.a_st_ctrl0[pt] = V_ST_MD; | ||
| 3880 | } else { | ||
| 3881 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 3882 | printk(KERN_DEBUG | ||
| 3883 | "%s: ST port %d is TE-mode\n", | ||
| 3884 | __func__, pt); | ||
| 3885 | /* clock delay */ | ||
| 3886 | HFC_outb(hc, A_ST_CLK_DLY, clockdelay_te); | ||
| 3887 | a_st_wr_state = 2; /* F2 */ | ||
| 3888 | hc->hw.a_st_ctrl0[pt] = 0; | ||
| 3889 | } | ||
| 3890 | if (!test_bit(HFC_CFG_NONCAP_TX, &hc->chan[i].cfg)) | ||
| 3891 | hc->hw.a_st_ctrl0[pt] |= V_TX_LI; | ||
| 3892 | /* line setup */ | ||
| 3893 | HFC_outb(hc, A_ST_CTRL0, hc->hw.a_st_ctrl0[pt]); | ||
| 3894 | /* disable E-channel */ | ||
| 3895 | if ((dch->dev.D.protocol == ISDN_P_NT_S0) || | ||
| 3896 | test_bit(HFC_CFG_DIS_ECHANNEL, &hc->chan[i].cfg)) | ||
| 3897 | HFC_outb(hc, A_ST_CTRL1, V_E_IGNO); | ||
| 3898 | else | ||
| 3899 | HFC_outb(hc, A_ST_CTRL1, 0); | ||
| 3900 | /* enable B-channel receive */ | ||
| 3901 | HFC_outb(hc, A_ST_CTRL2, V_B1_RX_EN | V_B2_RX_EN); | ||
| 3902 | /* state machine setup */ | ||
| 3903 | HFC_outb(hc, A_ST_WR_STATE, a_st_wr_state | V_ST_LD_STA); | ||
| 3904 | udelay(6); /* wait at least 5,21us */ | ||
| 3905 | HFC_outb(hc, A_ST_WR_STATE, a_st_wr_state); | ||
| 3906 | hc->hw.r_sci_msk |= 1 << pt; | ||
| 3907 | /* state machine interrupts */ | ||
| 3908 | HFC_outb(hc, R_SCI_MSK, hc->hw.r_sci_msk); | ||
| 3909 | /* unset sync on port */ | ||
| 3910 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
| 3911 | hc->syncronized &= | ||
| 3912 | ~(1 << hc->chan[dch->slot].port); | ||
| 3913 | plxsd_checksync(hc, 0); | ||
| 3914 | } | ||
| 3915 | } | ||
| 3916 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 3917 | printk("%s: done\n", __func__); | ||
| 3918 | } | ||
| 3919 | |||
| 3920 | |||
| 3921 | static int | ||
| 3922 | open_dchannel(struct hfc_multi *hc, struct dchannel *dch, | ||
| 3923 | struct channel_req *rq) | ||
| 3924 | { | ||
| 3925 | int err = 0; | ||
| 3926 | u_long flags; | ||
| 3927 | |||
| 3928 | if (debug & DEBUG_HW_OPEN) | ||
| 3929 | printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__, | ||
| 3930 | dch->dev.id, __builtin_return_address(0)); | ||
| 3931 | if (rq->protocol == ISDN_P_NONE) | ||
| 3932 | return -EINVAL; | ||
| 3933 | if ((dch->dev.D.protocol != ISDN_P_NONE) && | ||
| 3934 | (dch->dev.D.protocol != rq->protocol)) { | ||
| 3935 | if (debug & DEBUG_HFCMULTI_MODE) | ||
| 3936 | printk(KERN_WARNING "%s: change protocol %x to %x\n", | ||
| 3937 | __func__, dch->dev.D.protocol, rq->protocol); | ||
| 3938 | } | ||
| 3939 | if ((dch->dev.D.protocol == ISDN_P_TE_S0) | ||
| 3940 | && (rq->protocol != ISDN_P_TE_S0)) | ||
| 3941 | l1_event(dch->l1, CLOSE_CHANNEL); | ||
| 3942 | if (dch->dev.D.protocol != rq->protocol) { | ||
| 3943 | if (rq->protocol == ISDN_P_TE_S0) { | ||
| 3944 | err = create_l1(dch, hfcm_l1callback); | ||
| 3945 | if (err) | ||
| 3946 | return err; | ||
| 3947 | } | ||
| 3948 | dch->dev.D.protocol = rq->protocol; | ||
| 3949 | spin_lock_irqsave(&hc->lock, flags); | ||
| 3950 | hfcmulti_initmode(dch); | ||
| 3951 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 3952 | } | ||
| 3953 | |||
| 3954 | if (((rq->protocol == ISDN_P_NT_S0) && (dch->state == 3)) || | ||
| 3955 | ((rq->protocol == ISDN_P_TE_S0) && (dch->state == 7)) || | ||
| 3956 | ((rq->protocol == ISDN_P_NT_E1) && (dch->state == 1)) || | ||
| 3957 | ((rq->protocol == ISDN_P_TE_E1) && (dch->state == 1))) { | ||
| 3958 | _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, | ||
| 3959 | 0, NULL, GFP_KERNEL); | ||
| 3960 | } | ||
| 3961 | rq->ch = &dch->dev.D; | ||
| 3962 | if (!try_module_get(THIS_MODULE)) | ||
| 3963 | printk(KERN_WARNING "%s:cannot get module\n", __func__); | ||
| 3964 | return 0; | ||
| 3965 | } | ||
| 3966 | |||
| 3967 | static int | ||
| 3968 | open_bchannel(struct hfc_multi *hc, struct dchannel *dch, | ||
| 3969 | struct channel_req *rq) | ||
| 3970 | { | ||
| 3971 | struct bchannel *bch; | ||
| 3972 | int ch; | ||
| 3973 | |||
| 3974 | if (!test_bit(rq->adr.channel, &dch->dev.channelmap[0])) | ||
| 3975 | return -EINVAL; | ||
| 3976 | if (rq->protocol == ISDN_P_NONE) | ||
| 3977 | return -EINVAL; | ||
| 3978 | if (hc->type == 1) | ||
| 3979 | ch = rq->adr.channel; | ||
| 3980 | else | ||
| 3981 | ch = (rq->adr.channel - 1) + (dch->slot - 2); | ||
| 3982 | bch = hc->chan[ch].bch; | ||
| 3983 | if (!bch) { | ||
| 3984 | printk(KERN_ERR "%s:internal error ch %d has no bch\n", | ||
| 3985 | __func__, ch); | ||
| 3986 | return -EINVAL; | ||
| 3987 | } | ||
| 3988 | if (test_and_set_bit(FLG_OPEN, &bch->Flags)) | ||
| 3989 | return -EBUSY; /* b-channel can be only open once */ | ||
| 3990 | bch->ch.protocol = rq->protocol; | ||
| 3991 | hc->chan[ch].rx_off = 0; | ||
| 3992 | rq->ch = &bch->ch; | ||
| 3993 | if (!try_module_get(THIS_MODULE)) | ||
| 3994 | printk(KERN_WARNING "%s:cannot get module\n", __func__); | ||
| 3995 | return 0; | ||
| 3996 | } | ||
| 3997 | |||
| 3998 | /* | ||
| 3999 | * device control function | ||
| 4000 | */ | ||
| 4001 | static int | ||
| 4002 | channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) | ||
| 4003 | { | ||
| 4004 | int ret = 0; | ||
| 4005 | |||
| 4006 | switch (cq->op) { | ||
| 4007 | case MISDN_CTRL_GETOP: | ||
| 4008 | cq->op = 0; | ||
| 4009 | break; | ||
| 4010 | default: | ||
| 4011 | printk(KERN_WARNING "%s: unknown Op %x\n", | ||
| 4012 | __func__, cq->op); | ||
| 4013 | ret = -EINVAL; | ||
| 4014 | break; | ||
| 4015 | } | ||
| 4016 | return ret; | ||
| 4017 | } | ||
| 4018 | |||
| 4019 | static int | ||
| 4020 | hfcm_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
| 4021 | { | ||
| 4022 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
| 4023 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
| 4024 | struct hfc_multi *hc = dch->hw; | ||
| 4025 | struct channel_req *rq; | ||
| 4026 | int err = 0; | ||
| 4027 | u_long flags; | ||
| 4028 | |||
| 4029 | if (dch->debug & DEBUG_HW) | ||
| 4030 | printk(KERN_DEBUG "%s: cmd:%x %p\n", | ||
| 4031 | __func__, cmd, arg); | ||
| 4032 | switch (cmd) { | ||
| 4033 | case OPEN_CHANNEL: | ||
| 4034 | rq = arg; | ||
| 4035 | switch (rq->protocol) { | ||
| 4036 | case ISDN_P_TE_S0: | ||
| 4037 | case ISDN_P_NT_S0: | ||
| 4038 | if (hc->type == 1) { | ||
| 4039 | err = -EINVAL; | ||
| 4040 | break; | ||
| 4041 | } | ||
| 4042 | err = open_dchannel(hc, dch, rq); /* locked there */ | ||
| 4043 | break; | ||
| 4044 | case ISDN_P_TE_E1: | ||
| 4045 | case ISDN_P_NT_E1: | ||
| 4046 | if (hc->type != 1) { | ||
| 4047 | err = -EINVAL; | ||
| 4048 | break; | ||
| 4049 | } | ||
| 4050 | err = open_dchannel(hc, dch, rq); /* locked there */ | ||
| 4051 | break; | ||
| 4052 | default: | ||
| 4053 | spin_lock_irqsave(&hc->lock, flags); | ||
| 4054 | err = open_bchannel(hc, dch, rq); | ||
| 4055 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 4056 | } | ||
| 4057 | break; | ||
| 4058 | case CLOSE_CHANNEL: | ||
| 4059 | if (debug & DEBUG_HW_OPEN) | ||
| 4060 | printk(KERN_DEBUG "%s: dev(%d) close from %p\n", | ||
| 4061 | __func__, dch->dev.id, | ||
| 4062 | __builtin_return_address(0)); | ||
| 4063 | module_put(THIS_MODULE); | ||
| 4064 | break; | ||
| 4065 | case CONTROL_CHANNEL: | ||
| 4066 | spin_lock_irqsave(&hc->lock, flags); | ||
| 4067 | err = channel_dctrl(dch, arg); | ||
| 4068 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 4069 | break; | ||
| 4070 | default: | ||
| 4071 | if (dch->debug & DEBUG_HW) | ||
| 4072 | printk(KERN_DEBUG "%s: unknown command %x\n", | ||
| 4073 | __func__, cmd); | ||
| 4074 | err = -EINVAL; | ||
| 4075 | } | ||
| 4076 | return err; | ||
| 4077 | } | ||
| 4078 | |||
| 4079 | /* | ||
| 4080 | * initialize the card | ||
| 4081 | */ | ||
| 4082 | |||
| 4083 | /* | ||
| 4084 | * start timer irq, wait some time and check if we have interrupts. | ||
| 4085 | * if not, reset chip and try again. | ||
| 4086 | */ | ||
| 4087 | static int | ||
| 4088 | init_card(struct hfc_multi *hc) | ||
| 4089 | { | ||
| 4090 | int err = -EIO; | ||
| 4091 | u_long flags; | ||
| 4092 | u_short *plx_acc; | ||
| 4093 | u_long plx_flags; | ||
| 4094 | |||
| 4095 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4096 | printk(KERN_DEBUG "%s: entered\n", __func__); | ||
| 4097 | |||
| 4098 | spin_lock_irqsave(&hc->lock, flags); | ||
| 4099 | /* set interrupts but leave global interrupt disabled */ | ||
| 4100 | hc->hw.r_irq_ctrl = V_FIFO_IRQ; | ||
| 4101 | disable_hwirq(hc); | ||
| 4102 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 4103 | |||
| 4104 | if (request_irq(hc->pci_dev->irq, hfcmulti_interrupt, IRQF_SHARED, | ||
| 4105 | "HFC-multi", hc)) { | ||
| 4106 | printk(KERN_WARNING "mISDN: Could not get interrupt %d.\n", | ||
| 4107 | hc->pci_dev->irq); | ||
| 4108 | return -EIO; | ||
| 4109 | } | ||
| 4110 | hc->irq = hc->pci_dev->irq; | ||
| 4111 | |||
| 4112 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
| 4113 | spin_lock_irqsave(&plx_lock, plx_flags); | ||
| 4114 | plx_acc = (u_short *)(hc->plx_membase+PLX_INTCSR); | ||
| 4115 | writew((PLX_INTCSR_PCIINT_ENABLE | PLX_INTCSR_LINTI1_ENABLE), | ||
| 4116 | plx_acc); /* enable PCI & LINT1 irq */ | ||
| 4117 | spin_unlock_irqrestore(&plx_lock, plx_flags); | ||
| 4118 | } | ||
| 4119 | |||
| 4120 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4121 | printk(KERN_DEBUG "%s: IRQ %d count %d\n", | ||
| 4122 | __func__, hc->irq, hc->irqcnt); | ||
| 4123 | err = init_chip(hc); | ||
| 4124 | if (err) | ||
| 4125 | goto error; | ||
| 4126 | /* | ||
| 4127 | * Finally enable IRQ output | ||
| 4128 | * this is only allowed, if an IRQ routine is allready | ||
| 4129 | * established for this HFC, so don't do that earlier | ||
| 4130 | */ | ||
| 4131 | spin_lock_irqsave(&hc->lock, flags); | ||
| 4132 | enable_hwirq(hc); | ||
| 4133 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 4134 | /* printk(KERN_DEBUG "no master irq set!!!\n"); */ | ||
| 4135 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
| 4136 | schedule_timeout((100*HZ)/1000); /* Timeout 100ms */ | ||
| 4137 | /* turn IRQ off until chip is completely initialized */ | ||
| 4138 | spin_lock_irqsave(&hc->lock, flags); | ||
| 4139 | disable_hwirq(hc); | ||
| 4140 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 4141 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4142 | printk(KERN_DEBUG "%s: IRQ %d count %d\n", | ||
| 4143 | __func__, hc->irq, hc->irqcnt); | ||
| 4144 | if (hc->irqcnt) { | ||
| 4145 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4146 | printk(KERN_DEBUG "%s: done\n", __func__); | ||
| 4147 | |||
| 4148 | return 0; | ||
| 4149 | } | ||
| 4150 | if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { | ||
| 4151 | printk(KERN_INFO "ignoring missing interrupts\n"); | ||
| 4152 | return 0; | ||
| 4153 | } | ||
| 4154 | |||
| 4155 | printk(KERN_ERR "HFC PCI: IRQ(%d) getting no interrupts during init.\n", | ||
| 4156 | hc->irq); | ||
| 4157 | |||
| 4158 | err = -EIO; | ||
| 4159 | |||
| 4160 | error: | ||
| 4161 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
| 4162 | spin_lock_irqsave(&plx_lock, plx_flags); | ||
| 4163 | plx_acc = (u_short *)(hc->plx_membase+PLX_INTCSR); | ||
| 4164 | writew(0x00, plx_acc); /*disable IRQs*/ | ||
| 4165 | spin_unlock_irqrestore(&plx_lock, plx_flags); | ||
| 4166 | } | ||
| 4167 | |||
| 4168 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4169 | printk(KERN_WARNING "%s: free irq %d\n", __func__, hc->irq); | ||
| 4170 | if (hc->irq) { | ||
| 4171 | free_irq(hc->irq, hc); | ||
| 4172 | hc->irq = 0; | ||
| 4173 | } | ||
| 4174 | |||
| 4175 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4176 | printk(KERN_DEBUG "%s: done (err=%d)\n", __func__, err); | ||
| 4177 | return err; | ||
| 4178 | } | ||
| 4179 | |||
| 4180 | /* | ||
| 4181 | * find pci device and set it up | ||
| 4182 | */ | ||
| 4183 | |||
| 4184 | static int | ||
| 4185 | setup_pci(struct hfc_multi *hc, struct pci_dev *pdev, | ||
| 4186 | const struct pci_device_id *ent) | ||
| 4187 | { | ||
| 4188 | struct hm_map *m = (struct hm_map *)ent->driver_data; | ||
| 4189 | |||
| 4190 | printk(KERN_INFO | ||
| 4191 | "HFC-multi: card manufacturer: '%s' card name: '%s' clock: %s\n", | ||
| 4192 | m->vendor_name, m->card_name, m->clock2 ? "double" : "normal"); | ||
| 4193 | |||
| 4194 | hc->pci_dev = pdev; | ||
| 4195 | if (m->clock2) | ||
| 4196 | test_and_set_bit(HFC_CHIP_CLOCK2, &hc->chip); | ||
| 4197 | |||
| 4198 | if (ent->device == 0xB410) { | ||
| 4199 | test_and_set_bit(HFC_CHIP_B410P, &hc->chip); | ||
| 4200 | test_and_set_bit(HFC_CHIP_PCM_MASTER, &hc->chip); | ||
| 4201 | test_and_clear_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); | ||
| 4202 | hc->slots = 32; | ||
| 4203 | } | ||
| 4204 | |||
| 4205 | if (hc->pci_dev->irq <= 0) { | ||
| 4206 | printk(KERN_WARNING "HFC-multi: No IRQ for PCI card found.\n"); | ||
| 4207 | return -EIO; | ||
| 4208 | } | ||
| 4209 | if (pci_enable_device(hc->pci_dev)) { | ||
| 4210 | printk(KERN_WARNING "HFC-multi: Error enabling PCI card.\n"); | ||
| 4211 | return -EIO; | ||
| 4212 | } | ||
| 4213 | hc->leds = m->leds; | ||
| 4214 | hc->ledstate = 0xAFFEAFFE; | ||
| 4215 | hc->opticalsupport = m->opticalsupport; | ||
| 4216 | |||
| 4217 | /* set memory access methods */ | ||
| 4218 | if (m->io_mode) /* use mode from card config */ | ||
| 4219 | hc->io_mode = m->io_mode; | ||
| 4220 | switch (hc->io_mode) { | ||
| 4221 | case HFC_IO_MODE_PLXSD: | ||
| 4222 | test_and_set_bit(HFC_CHIP_PLXSD, &hc->chip); | ||
| 4223 | hc->slots = 128; /* required */ | ||
| 4224 | /* fall through */ | ||
| 4225 | case HFC_IO_MODE_PCIMEM: | ||
| 4226 | hc->HFC_outb = HFC_outb_pcimem; | ||
| 4227 | hc->HFC_inb = HFC_inb_pcimem; | ||
| 4228 | hc->HFC_inw = HFC_inw_pcimem; | ||
| 4229 | hc->HFC_wait = HFC_wait_pcimem; | ||
| 4230 | hc->read_fifo = read_fifo_pcimem; | ||
| 4231 | hc->write_fifo = write_fifo_pcimem; | ||
| 4232 | break; | ||
| 4233 | case HFC_IO_MODE_REGIO: | ||
| 4234 | hc->HFC_outb = HFC_outb_regio; | ||
| 4235 | hc->HFC_inb = HFC_inb_regio; | ||
| 4236 | hc->HFC_inw = HFC_inw_regio; | ||
| 4237 | hc->HFC_wait = HFC_wait_regio; | ||
| 4238 | hc->read_fifo = read_fifo_regio; | ||
| 4239 | hc->write_fifo = write_fifo_regio; | ||
| 4240 | break; | ||
| 4241 | default: | ||
| 4242 | printk(KERN_WARNING "HFC-multi: Invalid IO mode.\n"); | ||
| 4243 | pci_disable_device(hc->pci_dev); | ||
| 4244 | return -EIO; | ||
| 4245 | } | ||
| 4246 | hc->HFC_outb_nodebug = hc->HFC_outb; | ||
| 4247 | hc->HFC_inb_nodebug = hc->HFC_inb; | ||
| 4248 | hc->HFC_inw_nodebug = hc->HFC_inw; | ||
| 4249 | hc->HFC_wait_nodebug = hc->HFC_wait; | ||
| 4250 | #ifdef HFC_REGISTER_DEBUG | ||
| 4251 | hc->HFC_outb = HFC_outb_debug; | ||
| 4252 | hc->HFC_inb = HFC_inb_debug; | ||
| 4253 | hc->HFC_inw = HFC_inw_debug; | ||
| 4254 | hc->HFC_wait = HFC_wait_debug; | ||
| 4255 | #endif | ||
| 4256 | hc->pci_iobase = 0; | ||
| 4257 | hc->pci_membase = NULL; | ||
| 4258 | hc->plx_membase = NULL; | ||
| 4259 | |||
| 4260 | switch (hc->io_mode) { | ||
| 4261 | case HFC_IO_MODE_PLXSD: | ||
| 4262 | hc->plx_origmembase = hc->pci_dev->resource[0].start; | ||
| 4263 | /* MEMBASE 1 is PLX PCI Bridge */ | ||
| 4264 | |||
| 4265 | if (!hc->plx_origmembase) { | ||
| 4266 | printk(KERN_WARNING | ||
| 4267 | "HFC-multi: No IO-Memory for PCI PLX bridge found\n"); | ||
| 4268 | pci_disable_device(hc->pci_dev); | ||
| 4269 | return -EIO; | ||
| 4270 | } | ||
| 4271 | |||
| 4272 | hc->plx_membase = ioremap(hc->plx_origmembase, 0x80); | ||
| 4273 | if (!hc->plx_membase) { | ||
| 4274 | printk(KERN_WARNING | ||
| 4275 | "HFC-multi: failed to remap plx address space. " | ||
| 4276 | "(internal error)\n"); | ||
| 4277 | pci_disable_device(hc->pci_dev); | ||
| 4278 | return -EIO; | ||
| 4279 | } | ||
| 4280 | printk(KERN_INFO | ||
| 4281 | "HFC-multi: plx_membase:%#lx plx_origmembase:%#lx\n", | ||
| 4282 | (u_long)hc->plx_membase, hc->plx_origmembase); | ||
| 4283 | |||
| 4284 | hc->pci_origmembase = hc->pci_dev->resource[2].start; | ||
| 4285 | /* MEMBASE 1 is PLX PCI Bridge */ | ||
| 4286 | if (!hc->pci_origmembase) { | ||
| 4287 | printk(KERN_WARNING | ||
| 4288 | "HFC-multi: No IO-Memory for PCI card found\n"); | ||
| 4289 | pci_disable_device(hc->pci_dev); | ||
| 4290 | return -EIO; | ||
| 4291 | } | ||
| 4292 | |||
| 4293 | hc->pci_membase = ioremap(hc->pci_origmembase, 0x400); | ||
| 4294 | if (!hc->pci_membase) { | ||
| 4295 | printk(KERN_WARNING "HFC-multi: failed to remap io " | ||
| 4296 | "address space. (internal error)\n"); | ||
| 4297 | pci_disable_device(hc->pci_dev); | ||
| 4298 | return -EIO; | ||
| 4299 | } | ||
| 4300 | |||
| 4301 | printk(KERN_INFO | ||
| 4302 | "card %d: defined at MEMBASE %#lx (%#lx) IRQ %d HZ %d " | ||
| 4303 | "leds-type %d\n", | ||
| 4304 | hc->id, (u_long)hc->pci_membase, hc->pci_origmembase, | ||
| 4305 | hc->pci_dev->irq, HZ, hc->leds); | ||
| 4306 | pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO); | ||
| 4307 | break; | ||
| 4308 | case HFC_IO_MODE_PCIMEM: | ||
| 4309 | hc->pci_origmembase = hc->pci_dev->resource[1].start; | ||
| 4310 | if (!hc->pci_origmembase) { | ||
| 4311 | printk(KERN_WARNING | ||
| 4312 | "HFC-multi: No IO-Memory for PCI card found\n"); | ||
| 4313 | pci_disable_device(hc->pci_dev); | ||
| 4314 | return -EIO; | ||
| 4315 | } | ||
| 4316 | |||
| 4317 | hc->pci_membase = ioremap(hc->pci_origmembase, 256); | ||
| 4318 | if (!hc->pci_membase) { | ||
| 4319 | printk(KERN_WARNING | ||
| 4320 | "HFC-multi: failed to remap io address space. " | ||
| 4321 | "(internal error)\n"); | ||
| 4322 | pci_disable_device(hc->pci_dev); | ||
| 4323 | return -EIO; | ||
| 4324 | } | ||
| 4325 | printk(KERN_INFO "card %d: defined at MEMBASE %#lx (%#lx) IRQ %d " | ||
| 4326 | "HZ %d leds-type %d\n", hc->id, (u_long)hc->pci_membase, | ||
| 4327 | hc->pci_origmembase, hc->pci_dev->irq, HZ, hc->leds); | ||
| 4328 | pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO); | ||
| 4329 | break; | ||
| 4330 | case HFC_IO_MODE_REGIO: | ||
| 4331 | hc->pci_iobase = (u_int) hc->pci_dev->resource[0].start; | ||
| 4332 | if (!hc->pci_iobase) { | ||
| 4333 | printk(KERN_WARNING | ||
| 4334 | "HFC-multi: No IO for PCI card found\n"); | ||
| 4335 | pci_disable_device(hc->pci_dev); | ||
| 4336 | return -EIO; | ||
| 4337 | } | ||
| 4338 | |||
| 4339 | if (!request_region(hc->pci_iobase, 8, "hfcmulti")) { | ||
| 4340 | printk(KERN_WARNING "HFC-multi: failed to request " | ||
| 4341 | "address space at 0x%08lx (internal error)\n", | ||
| 4342 | hc->pci_iobase); | ||
| 4343 | pci_disable_device(hc->pci_dev); | ||
| 4344 | return -EIO; | ||
| 4345 | } | ||
| 4346 | |||
| 4347 | printk(KERN_INFO | ||
| 4348 | "%s %s: defined at IOBASE %#x IRQ %d HZ %d leds-type %d\n", | ||
| 4349 | m->vendor_name, m->card_name, (u_int) hc->pci_iobase, | ||
| 4350 | hc->pci_dev->irq, HZ, hc->leds); | ||
| 4351 | pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_REGIO); | ||
| 4352 | break; | ||
| 4353 | default: | ||
| 4354 | printk(KERN_WARNING "HFC-multi: Invalid IO mode.\n"); | ||
| 4355 | pci_disable_device(hc->pci_dev); | ||
| 4356 | return -EIO; | ||
| 4357 | } | ||
| 4358 | |||
| 4359 | pci_set_drvdata(hc->pci_dev, hc); | ||
| 4360 | |||
| 4361 | /* At this point the needed PCI config is done */ | ||
| 4362 | /* fifos are still not enabled */ | ||
| 4363 | return 0; | ||
| 4364 | } | ||
| 4365 | |||
| 4366 | |||
| 4367 | /* | ||
| 4368 | * remove port | ||
| 4369 | */ | ||
| 4370 | |||
| 4371 | static void | ||
| 4372 | release_port(struct hfc_multi *hc, struct dchannel *dch) | ||
| 4373 | { | ||
| 4374 | int pt, ci, i = 0; | ||
| 4375 | u_long flags; | ||
| 4376 | struct bchannel *pb; | ||
| 4377 | |||
| 4378 | ci = dch->slot; | ||
| 4379 | pt = hc->chan[ci].port; | ||
| 4380 | |||
| 4381 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4382 | printk(KERN_DEBUG "%s: entered for port %d\n", | ||
| 4383 | __func__, pt + 1); | ||
| 4384 | |||
| 4385 | if (pt >= hc->ports) { | ||
| 4386 | printk(KERN_WARNING "%s: ERROR port out of range (%d).\n", | ||
| 4387 | __func__, pt + 1); | ||
| 4388 | return; | ||
| 4389 | } | ||
| 4390 | |||
| 4391 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4392 | printk(KERN_DEBUG "%s: releasing port=%d\n", | ||
| 4393 | __func__, pt + 1); | ||
| 4394 | |||
| 4395 | if (dch->dev.D.protocol == ISDN_P_TE_S0) | ||
| 4396 | l1_event(dch->l1, CLOSE_CHANNEL); | ||
| 4397 | |||
| 4398 | hc->chan[ci].dch = NULL; | ||
| 4399 | |||
| 4400 | if (hc->created[pt]) { | ||
| 4401 | hc->created[pt] = 0; | ||
| 4402 | mISDN_unregister_device(&dch->dev); | ||
| 4403 | } | ||
| 4404 | |||
| 4405 | spin_lock_irqsave(&hc->lock, flags); | ||
| 4406 | |||
| 4407 | if (dch->timer.function) { | ||
| 4408 | del_timer(&dch->timer); | ||
| 4409 | dch->timer.function = NULL; | ||
| 4410 | } | ||
| 4411 | |||
| 4412 | if (hc->type == 1) { /* E1 */ | ||
| 4413 | /* remove sync */ | ||
| 4414 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
| 4415 | hc->syncronized = 0; | ||
| 4416 | plxsd_checksync(hc, 1); | ||
| 4417 | } | ||
| 4418 | /* free channels */ | ||
| 4419 | for (i = 0; i <= 31; i++) { | ||
| 4420 | if (hc->chan[i].bch) { | ||
| 4421 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4422 | printk(KERN_DEBUG | ||
| 4423 | "%s: free port %d channel %d\n", | ||
| 4424 | __func__, hc->chan[i].port+1, i); | ||
| 4425 | pb = hc->chan[i].bch; | ||
| 4426 | hc->chan[i].bch = NULL; | ||
| 4427 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 4428 | mISDN_freebchannel(pb); | ||
| 4429 | kfree(pb); | ||
| 4430 | kfree(hc->chan[i].coeff); | ||
| 4431 | spin_lock_irqsave(&hc->lock, flags); | ||
| 4432 | } | ||
| 4433 | } | ||
| 4434 | } else { | ||
| 4435 | /* remove sync */ | ||
| 4436 | if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { | ||
| 4437 | hc->syncronized &= | ||
| 4438 | ~(1 << hc->chan[ci].port); | ||
| 4439 | plxsd_checksync(hc, 1); | ||
| 4440 | } | ||
| 4441 | /* free channels */ | ||
| 4442 | if (hc->chan[ci - 2].bch) { | ||
| 4443 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4444 | printk(KERN_DEBUG | ||
| 4445 | "%s: free port %d channel %d\n", | ||
| 4446 | __func__, hc->chan[ci - 2].port+1, | ||
| 4447 | ci - 2); | ||
| 4448 | pb = hc->chan[ci - 2].bch; | ||
| 4449 | hc->chan[ci - 2].bch = NULL; | ||
| 4450 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 4451 | mISDN_freebchannel(pb); | ||
| 4452 | kfree(pb); | ||
| 4453 | kfree(hc->chan[ci - 2].coeff); | ||
| 4454 | spin_lock_irqsave(&hc->lock, flags); | ||
| 4455 | } | ||
| 4456 | if (hc->chan[ci - 1].bch) { | ||
| 4457 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4458 | printk(KERN_DEBUG | ||
| 4459 | "%s: free port %d channel %d\n", | ||
| 4460 | __func__, hc->chan[ci - 1].port+1, | ||
| 4461 | ci - 1); | ||
| 4462 | pb = hc->chan[ci - 1].bch; | ||
| 4463 | hc->chan[ci - 1].bch = NULL; | ||
| 4464 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 4465 | mISDN_freebchannel(pb); | ||
| 4466 | kfree(pb); | ||
| 4467 | kfree(hc->chan[ci - 1].coeff); | ||
| 4468 | spin_lock_irqsave(&hc->lock, flags); | ||
| 4469 | } | ||
| 4470 | } | ||
| 4471 | |||
| 4472 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 4473 | |||
| 4474 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4475 | printk(KERN_DEBUG "%s: free port %d channel D\n", __func__, pt); | ||
| 4476 | mISDN_freedchannel(dch); | ||
| 4477 | kfree(dch); | ||
| 4478 | |||
| 4479 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4480 | printk(KERN_DEBUG "%s: done!\n", __func__); | ||
| 4481 | } | ||
| 4482 | |||
| 4483 | static void | ||
| 4484 | release_card(struct hfc_multi *hc) | ||
| 4485 | { | ||
| 4486 | u_long flags; | ||
| 4487 | int ch; | ||
| 4488 | |||
| 4489 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4490 | printk(KERN_WARNING "%s: release card (%d) entered\n", | ||
| 4491 | __func__, hc->id); | ||
| 4492 | |||
| 4493 | spin_lock_irqsave(&hc->lock, flags); | ||
| 4494 | disable_hwirq(hc); | ||
| 4495 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 4496 | |||
| 4497 | udelay(1000); | ||
| 4498 | |||
| 4499 | /* dimm leds */ | ||
| 4500 | if (hc->leds) | ||
| 4501 | hfcmulti_leds(hc); | ||
| 4502 | |||
| 4503 | /* disable D-channels & B-channels */ | ||
| 4504 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4505 | printk(KERN_DEBUG "%s: disable all channels (d and b)\n", | ||
| 4506 | __func__); | ||
| 4507 | for (ch = 0; ch <= 31; ch++) { | ||
| 4508 | if (hc->chan[ch].dch) | ||
| 4509 | release_port(hc, hc->chan[ch].dch); | ||
| 4510 | } | ||
| 4511 | |||
| 4512 | /* release hardware & irq */ | ||
| 4513 | if (hc->irq) { | ||
| 4514 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4515 | printk(KERN_WARNING "%s: free irq %d\n", | ||
| 4516 | __func__, hc->irq); | ||
| 4517 | free_irq(hc->irq, hc); | ||
| 4518 | hc->irq = 0; | ||
| 4519 | |||
| 4520 | } | ||
| 4521 | release_io_hfcmulti(hc); | ||
| 4522 | |||
| 4523 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4524 | printk(KERN_WARNING "%s: remove instance from list\n", | ||
| 4525 | __func__); | ||
| 4526 | list_del(&hc->list); | ||
| 4527 | |||
| 4528 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4529 | printk(KERN_WARNING "%s: delete instance\n", __func__); | ||
| 4530 | if (hc == syncmaster) | ||
| 4531 | syncmaster = NULL; | ||
| 4532 | kfree(hc); | ||
| 4533 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4534 | printk(KERN_WARNING "%s: card successfully removed\n", | ||
| 4535 | __func__); | ||
| 4536 | } | ||
| 4537 | |||
| 4538 | static int | ||
| 4539 | init_e1_port(struct hfc_multi *hc, struct hm_map *m) | ||
| 4540 | { | ||
| 4541 | struct dchannel *dch; | ||
| 4542 | struct bchannel *bch; | ||
| 4543 | int ch, ret = 0; | ||
| 4544 | char name[MISDN_MAX_IDLEN]; | ||
| 4545 | |||
| 4546 | dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL); | ||
| 4547 | if (!dch) | ||
| 4548 | return -ENOMEM; | ||
| 4549 | dch->debug = debug; | ||
| 4550 | mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change); | ||
| 4551 | dch->hw = hc; | ||
| 4552 | dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1); | ||
| 4553 | dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | | ||
| 4554 | (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); | ||
| 4555 | dch->dev.D.send = handle_dmsg; | ||
| 4556 | dch->dev.D.ctrl = hfcm_dctrl; | ||
| 4557 | dch->dev.nrbchan = (hc->dslot)?30:31; | ||
| 4558 | dch->slot = hc->dslot; | ||
| 4559 | hc->chan[hc->dslot].dch = dch; | ||
| 4560 | hc->chan[hc->dslot].port = 0; | ||
| 4561 | hc->chan[hc->dslot].nt_timer = -1; | ||
| 4562 | for (ch = 1; ch <= 31; ch++) { | ||
| 4563 | if (ch == hc->dslot) /* skip dchannel */ | ||
| 4564 | continue; | ||
| 4565 | bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL); | ||
| 4566 | if (!bch) { | ||
| 4567 | printk(KERN_ERR "%s: no memory for bchannel\n", | ||
| 4568 | __func__); | ||
| 4569 | ret = -ENOMEM; | ||
| 4570 | goto free_chan; | ||
| 4571 | } | ||
| 4572 | hc->chan[ch].coeff = kzalloc(512, GFP_KERNEL); | ||
| 4573 | if (!hc->chan[ch].coeff) { | ||
| 4574 | printk(KERN_ERR "%s: no memory for coeffs\n", | ||
| 4575 | __func__); | ||
| 4576 | ret = -ENOMEM; | ||
| 4577 | goto free_chan; | ||
| 4578 | } | ||
| 4579 | bch->nr = ch; | ||
| 4580 | bch->slot = ch; | ||
| 4581 | bch->debug = debug; | ||
| 4582 | mISDN_initbchannel(bch, MAX_DATA_MEM); | ||
| 4583 | bch->hw = hc; | ||
| 4584 | bch->ch.send = handle_bmsg; | ||
| 4585 | bch->ch.ctrl = hfcm_bctrl; | ||
| 4586 | bch->ch.nr = ch; | ||
| 4587 | list_add(&bch->ch.list, &dch->dev.bchannels); | ||
| 4588 | hc->chan[ch].bch = bch; | ||
| 4589 | hc->chan[ch].port = 0; | ||
| 4590 | test_and_set_bit(bch->nr, &dch->dev.channelmap[0]); | ||
| 4591 | } | ||
| 4592 | /* set optical line type */ | ||
| 4593 | if (port[Port_cnt] & 0x001) { | ||
| 4594 | if (!m->opticalsupport) { | ||
| 4595 | printk(KERN_INFO | ||
| 4596 | "This board has no optical " | ||
| 4597 | "support\n"); | ||
| 4598 | } else { | ||
| 4599 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4600 | printk(KERN_DEBUG | ||
| 4601 | "%s: PORT set optical " | ||
| 4602 | "interfacs: card(%d) " | ||
| 4603 | "port(%d)\n", | ||
| 4604 | __func__, | ||
| 4605 | HFC_cnt + 1, 1); | ||
| 4606 | test_and_set_bit(HFC_CFG_OPTICAL, | ||
| 4607 | &hc->chan[hc->dslot].cfg); | ||
| 4608 | } | ||
| 4609 | } | ||
| 4610 | /* set LOS report */ | ||
| 4611 | if (port[Port_cnt] & 0x004) { | ||
| 4612 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4613 | printk(KERN_DEBUG "%s: PORT set " | ||
| 4614 | "LOS report: card(%d) port(%d)\n", | ||
| 4615 | __func__, HFC_cnt + 1, 1); | ||
| 4616 | test_and_set_bit(HFC_CFG_REPORT_LOS, | ||
| 4617 | &hc->chan[hc->dslot].cfg); | ||
| 4618 | } | ||
| 4619 | /* set AIS report */ | ||
| 4620 | if (port[Port_cnt] & 0x008) { | ||
| 4621 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4622 | printk(KERN_DEBUG "%s: PORT set " | ||
| 4623 | "AIS report: card(%d) port(%d)\n", | ||
| 4624 | __func__, HFC_cnt + 1, 1); | ||
| 4625 | test_and_set_bit(HFC_CFG_REPORT_AIS, | ||
| 4626 | &hc->chan[hc->dslot].cfg); | ||
| 4627 | } | ||
| 4628 | /* set SLIP report */ | ||
| 4629 | if (port[Port_cnt] & 0x010) { | ||
| 4630 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4631 | printk(KERN_DEBUG | ||
| 4632 | "%s: PORT set SLIP report: " | ||
| 4633 | "card(%d) port(%d)\n", | ||
| 4634 | __func__, HFC_cnt + 1, 1); | ||
| 4635 | test_and_set_bit(HFC_CFG_REPORT_SLIP, | ||
| 4636 | &hc->chan[hc->dslot].cfg); | ||
| 4637 | } | ||
| 4638 | /* set RDI report */ | ||
| 4639 | if (port[Port_cnt] & 0x020) { | ||
| 4640 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4641 | printk(KERN_DEBUG | ||
| 4642 | "%s: PORT set RDI report: " | ||
| 4643 | "card(%d) port(%d)\n", | ||
| 4644 | __func__, HFC_cnt + 1, 1); | ||
| 4645 | test_and_set_bit(HFC_CFG_REPORT_RDI, | ||
| 4646 | &hc->chan[hc->dslot].cfg); | ||
| 4647 | } | ||
| 4648 | /* set CRC-4 Mode */ | ||
| 4649 | if (!(port[Port_cnt] & 0x100)) { | ||
| 4650 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4651 | printk(KERN_DEBUG "%s: PORT turn on CRC4 report:" | ||
| 4652 | " card(%d) port(%d)\n", | ||
| 4653 | __func__, HFC_cnt + 1, 1); | ||
| 4654 | test_and_set_bit(HFC_CFG_CRC4, | ||
| 4655 | &hc->chan[hc->dslot].cfg); | ||
| 4656 | } else { | ||
| 4657 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4658 | printk(KERN_DEBUG "%s: PORT turn off CRC4" | ||
| 4659 | " report: card(%d) port(%d)\n", | ||
| 4660 | __func__, HFC_cnt + 1, 1); | ||
| 4661 | } | ||
| 4662 | /* set forced clock */ | ||
| 4663 | if (port[Port_cnt] & 0x0200) { | ||
| 4664 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4665 | printk(KERN_DEBUG "%s: PORT force getting clock from " | ||
| 4666 | "E1: card(%d) port(%d)\n", | ||
| 4667 | __func__, HFC_cnt + 1, 1); | ||
| 4668 | test_and_set_bit(HFC_CHIP_E1CLOCK_GET, &hc->chip); | ||
| 4669 | } else | ||
| 4670 | if (port[Port_cnt] & 0x0400) { | ||
| 4671 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4672 | printk(KERN_DEBUG "%s: PORT force putting clock to " | ||
| 4673 | "E1: card(%d) port(%d)\n", | ||
| 4674 | __func__, HFC_cnt + 1, 1); | ||
| 4675 | test_and_set_bit(HFC_CHIP_E1CLOCK_PUT, &hc->chip); | ||
| 4676 | } | ||
| 4677 | /* set JATT PLL */ | ||
| 4678 | if (port[Port_cnt] & 0x0800) { | ||
| 4679 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4680 | printk(KERN_DEBUG "%s: PORT disable JATT PLL on " | ||
| 4681 | "E1: card(%d) port(%d)\n", | ||
| 4682 | __func__, HFC_cnt + 1, 1); | ||
| 4683 | test_and_set_bit(HFC_CHIP_RX_SYNC, &hc->chip); | ||
| 4684 | } | ||
| 4685 | /* set elastic jitter buffer */ | ||
| 4686 | if (port[Port_cnt] & 0x3000) { | ||
| 4687 | hc->chan[hc->dslot].jitter = (port[Port_cnt]>>12) & 0x3; | ||
| 4688 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4689 | printk(KERN_DEBUG | ||
| 4690 | "%s: PORT set elastic " | ||
| 4691 | "buffer to %d: card(%d) port(%d)\n", | ||
| 4692 | __func__, hc->chan[hc->dslot].jitter, | ||
| 4693 | HFC_cnt + 1, 1); | ||
| 4694 | } else | ||
| 4695 | hc->chan[hc->dslot].jitter = 2; /* default */ | ||
| 4696 | snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d", HFC_cnt + 1); | ||
| 4697 | ret = mISDN_register_device(&dch->dev, name); | ||
| 4698 | if (ret) | ||
| 4699 | goto free_chan; | ||
| 4700 | hc->created[0] = 1; | ||
| 4701 | return ret; | ||
| 4702 | free_chan: | ||
| 4703 | release_port(hc, dch); | ||
| 4704 | return ret; | ||
| 4705 | } | ||
| 4706 | |||
| 4707 | static int | ||
| 4708 | init_multi_port(struct hfc_multi *hc, int pt) | ||
| 4709 | { | ||
| 4710 | struct dchannel *dch; | ||
| 4711 | struct bchannel *bch; | ||
| 4712 | int ch, i, ret = 0; | ||
| 4713 | char name[MISDN_MAX_IDLEN]; | ||
| 4714 | |||
| 4715 | dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL); | ||
| 4716 | if (!dch) | ||
| 4717 | return -ENOMEM; | ||
| 4718 | dch->debug = debug; | ||
| 4719 | mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change); | ||
| 4720 | dch->hw = hc; | ||
| 4721 | dch->dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0); | ||
| 4722 | dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | | ||
| 4723 | (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); | ||
| 4724 | dch->dev.D.send = handle_dmsg; | ||
| 4725 | dch->dev.D.ctrl = hfcm_dctrl; | ||
| 4726 | dch->dev.nrbchan = 2; | ||
| 4727 | i = pt << 2; | ||
| 4728 | dch->slot = i + 2; | ||
| 4729 | hc->chan[i + 2].dch = dch; | ||
| 4730 | hc->chan[i + 2].port = pt; | ||
| 4731 | hc->chan[i + 2].nt_timer = -1; | ||
| 4732 | for (ch = 0; ch < dch->dev.nrbchan; ch++) { | ||
| 4733 | bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL); | ||
| 4734 | if (!bch) { | ||
| 4735 | printk(KERN_ERR "%s: no memory for bchannel\n", | ||
| 4736 | __func__); | ||
| 4737 | ret = -ENOMEM; | ||
| 4738 | goto free_chan; | ||
| 4739 | } | ||
| 4740 | hc->chan[i + ch].coeff = kzalloc(512, GFP_KERNEL); | ||
| 4741 | if (!hc->chan[i + ch].coeff) { | ||
| 4742 | printk(KERN_ERR "%s: no memory for coeffs\n", | ||
| 4743 | __func__); | ||
| 4744 | ret = -ENOMEM; | ||
| 4745 | goto free_chan; | ||
| 4746 | } | ||
| 4747 | bch->nr = ch + 1; | ||
| 4748 | bch->slot = i + ch; | ||
| 4749 | bch->debug = debug; | ||
| 4750 | mISDN_initbchannel(bch, MAX_DATA_MEM); | ||
| 4751 | bch->hw = hc; | ||
| 4752 | bch->ch.send = handle_bmsg; | ||
| 4753 | bch->ch.ctrl = hfcm_bctrl; | ||
| 4754 | bch->ch.nr = ch + 1; | ||
| 4755 | list_add(&bch->ch.list, &dch->dev.bchannels); | ||
| 4756 | hc->chan[i + ch].bch = bch; | ||
| 4757 | hc->chan[i + ch].port = pt; | ||
| 4758 | test_and_set_bit(bch->nr, &dch->dev.channelmap[0]); | ||
| 4759 | } | ||
| 4760 | /* set master clock */ | ||
| 4761 | if (port[Port_cnt] & 0x001) { | ||
| 4762 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4763 | printk(KERN_DEBUG | ||
| 4764 | "%s: PROTOCOL set master clock: " | ||
| 4765 | "card(%d) port(%d)\n", | ||
| 4766 | __func__, HFC_cnt + 1, pt + 1); | ||
| 4767 | if (dch->dev.D.protocol != ISDN_P_TE_S0) { | ||
| 4768 | printk(KERN_ERR "Error: Master clock " | ||
| 4769 | "for port(%d) of card(%d) is only" | ||
| 4770 | " possible with TE-mode\n", | ||
| 4771 | pt + 1, HFC_cnt + 1); | ||
| 4772 | ret = -EINVAL; | ||
| 4773 | goto free_chan; | ||
| 4774 | } | ||
| 4775 | if (hc->masterclk >= 0) { | ||
| 4776 | printk(KERN_ERR "Error: Master clock " | ||
| 4777 | "for port(%d) of card(%d) already " | ||
| 4778 | "defined for port(%d)\n", | ||
| 4779 | pt + 1, HFC_cnt + 1, hc->masterclk+1); | ||
| 4780 | ret = -EINVAL; | ||
| 4781 | goto free_chan; | ||
| 4782 | } | ||
| 4783 | hc->masterclk = pt; | ||
| 4784 | } | ||
| 4785 | /* set transmitter line to non capacitive */ | ||
| 4786 | if (port[Port_cnt] & 0x002) { | ||
| 4787 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4788 | printk(KERN_DEBUG | ||
| 4789 | "%s: PROTOCOL set non capacitive " | ||
| 4790 | "transmitter: card(%d) port(%d)\n", | ||
| 4791 | __func__, HFC_cnt + 1, pt + 1); | ||
| 4792 | test_and_set_bit(HFC_CFG_NONCAP_TX, | ||
| 4793 | &hc->chan[i + 2].cfg); | ||
| 4794 | } | ||
| 4795 | /* disable E-channel */ | ||
| 4796 | if (port[Port_cnt] & 0x004) { | ||
| 4797 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4798 | printk(KERN_DEBUG | ||
| 4799 | "%s: PROTOCOL disable E-channel: " | ||
| 4800 | "card(%d) port(%d)\n", | ||
| 4801 | __func__, HFC_cnt + 1, pt + 1); | ||
| 4802 | test_and_set_bit(HFC_CFG_DIS_ECHANNEL, | ||
| 4803 | &hc->chan[i + 2].cfg); | ||
| 4804 | } | ||
| 4805 | snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d/%d", | ||
| 4806 | hc->type, HFC_cnt + 1, pt + 1); | ||
| 4807 | ret = mISDN_register_device(&dch->dev, name); | ||
| 4808 | if (ret) | ||
| 4809 | goto free_chan; | ||
| 4810 | hc->created[pt] = 1; | ||
| 4811 | return ret; | ||
| 4812 | free_chan: | ||
| 4813 | release_port(hc, dch); | ||
| 4814 | return ret; | ||
| 4815 | } | ||
| 4816 | |||
| 4817 | static int | ||
| 4818 | hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
| 4819 | { | ||
| 4820 | struct hm_map *m = (struct hm_map *)ent->driver_data; | ||
| 4821 | int ret_err = 0; | ||
| 4822 | int pt; | ||
| 4823 | struct hfc_multi *hc; | ||
| 4824 | u_long flags; | ||
| 4825 | u_char dips = 0, pmj = 0; /* dip settings, port mode Jumpers */ | ||
| 4826 | |||
| 4827 | if (HFC_cnt >= MAX_CARDS) { | ||
| 4828 | printk(KERN_ERR "too many cards (max=%d).\n", | ||
| 4829 | MAX_CARDS); | ||
| 4830 | return -EINVAL; | ||
| 4831 | } | ||
| 4832 | if ((type[HFC_cnt] & 0xff) && (type[HFC_cnt] & 0xff) != m->type) { | ||
| 4833 | printk(KERN_WARNING "HFC-MULTI: Card '%s:%s' type %d found but " | ||
| 4834 | "type[%d] %d was supplied as module parameter\n", | ||
| 4835 | m->vendor_name, m->card_name, m->type, HFC_cnt, | ||
| 4836 | type[HFC_cnt] & 0xff); | ||
| 4837 | printk(KERN_WARNING "HFC-MULTI: Load module without parameters " | ||
| 4838 | "first, to see cards and their types."); | ||
| 4839 | return -EINVAL; | ||
| 4840 | } | ||
| 4841 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4842 | printk(KERN_DEBUG "%s: Registering %s:%s chip type %d (0x%x)\n", | ||
| 4843 | __func__, m->vendor_name, m->card_name, m->type, | ||
| 4844 | type[HFC_cnt]); | ||
| 4845 | |||
| 4846 | /* allocate card+fifo structure */ | ||
| 4847 | hc = kzalloc(sizeof(struct hfc_multi), GFP_KERNEL); | ||
| 4848 | if (!hc) { | ||
| 4849 | printk(KERN_ERR "No kmem for HFC-Multi card\n"); | ||
| 4850 | return -ENOMEM; | ||
| 4851 | } | ||
| 4852 | spin_lock_init(&hc->lock); | ||
| 4853 | hc->mtyp = m; | ||
| 4854 | hc->type = m->type; | ||
| 4855 | hc->ports = m->ports; | ||
| 4856 | hc->id = HFC_cnt; | ||
| 4857 | hc->pcm = pcm[HFC_cnt]; | ||
| 4858 | hc->io_mode = iomode[HFC_cnt]; | ||
| 4859 | if (dslot[HFC_cnt] < 0) { | ||
| 4860 | hc->dslot = 0; | ||
| 4861 | printk(KERN_INFO "HFC-E1 card has disabled D-channel, but " | ||
| 4862 | "31 B-channels\n"); | ||
| 4863 | } if (dslot[HFC_cnt] > 0 && dslot[HFC_cnt] < 32) { | ||
| 4864 | hc->dslot = dslot[HFC_cnt]; | ||
| 4865 | printk(KERN_INFO "HFC-E1 card has alternating D-channel on " | ||
| 4866 | "time slot %d\n", dslot[HFC_cnt]); | ||
| 4867 | } else | ||
| 4868 | hc->dslot = 16; | ||
| 4869 | |||
| 4870 | /* set chip specific features */ | ||
| 4871 | hc->masterclk = -1; | ||
| 4872 | if (type[HFC_cnt] & 0x100) { | ||
| 4873 | test_and_set_bit(HFC_CHIP_ULAW, &hc->chip); | ||
| 4874 | silence = 0xff; /* ulaw silence */ | ||
| 4875 | } else | ||
| 4876 | silence = 0x2a; /* alaw silence */ | ||
| 4877 | if (!(type[HFC_cnt] & 0x200)) | ||
| 4878 | test_and_set_bit(HFC_CHIP_DTMF, &hc->chip); | ||
| 4879 | |||
| 4880 | if (type[HFC_cnt] & 0x800) | ||
| 4881 | test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); | ||
| 4882 | if (type[HFC_cnt] & 0x1000) { | ||
| 4883 | test_and_set_bit(HFC_CHIP_PCM_MASTER, &hc->chip); | ||
| 4884 | test_and_clear_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); | ||
| 4885 | } | ||
| 4886 | if (type[HFC_cnt] & 0x4000) | ||
| 4887 | test_and_set_bit(HFC_CHIP_EXRAM_128, &hc->chip); | ||
| 4888 | if (type[HFC_cnt] & 0x8000) | ||
| 4889 | test_and_set_bit(HFC_CHIP_EXRAM_512, &hc->chip); | ||
| 4890 | hc->slots = 32; | ||
| 4891 | if (type[HFC_cnt] & 0x10000) | ||
| 4892 | hc->slots = 64; | ||
| 4893 | if (type[HFC_cnt] & 0x20000) | ||
| 4894 | hc->slots = 128; | ||
| 4895 | if (type[HFC_cnt] & 0x80000) { | ||
| 4896 | test_and_set_bit(HFC_CHIP_WATCHDOG, &hc->chip); | ||
| 4897 | hc->wdcount = 0; | ||
| 4898 | hc->wdbyte = V_GPIO_OUT2; | ||
| 4899 | printk(KERN_NOTICE "Watchdog enabled\n"); | ||
| 4900 | } | ||
| 4901 | |||
| 4902 | /* setup pci, hc->slots may change due to PLXSD */ | ||
| 4903 | ret_err = setup_pci(hc, pdev, ent); | ||
| 4904 | if (ret_err) { | ||
| 4905 | if (hc == syncmaster) | ||
| 4906 | syncmaster = NULL; | ||
| 4907 | kfree(hc); | ||
| 4908 | return ret_err; | ||
| 4909 | } | ||
| 4910 | |||
| 4911 | /* crate channels */ | ||
| 4912 | for (pt = 0; pt < hc->ports; pt++) { | ||
| 4913 | if (Port_cnt >= MAX_PORTS) { | ||
| 4914 | printk(KERN_ERR "too many ports (max=%d).\n", | ||
| 4915 | MAX_PORTS); | ||
| 4916 | ret_err = -EINVAL; | ||
| 4917 | goto free_card; | ||
| 4918 | } | ||
| 4919 | if (hc->type == 1) | ||
| 4920 | ret_err = init_e1_port(hc, m); | ||
| 4921 | else | ||
| 4922 | ret_err = init_multi_port(hc, pt); | ||
| 4923 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 4924 | printk(KERN_DEBUG | ||
| 4925 | "%s: Registering D-channel, card(%d) port(%d)" | ||
| 4926 | "result %d\n", | ||
| 4927 | __func__, HFC_cnt + 1, pt, ret_err); | ||
| 4928 | |||
| 4929 | if (ret_err) { | ||
| 4930 | while (pt) { /* release already registered ports */ | ||
| 4931 | pt--; | ||
| 4932 | release_port(hc, hc->chan[(pt << 2) + 2].dch); | ||
| 4933 | } | ||
| 4934 | goto free_card; | ||
| 4935 | } | ||
| 4936 | Port_cnt++; | ||
| 4937 | } | ||
| 4938 | |||
| 4939 | /* disp switches */ | ||
| 4940 | switch (m->dip_type) { | ||
| 4941 | case DIP_4S: | ||
| 4942 | /* | ||
| 4943 | * get DIP Setting for beroNet 1S/2S/4S cards | ||
| 4944 | * check if Port Jumper config matches | ||
| 4945 | * module param 'protocol' | ||
| 4946 | * DIP Setting: (collect GPIO 13/14/15 (R_GPIO_IN1) + | ||
| 4947 | * GPI 19/23 (R_GPI_IN2)) | ||
| 4948 | */ | ||
| 4949 | dips = ((~HFC_inb(hc, R_GPIO_IN1) & 0xE0) >> 5) | | ||
| 4950 | ((~HFC_inb(hc, R_GPI_IN2) & 0x80) >> 3) | | ||
| 4951 | (~HFC_inb(hc, R_GPI_IN2) & 0x08); | ||
| 4952 | |||
| 4953 | /* Port mode (TE/NT) jumpers */ | ||
| 4954 | pmj = ((HFC_inb(hc, R_GPI_IN3) >> 4) & 0xf); | ||
| 4955 | |||
| 4956 | if (test_bit(HFC_CHIP_B410P, &hc->chip)) | ||
| 4957 | pmj = ~pmj & 0xf; | ||
| 4958 | |||
| 4959 | printk(KERN_INFO "%s: %s DIPs(0x%x) jumpers(0x%x)\n", | ||
| 4960 | m->vendor_name, m->card_name, dips, pmj); | ||
| 4961 | break; | ||
| 4962 | case DIP_8S: | ||
| 4963 | /* | ||
| 4964 | * get DIP Setting for beroNet 8S0+ cards | ||
| 4965 | * | ||
| 4966 | * enable PCI auxbridge function | ||
| 4967 | */ | ||
| 4968 | HFC_outb(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK); | ||
| 4969 | /* prepare access to auxport */ | ||
| 4970 | outw(0x4000, hc->pci_iobase + 4); | ||
| 4971 | /* | ||
| 4972 | * some dummy reads are required to | ||
| 4973 | * read valid DIP switch data | ||
| 4974 | */ | ||
| 4975 | dips = inb(hc->pci_iobase); | ||
| 4976 | dips = inb(hc->pci_iobase); | ||
| 4977 | dips = inb(hc->pci_iobase); | ||
| 4978 | dips = ~inb(hc->pci_iobase) & 0x3F; | ||
| 4979 | outw(0x0, hc->pci_iobase + 4); | ||
| 4980 | /* disable PCI auxbridge function */ | ||
| 4981 | HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK); | ||
| 4982 | printk(KERN_INFO "%s: %s DIPs(0x%x)\n", | ||
| 4983 | m->vendor_name, m->card_name, dips); | ||
| 4984 | break; | ||
| 4985 | case DIP_E1: | ||
| 4986 | /* | ||
| 4987 | * get DIP Setting for beroNet E1 cards | ||
| 4988 | * DIP Setting: collect GPI 4/5/6/7 (R_GPI_IN0) | ||
| 4989 | */ | ||
| 4990 | dips = (~HFC_inb(hc, R_GPI_IN0) & 0xF0)>>4; | ||
| 4991 | printk(KERN_INFO "%s: %s DIPs(0x%x)\n", | ||
| 4992 | m->vendor_name, m->card_name, dips); | ||
| 4993 | break; | ||
| 4994 | } | ||
| 4995 | |||
| 4996 | /* add to list */ | ||
| 4997 | spin_lock_irqsave(&HFClock, flags); | ||
| 4998 | list_add_tail(&hc->list, &HFClist); | ||
| 4999 | spin_unlock_irqrestore(&HFClock, flags); | ||
| 5000 | |||
| 5001 | /* initialize hardware */ | ||
| 5002 | ret_err = init_card(hc); | ||
| 5003 | if (ret_err) { | ||
| 5004 | printk(KERN_ERR "init card returns %d\n", ret_err); | ||
| 5005 | release_card(hc); | ||
| 5006 | return ret_err; | ||
| 5007 | } | ||
| 5008 | |||
| 5009 | /* start IRQ and return */ | ||
| 5010 | spin_lock_irqsave(&hc->lock, flags); | ||
| 5011 | enable_hwirq(hc); | ||
| 5012 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 5013 | return 0; | ||
| 5014 | |||
| 5015 | free_card: | ||
| 5016 | release_io_hfcmulti(hc); | ||
| 5017 | if (hc == syncmaster) | ||
| 5018 | syncmaster = NULL; | ||
| 5019 | kfree(hc); | ||
| 5020 | return ret_err; | ||
| 5021 | } | ||
| 5022 | |||
| 5023 | static void __devexit hfc_remove_pci(struct pci_dev *pdev) | ||
| 5024 | { | ||
| 5025 | struct hfc_multi *card = pci_get_drvdata(pdev); | ||
| 5026 | u_long flags; | ||
| 5027 | |||
| 5028 | if (debug) | ||
| 5029 | printk(KERN_INFO "removing hfc_multi card vendor:%x " | ||
| 5030 | "device:%x subvendor:%x subdevice:%x\n", | ||
| 5031 | pdev->vendor, pdev->device, | ||
| 5032 | pdev->subsystem_vendor, pdev->subsystem_device); | ||
| 5033 | |||
| 5034 | if (card) { | ||
| 5035 | spin_lock_irqsave(&HFClock, flags); | ||
| 5036 | release_card(card); | ||
| 5037 | spin_unlock_irqrestore(&HFClock, flags); | ||
| 5038 | } else { | ||
| 5039 | if (debug) | ||
| 5040 | printk(KERN_WARNING "%s: drvdata allready removed\n", | ||
| 5041 | __func__); | ||
| 5042 | } | ||
| 5043 | } | ||
| 5044 | |||
| 5045 | #define VENDOR_CCD "Cologne Chip AG" | ||
| 5046 | #define VENDOR_BN "beroNet GmbH" | ||
| 5047 | #define VENDOR_DIG "Digium Inc." | ||
| 5048 | #define VENDOR_JH "Junghanns.NET GmbH" | ||
| 5049 | #define VENDOR_PRIM "PrimuX" | ||
| 5050 | |||
| 5051 | static const struct hm_map hfcm_map[] = { | ||
| 5052 | /*0*/ {VENDOR_BN, "HFC-1S Card (mini PCI)", 4, 1, 1, 3, 0, DIP_4S, 0}, | ||
| 5053 | /*1*/ {VENDOR_BN, "HFC-2S Card", 4, 2, 1, 3, 0, DIP_4S}, | ||
| 5054 | /*2*/ {VENDOR_BN, "HFC-2S Card (mini PCI)", 4, 2, 1, 3, 0, DIP_4S, 0}, | ||
| 5055 | /*3*/ {VENDOR_BN, "HFC-4S Card", 4, 4, 1, 2, 0, DIP_4S, 0}, | ||
| 5056 | /*4*/ {VENDOR_BN, "HFC-4S Card (mini PCI)", 4, 4, 1, 2, 0, 0, 0}, | ||
| 5057 | /*5*/ {VENDOR_CCD, "HFC-4S Eval (old)", 4, 4, 0, 0, 0, 0, 0}, | ||
| 5058 | /*6*/ {VENDOR_CCD, "HFC-4S IOB4ST", 4, 4, 1, 2, 0, 0, 0}, | ||
| 5059 | /*7*/ {VENDOR_CCD, "HFC-4S", 4, 4, 1, 2, 0, 0, 0}, | ||
| 5060 | /*8*/ {VENDOR_DIG, "HFC-4S Card", 4, 4, 0, 2, 0, 0, HFC_IO_MODE_REGIO}, | ||
| 5061 | /*9*/ {VENDOR_CCD, "HFC-4S Swyx 4xS0 SX2 QuadBri", 4, 4, 1, 2, 0, 0, 0}, | ||
| 5062 | /*10*/ {VENDOR_JH, "HFC-4S (junghanns 2.0)", 4, 4, 1, 2, 0, 0, 0}, | ||
| 5063 | /*11*/ {VENDOR_PRIM, "HFC-2S Primux Card", 4, 2, 0, 0, 0, 0, 0}, | ||
| 5064 | |||
| 5065 | /*12*/ {VENDOR_BN, "HFC-8S Card", 8, 8, 1, 0, 0, 0, 0}, | ||
| 5066 | /*13*/ {VENDOR_BN, "HFC-8S Card (+)", 8, 8, 1, 8, 0, DIP_8S, | ||
| 5067 | HFC_IO_MODE_REGIO}, | ||
| 5068 | /*14*/ {VENDOR_CCD, "HFC-8S Eval (old)", 8, 8, 0, 0, 0, 0, 0}, | ||
| 5069 | /*15*/ {VENDOR_CCD, "HFC-8S IOB4ST Recording", 8, 8, 1, 0, 0, 0, 0}, | ||
| 5070 | |||
| 5071 | /*16*/ {VENDOR_CCD, "HFC-8S IOB8ST", 8, 8, 1, 0, 0, 0, 0}, | ||
| 5072 | /*17*/ {VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0}, | ||
| 5073 | /*18*/ {VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0}, | ||
| 5074 | |||
| 5075 | /*19*/ {VENDOR_BN, "HFC-E1 Card", 1, 1, 0, 1, 0, DIP_E1, 0}, | ||
| 5076 | /*20*/ {VENDOR_BN, "HFC-E1 Card (mini PCI)", 1, 1, 0, 1, 0, 0, 0}, | ||
| 5077 | /*21*/ {VENDOR_BN, "HFC-E1+ Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0}, | ||
| 5078 | /*22*/ {VENDOR_BN, "HFC-E1 Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0}, | ||
| 5079 | |||
| 5080 | /*23*/ {VENDOR_CCD, "HFC-E1 Eval (old)", 1, 1, 0, 0, 0, 0, 0}, | ||
| 5081 | /*24*/ {VENDOR_CCD, "HFC-E1 IOB1E1", 1, 1, 0, 1, 0, 0, 0}, | ||
| 5082 | /*25*/ {VENDOR_CCD, "HFC-E1", 1, 1, 0, 1, 0, 0, 0}, | ||
| 5083 | |||
| 5084 | /*26*/ {VENDOR_CCD, "HFC-4S Speech Design", 4, 4, 0, 0, 0, 0, | ||
| 5085 | HFC_IO_MODE_PLXSD}, | ||
| 5086 | /*27*/ {VENDOR_CCD, "HFC-E1 Speech Design", 1, 1, 0, 0, 0, 0, | ||
| 5087 | HFC_IO_MODE_PLXSD}, | ||
| 5088 | /*28*/ {VENDOR_CCD, "HFC-4S OpenVox", 4, 4, 1, 0, 0, 0, 0}, | ||
| 5089 | /*29*/ {VENDOR_CCD, "HFC-2S OpenVox", 4, 2, 1, 0, 0, 0, 0}, | ||
| 5090 | /*30*/ {VENDOR_CCD, "HFC-8S OpenVox", 8, 8, 1, 0, 0, 0, 0}, | ||
| 5091 | }; | ||
| 5092 | |||
| 5093 | #undef H | ||
| 5094 | #define H(x) ((unsigned long)&hfcm_map[x]) | ||
| 5095 | static struct pci_device_id hfmultipci_ids[] __devinitdata = { | ||
| 5096 | |||
| 5097 | /* Cards with HFC-4S Chip */ | ||
| 5098 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
| 5099 | PCI_SUBDEVICE_ID_CCD_BN1SM, 0, 0, H(0)}, /* BN1S mini PCI */ | ||
| 5100 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
| 5101 | PCI_SUBDEVICE_ID_CCD_BN2S, 0, 0, H(1)}, /* BN2S */ | ||
| 5102 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
| 5103 | PCI_SUBDEVICE_ID_CCD_BN2SM, 0, 0, H(2)}, /* BN2S mini PCI */ | ||
| 5104 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
| 5105 | PCI_SUBDEVICE_ID_CCD_BN4S, 0, 0, H(3)}, /* BN4S */ | ||
| 5106 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
| 5107 | PCI_SUBDEVICE_ID_CCD_BN4SM, 0, 0, H(4)}, /* BN4S mini PCI */ | ||
| 5108 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
| 5109 | PCI_DEVICE_ID_CCD_HFC4S, 0, 0, H(5)}, /* Old Eval */ | ||
| 5110 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
| 5111 | PCI_SUBDEVICE_ID_CCD_IOB4ST, 0, 0, H(6)}, /* IOB4ST */ | ||
| 5112 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
| 5113 | PCI_SUBDEVICE_ID_CCD_HFC4S, 0, 0, H(7)}, /* 4S */ | ||
| 5114 | { PCI_VENDOR_ID_DIGIUM, PCI_DEVICE_ID_DIGIUM_HFC4S, | ||
| 5115 | PCI_VENDOR_ID_DIGIUM, PCI_DEVICE_ID_DIGIUM_HFC4S, 0, 0, H(8)}, | ||
| 5116 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
| 5117 | PCI_SUBDEVICE_ID_CCD_SWYX4S, 0, 0, H(9)}, /* 4S Swyx */ | ||
| 5118 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
| 5119 | PCI_SUBDEVICE_ID_CCD_JH4S20, 0, 0, H(10)}, | ||
| 5120 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
| 5121 | PCI_SUBDEVICE_ID_CCD_PMX2S, 0, 0, H(11)}, /* Primux */ | ||
| 5122 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
| 5123 | PCI_SUBDEVICE_ID_CCD_OV4S, 0, 0, H(28)}, /* OpenVox 4 */ | ||
| 5124 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD, | ||
| 5125 | PCI_SUBDEVICE_ID_CCD_OV2S, 0, 0, H(29)}, /* OpenVox 2 */ | ||
| 5126 | |||
| 5127 | /* Cards with HFC-8S Chip */ | ||
| 5128 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | ||
| 5129 | PCI_SUBDEVICE_ID_CCD_BN8S, 0, 0, H(12)}, /* BN8S */ | ||
| 5130 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | ||
| 5131 | PCI_SUBDEVICE_ID_CCD_BN8SP, 0, 0, H(13)}, /* BN8S+ */ | ||
| 5132 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | ||
| 5133 | PCI_DEVICE_ID_CCD_HFC8S, 0, 0, H(14)}, /* old Eval */ | ||
| 5134 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | ||
| 5135 | PCI_SUBDEVICE_ID_CCD_IOB8STR, 0, 0, H(15)}, | ||
| 5136 | /* IOB8ST Recording */ | ||
| 5137 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | ||
| 5138 | PCI_SUBDEVICE_ID_CCD_IOB8ST, 0, 0, H(16)}, /* IOB8ST */ | ||
| 5139 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | ||
| 5140 | PCI_SUBDEVICE_ID_CCD_IOB8ST_1, 0, 0, H(17)}, /* IOB8ST */ | ||
| 5141 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | ||
| 5142 | PCI_SUBDEVICE_ID_CCD_HFC8S, 0, 0, H(18)}, /* 8S */ | ||
| 5143 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, | ||
| 5144 | PCI_SUBDEVICE_ID_CCD_OV8S, 0, 0, H(30)}, /* OpenVox 8 */ | ||
| 5145 | |||
| 5146 | |||
| 5147 | /* Cards with HFC-E1 Chip */ | ||
| 5148 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | ||
| 5149 | PCI_SUBDEVICE_ID_CCD_BNE1, 0, 0, H(19)}, /* BNE1 */ | ||
| 5150 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | ||
| 5151 | PCI_SUBDEVICE_ID_CCD_BNE1M, 0, 0, H(20)}, /* BNE1 mini PCI */ | ||
| 5152 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | ||
| 5153 | PCI_SUBDEVICE_ID_CCD_BNE1DP, 0, 0, H(21)}, /* BNE1 + (Dual) */ | ||
| 5154 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | ||
| 5155 | PCI_SUBDEVICE_ID_CCD_BNE1D, 0, 0, H(22)}, /* BNE1 (Dual) */ | ||
| 5156 | |||
| 5157 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | ||
| 5158 | PCI_DEVICE_ID_CCD_HFCE1, 0, 0, H(23)}, /* Old Eval */ | ||
| 5159 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | ||
| 5160 | PCI_SUBDEVICE_ID_CCD_IOB1E1, 0, 0, H(24)}, /* IOB1E1 */ | ||
| 5161 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, | ||
| 5162 | PCI_SUBDEVICE_ID_CCD_HFCE1, 0, 0, H(25)}, /* E1 */ | ||
| 5163 | |||
| 5164 | { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_CCD, | ||
| 5165 | PCI_SUBDEVICE_ID_CCD_SPD4S, 0, 0, H(26)}, /* PLX PCI Bridge */ | ||
| 5166 | { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_CCD, | ||
| 5167 | PCI_SUBDEVICE_ID_CCD_SPDE1, 0, 0, H(27)}, /* PLX PCI Bridge */ | ||
| 5168 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_ANY_ID, PCI_ANY_ID, | ||
| 5169 | 0, 0, 0}, | ||
| 5170 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_ANY_ID, PCI_ANY_ID, | ||
| 5171 | 0, 0, 0}, | ||
| 5172 | { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_ANY_ID, PCI_ANY_ID, | ||
| 5173 | 0, 0, 0}, | ||
| 5174 | {0, } | ||
| 5175 | }; | ||
| 5176 | #undef H | ||
| 5177 | |||
| 5178 | MODULE_DEVICE_TABLE(pci, hfmultipci_ids); | ||
| 5179 | |||
| 5180 | static int | ||
| 5181 | hfcmulti_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
| 5182 | { | ||
| 5183 | struct hm_map *m = (struct hm_map *)ent->driver_data; | ||
| 5184 | int ret; | ||
| 5185 | |||
| 5186 | if (m == NULL) { | ||
| 5187 | if (ent->vendor == PCI_VENDOR_ID_CCD) | ||
| 5188 | if (ent->device == PCI_DEVICE_ID_CCD_HFC4S || | ||
| 5189 | ent->device == PCI_DEVICE_ID_CCD_HFC8S || | ||
| 5190 | ent->device == PCI_DEVICE_ID_CCD_HFCE1) | ||
| 5191 | printk(KERN_ERR | ||
| 5192 | "unknown HFC multiport controller " | ||
| 5193 | "(vendor:%x device:%x subvendor:%x " | ||
| 5194 | "subdevice:%x) Please contact the " | ||
| 5195 | "driver maintainer for support.\n", | ||
| 5196 | ent->vendor, ent->device, | ||
| 5197 | ent->subvendor, ent->subdevice); | ||
| 5198 | return -ENODEV; | ||
| 5199 | } | ||
| 5200 | ret = hfcmulti_init(pdev, ent); | ||
| 5201 | if (ret) | ||
| 5202 | return ret; | ||
| 5203 | HFC_cnt++; | ||
| 5204 | printk(KERN_INFO "%d devices registered\n", HFC_cnt); | ||
| 5205 | return 0; | ||
| 5206 | } | ||
| 5207 | |||
| 5208 | static struct pci_driver hfcmultipci_driver = { | ||
| 5209 | .name = "hfc_multi", | ||
| 5210 | .probe = hfcmulti_probe, | ||
| 5211 | .remove = __devexit_p(hfc_remove_pci), | ||
| 5212 | .id_table = hfmultipci_ids, | ||
| 5213 | }; | ||
| 5214 | |||
| 5215 | static void __exit | ||
| 5216 | HFCmulti_cleanup(void) | ||
| 5217 | { | ||
| 5218 | struct hfc_multi *card, *next; | ||
| 5219 | |||
| 5220 | /* unload interrupt function symbol */ | ||
| 5221 | if (hfc_interrupt) | ||
| 5222 | symbol_put(ztdummy_extern_interrupt); | ||
| 5223 | if (register_interrupt) | ||
| 5224 | symbol_put(ztdummy_register_interrupt); | ||
| 5225 | if (unregister_interrupt) { | ||
| 5226 | if (interrupt_registered) { | ||
| 5227 | interrupt_registered = 0; | ||
| 5228 | unregister_interrupt(); | ||
| 5229 | } | ||
| 5230 | symbol_put(ztdummy_unregister_interrupt); | ||
| 5231 | } | ||
| 5232 | |||
| 5233 | list_for_each_entry_safe(card, next, &HFClist, list) | ||
| 5234 | release_card(card); | ||
| 5235 | /* get rid of all devices of this driver */ | ||
| 5236 | pci_unregister_driver(&hfcmultipci_driver); | ||
| 5237 | } | ||
| 5238 | |||
| 5239 | static int __init | ||
| 5240 | HFCmulti_init(void) | ||
| 5241 | { | ||
| 5242 | int err; | ||
| 5243 | |||
| 5244 | #ifdef IRQ_DEBUG | ||
| 5245 | printk(KERN_ERR "%s: IRQ_DEBUG IS ENABLED!\n", __func__); | ||
| 5246 | #endif | ||
| 5247 | |||
| 5248 | spin_lock_init(&HFClock); | ||
| 5249 | spin_lock_init(&plx_lock); | ||
| 5250 | |||
| 5251 | if (debug & DEBUG_HFCMULTI_INIT) | ||
| 5252 | printk(KERN_DEBUG "%s: init entered\n", __func__); | ||
| 5253 | |||
| 5254 | #ifdef __BIG_ENDIAN | ||
| 5255 | #error "not running on big endian machines now" | ||
| 5256 | #endif | ||
| 5257 | hfc_interrupt = symbol_get(ztdummy_extern_interrupt); | ||
| 5258 | register_interrupt = symbol_get(ztdummy_register_interrupt); | ||
| 5259 | unregister_interrupt = symbol_get(ztdummy_unregister_interrupt); | ||
| 5260 | printk(KERN_INFO "mISDN: HFC-multi driver %s\n", | ||
| 5261 | hfcmulti_revision); | ||
| 5262 | |||
| 5263 | switch (poll) { | ||
| 5264 | case 0: | ||
| 5265 | poll_timer = 6; | ||
| 5266 | poll = 128; | ||
| 5267 | break; | ||
| 5268 | /* | ||
| 5269 | * wenn dieses break nochmal verschwindet, | ||
| 5270 | * gibt es heisse ohren :-) | ||
| 5271 | * "without the break you will get hot ears ???" | ||
| 5272 | */ | ||
| 5273 | case 8: | ||
| 5274 | poll_timer = 2; | ||
| 5275 | break; | ||
| 5276 | case 16: | ||
| 5277 | poll_timer = 3; | ||
| 5278 | break; | ||
| 5279 | case 32: | ||
| 5280 | poll_timer = 4; | ||
| 5281 | break; | ||
| 5282 | case 64: | ||
| 5283 | poll_timer = 5; | ||
| 5284 | break; | ||
| 5285 | case 128: | ||
| 5286 | poll_timer = 6; | ||
| 5287 | break; | ||
| 5288 | case 256: | ||
| 5289 | poll_timer = 7; | ||
| 5290 | break; | ||
| 5291 | default: | ||
| 5292 | printk(KERN_ERR | ||
| 5293 | "%s: Wrong poll value (%d).\n", __func__, poll); | ||
| 5294 | err = -EINVAL; | ||
| 5295 | return err; | ||
| 5296 | |||
| 5297 | } | ||
| 5298 | |||
| 5299 | err = pci_register_driver(&hfcmultipci_driver); | ||
| 5300 | if (err < 0) { | ||
| 5301 | printk(KERN_ERR "error registering pci driver: %x\n", err); | ||
| 5302 | if (hfc_interrupt) | ||
| 5303 | symbol_put(ztdummy_extern_interrupt); | ||
| 5304 | if (register_interrupt) | ||
| 5305 | symbol_put(ztdummy_register_interrupt); | ||
| 5306 | if (unregister_interrupt) { | ||
| 5307 | if (interrupt_registered) { | ||
| 5308 | interrupt_registered = 0; | ||
| 5309 | unregister_interrupt(); | ||
| 5310 | } | ||
| 5311 | symbol_put(ztdummy_unregister_interrupt); | ||
| 5312 | } | ||
| 5313 | return err; | ||
| 5314 | } | ||
| 5315 | return 0; | ||
| 5316 | } | ||
| 5317 | |||
| 5318 | |||
| 5319 | module_init(HFCmulti_init); | ||
| 5320 | module_exit(HFCmulti_cleanup); | ||
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c new file mode 100644 index 000000000000..917968530e1e --- /dev/null +++ b/drivers/isdn/hardware/mISDN/hfcpci.c | |||
| @@ -0,0 +1,2256 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * hfcpci.c low level driver for CCD's hfc-pci based cards | ||
| 4 | * | ||
| 5 | * Author Werner Cornelius (werner@isdn4linux.de) | ||
| 6 | * based on existing driver for CCD hfc ISA cards | ||
| 7 | * type approval valid for HFC-S PCI A based card | ||
| 8 | * | ||
| 9 | * Copyright 1999 by Werner Cornelius (werner@isdn-development.de) | ||
| 10 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License as published by | ||
| 14 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 15 | * any later version. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU General Public License for more details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU General Public License | ||
| 23 | * along with this program; if not, write to the Free Software | ||
| 24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 25 | * | ||
| 26 | */ | ||
| 27 | |||
| 28 | #include <linux/module.h> | ||
| 29 | #include <linux/pci.h> | ||
| 30 | #include <linux/delay.h> | ||
| 31 | #include <linux/mISDNhw.h> | ||
| 32 | |||
| 33 | #include "hfc_pci.h" | ||
| 34 | |||
| 35 | static const char *hfcpci_revision = "2.0"; | ||
| 36 | |||
| 37 | #define MAX_CARDS 8 | ||
| 38 | static int HFC_cnt; | ||
| 39 | static uint debug; | ||
| 40 | |||
| 41 | MODULE_AUTHOR("Karsten Keil"); | ||
| 42 | MODULE_LICENSE("GPL"); | ||
| 43 | module_param(debug, uint, 0); | ||
| 44 | |||
| 45 | static LIST_HEAD(HFClist); | ||
| 46 | DEFINE_RWLOCK(HFClock); | ||
| 47 | |||
| 48 | enum { | ||
| 49 | HFC_CCD_2BD0, | ||
| 50 | HFC_CCD_B000, | ||
| 51 | HFC_CCD_B006, | ||
| 52 | HFC_CCD_B007, | ||
| 53 | HFC_CCD_B008, | ||
| 54 | HFC_CCD_B009, | ||
| 55 | HFC_CCD_B00A, | ||
| 56 | HFC_CCD_B00B, | ||
| 57 | HFC_CCD_B00C, | ||
| 58 | HFC_CCD_B100, | ||
| 59 | HFC_CCD_B700, | ||
| 60 | HFC_CCD_B701, | ||
| 61 | HFC_ASUS_0675, | ||
| 62 | HFC_BERKOM_A1T, | ||
| 63 | HFC_BERKOM_TCONCEPT, | ||
| 64 | HFC_ANIGMA_MC145575, | ||
| 65 | HFC_ZOLTRIX_2BD0, | ||
| 66 | HFC_DIGI_DF_M_IOM2_E, | ||
| 67 | HFC_DIGI_DF_M_E, | ||
| 68 | HFC_DIGI_DF_M_IOM2_A, | ||
| 69 | HFC_DIGI_DF_M_A, | ||
| 70 | HFC_ABOCOM_2BD1, | ||
| 71 | HFC_SITECOM_DC105V2, | ||
| 72 | }; | ||
| 73 | |||
| 74 | struct hfcPCI_hw { | ||
| 75 | unsigned char cirm; | ||
| 76 | unsigned char ctmt; | ||
| 77 | unsigned char clkdel; | ||
| 78 | unsigned char states; | ||
| 79 | unsigned char conn; | ||
| 80 | unsigned char mst_m; | ||
| 81 | unsigned char int_m1; | ||
| 82 | unsigned char int_m2; | ||
| 83 | unsigned char sctrl; | ||
| 84 | unsigned char sctrl_r; | ||
| 85 | unsigned char sctrl_e; | ||
| 86 | unsigned char trm; | ||
| 87 | unsigned char fifo_en; | ||
| 88 | unsigned char bswapped; | ||
| 89 | unsigned char protocol; | ||
| 90 | int nt_timer; | ||
| 91 | unsigned char *pci_io; /* start of PCI IO memory */ | ||
| 92 | dma_addr_t dmahandle; | ||
| 93 | void *fifos; /* FIFO memory */ | ||
| 94 | int last_bfifo_cnt[2]; | ||
| 95 | /* marker saving last b-fifo frame count */ | ||
| 96 | struct timer_list timer; | ||
| 97 | }; | ||
| 98 | |||
| 99 | #define HFC_CFG_MASTER 1 | ||
| 100 | #define HFC_CFG_SLAVE 2 | ||
| 101 | #define HFC_CFG_PCM 3 | ||
| 102 | #define HFC_CFG_2HFC 4 | ||
| 103 | #define HFC_CFG_SLAVEHFC 5 | ||
| 104 | #define HFC_CFG_NEG_F0 6 | ||
| 105 | #define HFC_CFG_SW_DD_DU 7 | ||
| 106 | |||
| 107 | #define FLG_HFC_TIMER_T1 16 | ||
| 108 | #define FLG_HFC_TIMER_T3 17 | ||
| 109 | |||
| 110 | #define NT_T1_COUNT 1120 /* number of 3.125ms interrupts (3.5s) */ | ||
| 111 | #define NT_T3_COUNT 31 /* number of 3.125ms interrupts (97 ms) */ | ||
| 112 | #define CLKDEL_TE 0x0e /* CLKDEL in TE mode */ | ||
| 113 | #define CLKDEL_NT 0x6c /* CLKDEL in NT mode */ | ||
| 114 | |||
| 115 | |||
| 116 | struct hfc_pci { | ||
| 117 | struct list_head list; | ||
| 118 | u_char subtype; | ||
| 119 | u_char chanlimit; | ||
| 120 | u_char initdone; | ||
| 121 | u_long cfg; | ||
| 122 | u_int irq; | ||
| 123 | u_int irqcnt; | ||
| 124 | struct pci_dev *pdev; | ||
| 125 | struct hfcPCI_hw hw; | ||
| 126 | spinlock_t lock; /* card lock */ | ||
| 127 | struct dchannel dch; | ||
| 128 | struct bchannel bch[2]; | ||
| 129 | }; | ||
| 130 | |||
| 131 | /* Interface functions */ | ||
| 132 | static void | ||
| 133 | enable_hwirq(struct hfc_pci *hc) | ||
| 134 | { | ||
| 135 | hc->hw.int_m2 |= HFCPCI_IRQ_ENABLE; | ||
| 136 | Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2); | ||
| 137 | } | ||
| 138 | |||
| 139 | static void | ||
| 140 | disable_hwirq(struct hfc_pci *hc) | ||
| 141 | { | ||
| 142 | hc->hw.int_m2 &= ~((u_char)HFCPCI_IRQ_ENABLE); | ||
| 143 | Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2); | ||
| 144 | } | ||
| 145 | |||
| 146 | /* | ||
| 147 | * free hardware resources used by driver | ||
| 148 | */ | ||
| 149 | static void | ||
| 150 | release_io_hfcpci(struct hfc_pci *hc) | ||
| 151 | { | ||
| 152 | /* disable memory mapped ports + busmaster */ | ||
| 153 | pci_write_config_word(hc->pdev, PCI_COMMAND, 0); | ||
| 154 | del_timer(&hc->hw.timer); | ||
| 155 | pci_free_consistent(hc->pdev, 0x8000, hc->hw.fifos, hc->hw.dmahandle); | ||
| 156 | iounmap((void *)hc->hw.pci_io); | ||
| 157 | } | ||
| 158 | |||
| 159 | /* | ||
| 160 | * set mode (NT or TE) | ||
| 161 | */ | ||
| 162 | static void | ||
| 163 | hfcpci_setmode(struct hfc_pci *hc) | ||
| 164 | { | ||
| 165 | if (hc->hw.protocol == ISDN_P_NT_S0) { | ||
| 166 | hc->hw.clkdel = CLKDEL_NT; /* ST-Bit delay for NT-Mode */ | ||
| 167 | hc->hw.sctrl |= SCTRL_MODE_NT; /* NT-MODE */ | ||
| 168 | hc->hw.states = 1; /* G1 */ | ||
| 169 | } else { | ||
| 170 | hc->hw.clkdel = CLKDEL_TE; /* ST-Bit delay for TE-Mode */ | ||
| 171 | hc->hw.sctrl &= ~SCTRL_MODE_NT; /* TE-MODE */ | ||
| 172 | hc->hw.states = 2; /* F2 */ | ||
| 173 | } | ||
| 174 | Write_hfc(hc, HFCPCI_CLKDEL, hc->hw.clkdel); | ||
| 175 | Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | hc->hw.states); | ||
| 176 | udelay(10); | ||
| 177 | Write_hfc(hc, HFCPCI_STATES, hc->hw.states | 0x40); /* Deactivate */ | ||
| 178 | Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl); | ||
| 179 | } | ||
| 180 | |||
| 181 | /* | ||
| 182 | * function called to reset the HFC PCI chip. A complete software reset of chip | ||
| 183 | * and fifos is done. | ||
| 184 | */ | ||
| 185 | static void | ||
| 186 | reset_hfcpci(struct hfc_pci *hc) | ||
| 187 | { | ||
| 188 | u_char val; | ||
| 189 | int cnt = 0; | ||
| 190 | |||
| 191 | printk(KERN_DEBUG "reset_hfcpci: entered\n"); | ||
| 192 | val = Read_hfc(hc, HFCPCI_CHIP_ID); | ||
| 193 | printk(KERN_INFO "HFC_PCI: resetting HFC ChipId(%x)\n", val); | ||
| 194 | /* enable memory mapped ports, disable busmaster */ | ||
| 195 | pci_write_config_word(hc->pdev, PCI_COMMAND, PCI_ENA_MEMIO); | ||
| 196 | disable_hwirq(hc); | ||
| 197 | /* enable memory ports + busmaster */ | ||
| 198 | pci_write_config_word(hc->pdev, PCI_COMMAND, | ||
| 199 | PCI_ENA_MEMIO + PCI_ENA_MASTER); | ||
| 200 | val = Read_hfc(hc, HFCPCI_STATUS); | ||
| 201 | printk(KERN_DEBUG "HFC-PCI status(%x) before reset\n", val); | ||
| 202 | hc->hw.cirm = HFCPCI_RESET; /* Reset On */ | ||
| 203 | Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); | ||
| 204 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
| 205 | mdelay(10); /* Timeout 10ms */ | ||
| 206 | hc->hw.cirm = 0; /* Reset Off */ | ||
| 207 | Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); | ||
| 208 | val = Read_hfc(hc, HFCPCI_STATUS); | ||
| 209 | printk(KERN_DEBUG "HFC-PCI status(%x) after reset\n", val); | ||
| 210 | while (cnt < 50000) { /* max 50000 us */ | ||
| 211 | udelay(5); | ||
| 212 | cnt += 5; | ||
| 213 | val = Read_hfc(hc, HFCPCI_STATUS); | ||
| 214 | if (!(val & 2)) | ||
| 215 | break; | ||
| 216 | } | ||
| 217 | printk(KERN_DEBUG "HFC-PCI status(%x) after %dus\n", val, cnt); | ||
| 218 | |||
| 219 | hc->hw.fifo_en = 0x30; /* only D fifos enabled */ | ||
| 220 | |||
| 221 | hc->hw.bswapped = 0; /* no exchange */ | ||
| 222 | hc->hw.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER; | ||
| 223 | hc->hw.trm = HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */ | ||
| 224 | hc->hw.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */ | ||
| 225 | hc->hw.sctrl_r = 0; | ||
| 226 | hc->hw.sctrl_e = HFCPCI_AUTO_AWAKE; /* S/T Auto awake */ | ||
| 227 | hc->hw.mst_m = 0; | ||
| 228 | if (test_bit(HFC_CFG_MASTER, &hc->cfg)) | ||
| 229 | hc->hw.mst_m |= HFCPCI_MASTER; /* HFC Master Mode */ | ||
| 230 | if (test_bit(HFC_CFG_NEG_F0, &hc->cfg)) | ||
| 231 | hc->hw.mst_m |= HFCPCI_F0_NEGATIV; | ||
| 232 | Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); | ||
| 233 | Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); | ||
| 234 | Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e); | ||
| 235 | Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt); | ||
| 236 | |||
| 237 | hc->hw.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC | | ||
| 238 | HFCPCI_INTS_L1STATE | HFCPCI_INTS_TIMER; | ||
| 239 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
| 240 | |||
| 241 | /* Clear already pending ints */ | ||
| 242 | if (Read_hfc(hc, HFCPCI_INT_S1)); | ||
| 243 | |||
| 244 | /* set NT/TE mode */ | ||
| 245 | hfcpci_setmode(hc); | ||
| 246 | |||
| 247 | Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); | ||
| 248 | Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r); | ||
| 249 | |||
| 250 | /* | ||
| 251 | * Init GCI/IOM2 in master mode | ||
| 252 | * Slots 0 and 1 are set for B-chan 1 and 2 | ||
| 253 | * D- and monitor/CI channel are not enabled | ||
| 254 | * STIO1 is used as output for data, B1+B2 from ST->IOM+HFC | ||
| 255 | * STIO2 is used as data input, B1+B2 from IOM->ST | ||
| 256 | * ST B-channel send disabled -> continous 1s | ||
| 257 | * The IOM slots are always enabled | ||
| 258 | */ | ||
| 259 | if (test_bit(HFC_CFG_PCM, &hc->cfg)) { | ||
| 260 | /* set data flow directions: connect B1,B2: HFC to/from PCM */ | ||
| 261 | hc->hw.conn = 0x09; | ||
| 262 | } else { | ||
| 263 | hc->hw.conn = 0x36; /* set data flow directions */ | ||
| 264 | if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) { | ||
| 265 | Write_hfc(hc, HFCPCI_B1_SSL, 0xC0); | ||
| 266 | Write_hfc(hc, HFCPCI_B2_SSL, 0xC1); | ||
| 267 | Write_hfc(hc, HFCPCI_B1_RSL, 0xC0); | ||
| 268 | Write_hfc(hc, HFCPCI_B2_RSL, 0xC1); | ||
| 269 | } else { | ||
| 270 | Write_hfc(hc, HFCPCI_B1_SSL, 0x80); | ||
| 271 | Write_hfc(hc, HFCPCI_B2_SSL, 0x81); | ||
| 272 | Write_hfc(hc, HFCPCI_B1_RSL, 0x80); | ||
| 273 | Write_hfc(hc, HFCPCI_B2_RSL, 0x81); | ||
| 274 | } | ||
| 275 | } | ||
| 276 | Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); | ||
| 277 | val = Read_hfc(hc, HFCPCI_INT_S2); | ||
| 278 | } | ||
| 279 | |||
| 280 | /* | ||
| 281 | * Timer function called when kernel timer expires | ||
| 282 | */ | ||
| 283 | static void | ||
| 284 | hfcpci_Timer(struct hfc_pci *hc) | ||
| 285 | { | ||
| 286 | hc->hw.timer.expires = jiffies + 75; | ||
| 287 | /* WD RESET */ | ||
| 288 | /* | ||
| 289 | * WriteReg(hc, HFCD_DATA, HFCD_CTMT, hc->hw.ctmt | 0x80); | ||
| 290 | * add_timer(&hc->hw.timer); | ||
| 291 | */ | ||
| 292 | } | ||
| 293 | |||
| 294 | |||
| 295 | /* | ||
| 296 | * select a b-channel entry matching and active | ||
| 297 | */ | ||
| 298 | static struct bchannel * | ||
| 299 | Sel_BCS(struct hfc_pci *hc, int channel) | ||
| 300 | { | ||
| 301 | if (test_bit(FLG_ACTIVE, &hc->bch[0].Flags) && | ||
| 302 | (hc->bch[0].nr & channel)) | ||
| 303 | return &hc->bch[0]; | ||
| 304 | else if (test_bit(FLG_ACTIVE, &hc->bch[1].Flags) && | ||
| 305 | (hc->bch[1].nr & channel)) | ||
| 306 | return &hc->bch[1]; | ||
| 307 | else | ||
| 308 | return NULL; | ||
| 309 | } | ||
| 310 | |||
| 311 | /* | ||
| 312 | * clear the desired B-channel rx fifo | ||
| 313 | */ | ||
| 314 | static void | ||
| 315 | hfcpci_clear_fifo_rx(struct hfc_pci *hc, int fifo) | ||
| 316 | { | ||
| 317 | u_char fifo_state; | ||
| 318 | struct bzfifo *bzr; | ||
| 319 | |||
| 320 | if (fifo) { | ||
| 321 | bzr = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2; | ||
| 322 | fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B2RX; | ||
| 323 | } else { | ||
| 324 | bzr = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1; | ||
| 325 | fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B1RX; | ||
| 326 | } | ||
| 327 | if (fifo_state) | ||
| 328 | hc->hw.fifo_en ^= fifo_state; | ||
| 329 | Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); | ||
| 330 | hc->hw.last_bfifo_cnt[fifo] = 0; | ||
| 331 | bzr->f1 = MAX_B_FRAMES; | ||
| 332 | bzr->f2 = bzr->f1; /* init F pointers to remain constant */ | ||
| 333 | bzr->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1); | ||
| 334 | bzr->za[MAX_B_FRAMES].z2 = cpu_to_le16( | ||
| 335 | le16_to_cpu(bzr->za[MAX_B_FRAMES].z1)); | ||
| 336 | if (fifo_state) | ||
| 337 | hc->hw.fifo_en |= fifo_state; | ||
| 338 | Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); | ||
| 339 | } | ||
| 340 | |||
| 341 | /* | ||
| 342 | * clear the desired B-channel tx fifo | ||
| 343 | */ | ||
| 344 | static void hfcpci_clear_fifo_tx(struct hfc_pci *hc, int fifo) | ||
| 345 | { | ||
| 346 | u_char fifo_state; | ||
| 347 | struct bzfifo *bzt; | ||
| 348 | |||
| 349 | if (fifo) { | ||
| 350 | bzt = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2; | ||
| 351 | fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B2TX; | ||
| 352 | } else { | ||
| 353 | bzt = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1; | ||
| 354 | fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B1TX; | ||
| 355 | } | ||
| 356 | if (fifo_state) | ||
| 357 | hc->hw.fifo_en ^= fifo_state; | ||
| 358 | Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); | ||
| 359 | if (hc->bch[fifo].debug & DEBUG_HW_BCHANNEL) | ||
| 360 | printk(KERN_DEBUG "hfcpci_clear_fifo_tx%d f1(%x) f2(%x) " | ||
| 361 | "z1(%x) z2(%x) state(%x)\n", | ||
| 362 | fifo, bzt->f1, bzt->f2, | ||
| 363 | le16_to_cpu(bzt->za[MAX_B_FRAMES].z1), | ||
| 364 | le16_to_cpu(bzt->za[MAX_B_FRAMES].z2), | ||
| 365 | fifo_state); | ||
| 366 | bzt->f2 = MAX_B_FRAMES; | ||
| 367 | bzt->f1 = bzt->f2; /* init F pointers to remain constant */ | ||
| 368 | bzt->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1); | ||
| 369 | bzt->za[MAX_B_FRAMES].z2 = cpu_to_le16( | ||
| 370 | le16_to_cpu(bzt->za[MAX_B_FRAMES].z1 - 1)); | ||
| 371 | if (fifo_state) | ||
| 372 | hc->hw.fifo_en |= fifo_state; | ||
| 373 | Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); | ||
| 374 | if (hc->bch[fifo].debug & DEBUG_HW_BCHANNEL) | ||
| 375 | printk(KERN_DEBUG | ||
| 376 | "hfcpci_clear_fifo_tx%d f1(%x) f2(%x) z1(%x) z2(%x)\n", | ||
| 377 | fifo, bzt->f1, bzt->f2, | ||
| 378 | le16_to_cpu(bzt->za[MAX_B_FRAMES].z1), | ||
| 379 | le16_to_cpu(bzt->za[MAX_B_FRAMES].z2)); | ||
| 380 | } | ||
| 381 | |||
| 382 | /* | ||
| 383 | * read a complete B-frame out of the buffer | ||
| 384 | */ | ||
| 385 | static void | ||
| 386 | hfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz, | ||
| 387 | u_char *bdata, int count) | ||
| 388 | { | ||
| 389 | u_char *ptr, *ptr1, new_f2; | ||
| 390 | int total, maxlen, new_z2; | ||
| 391 | struct zt *zp; | ||
| 392 | |||
| 393 | if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO)) | ||
| 394 | printk(KERN_DEBUG "hfcpci_empty_fifo\n"); | ||
| 395 | zp = &bz->za[bz->f2]; /* point to Z-Regs */ | ||
| 396 | new_z2 = le16_to_cpu(zp->z2) + count; /* new position in fifo */ | ||
| 397 | if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) | ||
| 398 | new_z2 -= B_FIFO_SIZE; /* buffer wrap */ | ||
| 399 | new_f2 = (bz->f2 + 1) & MAX_B_FRAMES; | ||
| 400 | if ((count > MAX_DATA_SIZE + 3) || (count < 4) || | ||
| 401 | (*(bdata + (le16_to_cpu(zp->z1) - B_SUB_VAL)))) { | ||
| 402 | if (bch->debug & DEBUG_HW) | ||
| 403 | printk(KERN_DEBUG "hfcpci_empty_fifo: incoming packet " | ||
| 404 | "invalid length %d or crc\n", count); | ||
| 405 | #ifdef ERROR_STATISTIC | ||
| 406 | bch->err_inv++; | ||
| 407 | #endif | ||
| 408 | bz->za[new_f2].z2 = cpu_to_le16(new_z2); | ||
| 409 | bz->f2 = new_f2; /* next buffer */ | ||
| 410 | } else { | ||
| 411 | bch->rx_skb = mI_alloc_skb(count - 3, GFP_ATOMIC); | ||
| 412 | if (!bch->rx_skb) { | ||
| 413 | printk(KERN_WARNING "HFCPCI: receive out of memory\n"); | ||
| 414 | return; | ||
| 415 | } | ||
| 416 | total = count; | ||
| 417 | count -= 3; | ||
| 418 | ptr = skb_put(bch->rx_skb, count); | ||
| 419 | |||
| 420 | if (le16_to_cpu(zp->z2) + count <= B_FIFO_SIZE + B_SUB_VAL) | ||
| 421 | maxlen = count; /* complete transfer */ | ||
| 422 | else | ||
| 423 | maxlen = B_FIFO_SIZE + B_SUB_VAL - | ||
| 424 | le16_to_cpu(zp->z2); /* maximum */ | ||
| 425 | |||
| 426 | ptr1 = bdata + (le16_to_cpu(zp->z2) - B_SUB_VAL); | ||
| 427 | /* start of data */ | ||
| 428 | memcpy(ptr, ptr1, maxlen); /* copy data */ | ||
| 429 | count -= maxlen; | ||
| 430 | |||
| 431 | if (count) { /* rest remaining */ | ||
| 432 | ptr += maxlen; | ||
| 433 | ptr1 = bdata; /* start of buffer */ | ||
| 434 | memcpy(ptr, ptr1, count); /* rest */ | ||
| 435 | } | ||
| 436 | bz->za[new_f2].z2 = cpu_to_le16(new_z2); | ||
| 437 | bz->f2 = new_f2; /* next buffer */ | ||
| 438 | recv_Bchannel(bch); | ||
| 439 | } | ||
| 440 | } | ||
| 441 | |||
| 442 | /* | ||
| 443 | * D-channel receive procedure | ||
| 444 | */ | ||
| 445 | static int | ||
| 446 | receive_dmsg(struct hfc_pci *hc) | ||
| 447 | { | ||
| 448 | struct dchannel *dch = &hc->dch; | ||
| 449 | int maxlen; | ||
| 450 | int rcnt, total; | ||
| 451 | int count = 5; | ||
| 452 | u_char *ptr, *ptr1; | ||
| 453 | struct dfifo *df; | ||
| 454 | struct zt *zp; | ||
| 455 | |||
| 456 | df = &((union fifo_area *)(hc->hw.fifos))->d_chan.d_rx; | ||
| 457 | while (((df->f1 & D_FREG_MASK) != (df->f2 & D_FREG_MASK)) && count--) { | ||
| 458 | zp = &df->za[df->f2 & D_FREG_MASK]; | ||
| 459 | rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2); | ||
| 460 | if (rcnt < 0) | ||
| 461 | rcnt += D_FIFO_SIZE; | ||
| 462 | rcnt++; | ||
| 463 | if (dch->debug & DEBUG_HW_DCHANNEL) | ||
| 464 | printk(KERN_DEBUG | ||
| 465 | "hfcpci recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)\n", | ||
| 466 | df->f1, df->f2, | ||
| 467 | le16_to_cpu(zp->z1), | ||
| 468 | le16_to_cpu(zp->z2), | ||
| 469 | rcnt); | ||
| 470 | |||
| 471 | if ((rcnt > MAX_DFRAME_LEN + 3) || (rcnt < 4) || | ||
| 472 | (df->data[le16_to_cpu(zp->z1)])) { | ||
| 473 | if (dch->debug & DEBUG_HW) | ||
| 474 | printk(KERN_DEBUG | ||
| 475 | "empty_fifo hfcpci paket inv. len " | ||
| 476 | "%d or crc %d\n", | ||
| 477 | rcnt, | ||
| 478 | df->data[le16_to_cpu(zp->z1)]); | ||
| 479 | #ifdef ERROR_STATISTIC | ||
| 480 | cs->err_rx++; | ||
| 481 | #endif | ||
| 482 | df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | | ||
| 483 | (MAX_D_FRAMES + 1); /* next buffer */ | ||
| 484 | df->za[df->f2 & D_FREG_MASK].z2 = | ||
| 485 | cpu_to_le16((zp->z2 + rcnt) & (D_FIFO_SIZE - 1)); | ||
| 486 | } else { | ||
| 487 | dch->rx_skb = mI_alloc_skb(rcnt - 3, GFP_ATOMIC); | ||
| 488 | if (!dch->rx_skb) { | ||
| 489 | printk(KERN_WARNING | ||
| 490 | "HFC-PCI: D receive out of memory\n"); | ||
| 491 | break; | ||
| 492 | } | ||
| 493 | total = rcnt; | ||
| 494 | rcnt -= 3; | ||
| 495 | ptr = skb_put(dch->rx_skb, rcnt); | ||
| 496 | |||
| 497 | if (le16_to_cpu(zp->z2) + rcnt <= D_FIFO_SIZE) | ||
| 498 | maxlen = rcnt; /* complete transfer */ | ||
| 499 | else | ||
| 500 | maxlen = D_FIFO_SIZE - le16_to_cpu(zp->z2); | ||
| 501 | /* maximum */ | ||
| 502 | |||
| 503 | ptr1 = df->data + le16_to_cpu(zp->z2); | ||
| 504 | /* start of data */ | ||
| 505 | memcpy(ptr, ptr1, maxlen); /* copy data */ | ||
| 506 | rcnt -= maxlen; | ||
| 507 | |||
| 508 | if (rcnt) { /* rest remaining */ | ||
| 509 | ptr += maxlen; | ||
| 510 | ptr1 = df->data; /* start of buffer */ | ||
| 511 | memcpy(ptr, ptr1, rcnt); /* rest */ | ||
| 512 | } | ||
| 513 | df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | | ||
| 514 | (MAX_D_FRAMES + 1); /* next buffer */ | ||
| 515 | df->za[df->f2 & D_FREG_MASK].z2 = cpu_to_le16(( | ||
| 516 | le16_to_cpu(zp->z2) + total) & (D_FIFO_SIZE - 1)); | ||
| 517 | recv_Dchannel(dch); | ||
| 518 | } | ||
| 519 | } | ||
| 520 | return 1; | ||
| 521 | } | ||
| 522 | |||
| 523 | /* | ||
| 524 | * check for transparent receive data and read max one threshold size if avail | ||
| 525 | */ | ||
| 526 | int | ||
| 527 | hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata) | ||
| 528 | { | ||
| 529 | unsigned short *z1r, *z2r; | ||
| 530 | int new_z2, fcnt, maxlen; | ||
| 531 | u_char *ptr, *ptr1; | ||
| 532 | |||
| 533 | z1r = &bz->za[MAX_B_FRAMES].z1; /* pointer to z reg */ | ||
| 534 | z2r = z1r + 1; | ||
| 535 | |||
| 536 | fcnt = le16_to_cpu(*z1r) - le16_to_cpu(*z2r); | ||
| 537 | if (!fcnt) | ||
| 538 | return 0; /* no data avail */ | ||
| 539 | |||
| 540 | if (fcnt <= 0) | ||
| 541 | fcnt += B_FIFO_SIZE; /* bytes actually buffered */ | ||
| 542 | if (fcnt > HFCPCI_BTRANS_THRESHOLD) | ||
| 543 | fcnt = HFCPCI_BTRANS_THRESHOLD; /* limit size */ | ||
| 544 | |||
| 545 | new_z2 = le16_to_cpu(*z2r) + fcnt; /* new position in fifo */ | ||
| 546 | if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) | ||
| 547 | new_z2 -= B_FIFO_SIZE; /* buffer wrap */ | ||
| 548 | |||
| 549 | bch->rx_skb = mI_alloc_skb(fcnt, GFP_ATOMIC); | ||
| 550 | if (bch->rx_skb) { | ||
| 551 | ptr = skb_put(bch->rx_skb, fcnt); | ||
| 552 | if (le16_to_cpu(*z2r) + fcnt <= B_FIFO_SIZE + B_SUB_VAL) | ||
| 553 | maxlen = fcnt; /* complete transfer */ | ||
| 554 | else | ||
| 555 | maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(*z2r); | ||
| 556 | /* maximum */ | ||
| 557 | |||
| 558 | ptr1 = bdata + (le16_to_cpu(*z2r) - B_SUB_VAL); | ||
| 559 | /* start of data */ | ||
| 560 | memcpy(ptr, ptr1, maxlen); /* copy data */ | ||
| 561 | fcnt -= maxlen; | ||
| 562 | |||
| 563 | if (fcnt) { /* rest remaining */ | ||
| 564 | ptr += maxlen; | ||
| 565 | ptr1 = bdata; /* start of buffer */ | ||
| 566 | memcpy(ptr, ptr1, fcnt); /* rest */ | ||
| 567 | } | ||
| 568 | recv_Bchannel(bch); | ||
| 569 | } else | ||
| 570 | printk(KERN_WARNING "HFCPCI: receive out of memory\n"); | ||
| 571 | |||
| 572 | *z2r = cpu_to_le16(new_z2); /* new position */ | ||
| 573 | return 1; | ||
| 574 | } | ||
| 575 | |||
| 576 | /* | ||
| 577 | * B-channel main receive routine | ||
| 578 | */ | ||
| 579 | void | ||
| 580 | main_rec_hfcpci(struct bchannel *bch) | ||
| 581 | { | ||
| 582 | struct hfc_pci *hc = bch->hw; | ||
| 583 | int rcnt, real_fifo; | ||
| 584 | int receive, count = 5; | ||
| 585 | struct bzfifo *bz; | ||
| 586 | u_char *bdata; | ||
| 587 | struct zt *zp; | ||
| 588 | |||
| 589 | |||
| 590 | if ((bch->nr & 2) && (!hc->hw.bswapped)) { | ||
| 591 | bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2; | ||
| 592 | bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b2; | ||
| 593 | real_fifo = 1; | ||
| 594 | } else { | ||
| 595 | bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1; | ||
| 596 | bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b1; | ||
| 597 | real_fifo = 0; | ||
| 598 | } | ||
| 599 | Begin: | ||
| 600 | count--; | ||
| 601 | if (bz->f1 != bz->f2) { | ||
| 602 | if (bch->debug & DEBUG_HW_BCHANNEL) | ||
| 603 | printk(KERN_DEBUG "hfcpci rec ch(%x) f1(%d) f2(%d)\n", | ||
| 604 | bch->nr, bz->f1, bz->f2); | ||
| 605 | zp = &bz->za[bz->f2]; | ||
| 606 | |||
| 607 | rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2); | ||
| 608 | if (rcnt < 0) | ||
| 609 | rcnt += B_FIFO_SIZE; | ||
| 610 | rcnt++; | ||
| 611 | if (bch->debug & DEBUG_HW_BCHANNEL) | ||
| 612 | printk(KERN_DEBUG | ||
| 613 | "hfcpci rec ch(%x) z1(%x) z2(%x) cnt(%d)\n", | ||
| 614 | bch->nr, le16_to_cpu(zp->z1), | ||
| 615 | le16_to_cpu(zp->z2), rcnt); | ||
| 616 | hfcpci_empty_bfifo(bch, bz, bdata, rcnt); | ||
| 617 | rcnt = bz->f1 - bz->f2; | ||
| 618 | if (rcnt < 0) | ||
| 619 | rcnt += MAX_B_FRAMES + 1; | ||
| 620 | if (hc->hw.last_bfifo_cnt[real_fifo] > rcnt + 1) { | ||
| 621 | rcnt = 0; | ||
| 622 | hfcpci_clear_fifo_rx(hc, real_fifo); | ||
| 623 | } | ||
| 624 | hc->hw.last_bfifo_cnt[real_fifo] = rcnt; | ||
| 625 | if (rcnt > 1) | ||
| 626 | receive = 1; | ||
| 627 | else | ||
| 628 | receive = 0; | ||
| 629 | } else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
| 630 | receive = hfcpci_empty_fifo_trans(bch, bz, bdata); | ||
| 631 | else | ||
| 632 | receive = 0; | ||
| 633 | if (count && receive) | ||
| 634 | goto Begin; | ||
| 635 | |||
| 636 | } | ||
| 637 | |||
| 638 | /* | ||
| 639 | * D-channel send routine | ||
| 640 | */ | ||
| 641 | static void | ||
| 642 | hfcpci_fill_dfifo(struct hfc_pci *hc) | ||
| 643 | { | ||
| 644 | struct dchannel *dch = &hc->dch; | ||
| 645 | int fcnt; | ||
| 646 | int count, new_z1, maxlen; | ||
| 647 | struct dfifo *df; | ||
| 648 | u_char *src, *dst, new_f1; | ||
| 649 | |||
| 650 | if ((dch->debug & DEBUG_HW_DCHANNEL) && !(dch->debug & DEBUG_HW_DFIFO)) | ||
| 651 | printk(KERN_DEBUG "%s\n", __func__); | ||
| 652 | |||
| 653 | if (!dch->tx_skb) | ||
| 654 | return; | ||
| 655 | count = dch->tx_skb->len - dch->tx_idx; | ||
| 656 | if (count <= 0) | ||
| 657 | return; | ||
| 658 | df = &((union fifo_area *) (hc->hw.fifos))->d_chan.d_tx; | ||
| 659 | |||
| 660 | if (dch->debug & DEBUG_HW_DFIFO) | ||
| 661 | printk(KERN_DEBUG "%s:f1(%d) f2(%d) z1(f1)(%x)\n", __func__, | ||
| 662 | df->f1, df->f2, | ||
| 663 | le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1)); | ||
| 664 | fcnt = df->f1 - df->f2; /* frame count actually buffered */ | ||
| 665 | if (fcnt < 0) | ||
| 666 | fcnt += (MAX_D_FRAMES + 1); /* if wrap around */ | ||
| 667 | if (fcnt > (MAX_D_FRAMES - 1)) { | ||
| 668 | if (dch->debug & DEBUG_HW_DCHANNEL) | ||
| 669 | printk(KERN_DEBUG | ||
| 670 | "hfcpci_fill_Dfifo more as 14 frames\n"); | ||
| 671 | #ifdef ERROR_STATISTIC | ||
| 672 | cs->err_tx++; | ||
| 673 | #endif | ||
| 674 | return; | ||
| 675 | } | ||
| 676 | /* now determine free bytes in FIFO buffer */ | ||
| 677 | maxlen = le16_to_cpu(df->za[df->f2 & D_FREG_MASK].z2) - | ||
| 678 | le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) - 1; | ||
| 679 | if (maxlen <= 0) | ||
| 680 | maxlen += D_FIFO_SIZE; /* count now contains available bytes */ | ||
| 681 | |||
| 682 | if (dch->debug & DEBUG_HW_DCHANNEL) | ||
| 683 | printk(KERN_DEBUG "hfcpci_fill_Dfifo count(%d/%d)\n", | ||
| 684 | count, maxlen); | ||
| 685 | if (count > maxlen) { | ||
| 686 | if (dch->debug & DEBUG_HW_DCHANNEL) | ||
| 687 | printk(KERN_DEBUG "hfcpci_fill_Dfifo no fifo mem\n"); | ||
| 688 | return; | ||
| 689 | } | ||
| 690 | new_z1 = (le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) + count) & | ||
| 691 | (D_FIFO_SIZE - 1); | ||
| 692 | new_f1 = ((df->f1 + 1) & D_FREG_MASK) | (D_FREG_MASK + 1); | ||
| 693 | src = dch->tx_skb->data + dch->tx_idx; /* source pointer */ | ||
| 694 | dst = df->data + le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1); | ||
| 695 | maxlen = D_FIFO_SIZE - le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1); | ||
| 696 | /* end fifo */ | ||
| 697 | if (maxlen > count) | ||
| 698 | maxlen = count; /* limit size */ | ||
| 699 | memcpy(dst, src, maxlen); /* first copy */ | ||
| 700 | |||
| 701 | count -= maxlen; /* remaining bytes */ | ||
| 702 | if (count) { | ||
| 703 | dst = df->data; /* start of buffer */ | ||
| 704 | src += maxlen; /* new position */ | ||
| 705 | memcpy(dst, src, count); | ||
| 706 | } | ||
| 707 | df->za[new_f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1); | ||
| 708 | /* for next buffer */ | ||
| 709 | df->za[df->f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1); | ||
| 710 | /* new pos actual buffer */ | ||
| 711 | df->f1 = new_f1; /* next frame */ | ||
| 712 | dch->tx_idx = dch->tx_skb->len; | ||
| 713 | } | ||
| 714 | |||
| 715 | /* | ||
| 716 | * B-channel send routine | ||
| 717 | */ | ||
| 718 | static void | ||
| 719 | hfcpci_fill_fifo(struct bchannel *bch) | ||
| 720 | { | ||
| 721 | struct hfc_pci *hc = bch->hw; | ||
| 722 | int maxlen, fcnt; | ||
| 723 | int count, new_z1; | ||
| 724 | struct bzfifo *bz; | ||
| 725 | u_char *bdata; | ||
| 726 | u_char new_f1, *src, *dst; | ||
| 727 | unsigned short *z1t, *z2t; | ||
| 728 | |||
| 729 | if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO)) | ||
| 730 | printk(KERN_DEBUG "%s\n", __func__); | ||
| 731 | if ((!bch->tx_skb) || bch->tx_skb->len <= 0) | ||
| 732 | return; | ||
| 733 | count = bch->tx_skb->len - bch->tx_idx; | ||
| 734 | if ((bch->nr & 2) && (!hc->hw.bswapped)) { | ||
| 735 | bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2; | ||
| 736 | bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.txdat_b2; | ||
| 737 | } else { | ||
| 738 | bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1; | ||
| 739 | bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.txdat_b1; | ||
| 740 | } | ||
| 741 | |||
| 742 | if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { | ||
| 743 | z1t = &bz->za[MAX_B_FRAMES].z1; | ||
| 744 | z2t = z1t + 1; | ||
| 745 | if (bch->debug & DEBUG_HW_BCHANNEL) | ||
| 746 | printk(KERN_DEBUG "hfcpci_fill_fifo_trans ch(%x) " | ||
| 747 | "cnt(%d) z1(%x) z2(%x)\n", bch->nr, count, | ||
| 748 | le16_to_cpu(*z1t), le16_to_cpu(*z2t)); | ||
| 749 | fcnt = le16_to_cpu(*z2t) - le16_to_cpu(*z1t); | ||
| 750 | if (fcnt <= 0) | ||
| 751 | fcnt += B_FIFO_SIZE; | ||
| 752 | /* fcnt contains available bytes in fifo */ | ||
| 753 | fcnt = B_FIFO_SIZE - fcnt; | ||
| 754 | /* remaining bytes to send (bytes in fifo) */ | ||
| 755 | next_t_frame: | ||
| 756 | count = bch->tx_skb->len - bch->tx_idx; | ||
| 757 | /* maximum fill shall be HFCPCI_BTRANS_MAX */ | ||
| 758 | if (count > HFCPCI_BTRANS_MAX - fcnt) | ||
| 759 | count = HFCPCI_BTRANS_MAX - fcnt; | ||
| 760 | if (count <= 0) | ||
| 761 | return; | ||
| 762 | /* data is suitable for fifo */ | ||
| 763 | new_z1 = le16_to_cpu(*z1t) + count; | ||
| 764 | /* new buffer Position */ | ||
| 765 | if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) | ||
| 766 | new_z1 -= B_FIFO_SIZE; /* buffer wrap */ | ||
| 767 | src = bch->tx_skb->data + bch->tx_idx; | ||
| 768 | /* source pointer */ | ||
| 769 | dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL); | ||
| 770 | maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t); | ||
| 771 | /* end of fifo */ | ||
| 772 | if (bch->debug & DEBUG_HW_BFIFO) | ||
| 773 | printk(KERN_DEBUG "hfcpci_FFt fcnt(%d) " | ||
| 774 | "maxl(%d) nz1(%x) dst(%p)\n", | ||
| 775 | fcnt, maxlen, new_z1, dst); | ||
| 776 | fcnt += count; | ||
| 777 | bch->tx_idx += count; | ||
| 778 | if (maxlen > count) | ||
| 779 | maxlen = count; /* limit size */ | ||
| 780 | memcpy(dst, src, maxlen); /* first copy */ | ||
| 781 | count -= maxlen; /* remaining bytes */ | ||
| 782 | if (count) { | ||
| 783 | dst = bdata; /* start of buffer */ | ||
| 784 | src += maxlen; /* new position */ | ||
| 785 | memcpy(dst, src, count); | ||
| 786 | } | ||
| 787 | *z1t = cpu_to_le16(new_z1); /* now send data */ | ||
| 788 | if (bch->tx_idx < bch->tx_skb->len) | ||
| 789 | return; | ||
| 790 | /* send confirm, on trans, free on hdlc. */ | ||
| 791 | if (test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
| 792 | confirm_Bsend(bch); | ||
| 793 | dev_kfree_skb(bch->tx_skb); | ||
| 794 | if (get_next_bframe(bch)) | ||
| 795 | goto next_t_frame; | ||
| 796 | return; | ||
| 797 | } | ||
| 798 | if (bch->debug & DEBUG_HW_BCHANNEL) | ||
| 799 | printk(KERN_DEBUG | ||
| 800 | "%s: ch(%x) f1(%d) f2(%d) z1(f1)(%x)\n", | ||
| 801 | __func__, bch->nr, bz->f1, bz->f2, | ||
| 802 | bz->za[bz->f1].z1); | ||
| 803 | fcnt = bz->f1 - bz->f2; /* frame count actually buffered */ | ||
| 804 | if (fcnt < 0) | ||
| 805 | fcnt += (MAX_B_FRAMES + 1); /* if wrap around */ | ||
| 806 | if (fcnt > (MAX_B_FRAMES - 1)) { | ||
| 807 | if (bch->debug & DEBUG_HW_BCHANNEL) | ||
| 808 | printk(KERN_DEBUG | ||
| 809 | "hfcpci_fill_Bfifo more as 14 frames\n"); | ||
| 810 | return; | ||
| 811 | } | ||
| 812 | /* now determine free bytes in FIFO buffer */ | ||
| 813 | maxlen = le16_to_cpu(bz->za[bz->f2].z2) - | ||
| 814 | le16_to_cpu(bz->za[bz->f1].z1) - 1; | ||
| 815 | if (maxlen <= 0) | ||
| 816 | maxlen += B_FIFO_SIZE; /* count now contains available bytes */ | ||
| 817 | |||
| 818 | if (bch->debug & DEBUG_HW_BCHANNEL) | ||
| 819 | printk(KERN_DEBUG "hfcpci_fill_fifo ch(%x) count(%d/%d)\n", | ||
| 820 | bch->nr, count, maxlen); | ||
| 821 | |||
| 822 | if (maxlen < count) { | ||
| 823 | if (bch->debug & DEBUG_HW_BCHANNEL) | ||
| 824 | printk(KERN_DEBUG "hfcpci_fill_fifo no fifo mem\n"); | ||
| 825 | return; | ||
| 826 | } | ||
| 827 | new_z1 = le16_to_cpu(bz->za[bz->f1].z1) + count; | ||
| 828 | /* new buffer Position */ | ||
| 829 | if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) | ||
| 830 | new_z1 -= B_FIFO_SIZE; /* buffer wrap */ | ||
| 831 | |||
| 832 | new_f1 = ((bz->f1 + 1) & MAX_B_FRAMES); | ||
| 833 | src = bch->tx_skb->data + bch->tx_idx; /* source pointer */ | ||
| 834 | dst = bdata + (le16_to_cpu(bz->za[bz->f1].z1) - B_SUB_VAL); | ||
| 835 | maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(bz->za[bz->f1].z1); | ||
| 836 | /* end fifo */ | ||
| 837 | if (maxlen > count) | ||
| 838 | maxlen = count; /* limit size */ | ||
| 839 | memcpy(dst, src, maxlen); /* first copy */ | ||
| 840 | |||
| 841 | count -= maxlen; /* remaining bytes */ | ||
| 842 | if (count) { | ||
| 843 | dst = bdata; /* start of buffer */ | ||
| 844 | src += maxlen; /* new position */ | ||
| 845 | memcpy(dst, src, count); | ||
| 846 | } | ||
| 847 | bz->za[new_f1].z1 = cpu_to_le16(new_z1); /* for next buffer */ | ||
| 848 | bz->f1 = new_f1; /* next frame */ | ||
| 849 | dev_kfree_skb(bch->tx_skb); | ||
| 850 | get_next_bframe(bch); | ||
| 851 | } | ||
| 852 | |||
| 853 | |||
| 854 | |||
| 855 | /* | ||
| 856 | * handle L1 state changes TE | ||
| 857 | */ | ||
| 858 | |||
| 859 | static void | ||
| 860 | ph_state_te(struct dchannel *dch) | ||
| 861 | { | ||
| 862 | if (dch->debug) | ||
| 863 | printk(KERN_DEBUG "%s: TE newstate %x\n", | ||
| 864 | __func__, dch->state); | ||
| 865 | switch (dch->state) { | ||
| 866 | case 0: | ||
| 867 | l1_event(dch->l1, HW_RESET_IND); | ||
| 868 | break; | ||
| 869 | case 3: | ||
| 870 | l1_event(dch->l1, HW_DEACT_IND); | ||
| 871 | break; | ||
| 872 | case 5: | ||
| 873 | case 8: | ||
| 874 | l1_event(dch->l1, ANYSIGNAL); | ||
| 875 | break; | ||
| 876 | case 6: | ||
| 877 | l1_event(dch->l1, INFO2); | ||
| 878 | break; | ||
| 879 | case 7: | ||
| 880 | l1_event(dch->l1, INFO4_P8); | ||
| 881 | break; | ||
| 882 | } | ||
| 883 | } | ||
| 884 | |||
| 885 | /* | ||
| 886 | * handle L1 state changes NT | ||
| 887 | */ | ||
| 888 | |||
| 889 | static void | ||
| 890 | handle_nt_timer3(struct dchannel *dch) { | ||
| 891 | struct hfc_pci *hc = dch->hw; | ||
| 892 | |||
| 893 | test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); | ||
| 894 | hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; | ||
| 895 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
| 896 | hc->hw.nt_timer = 0; | ||
| 897 | test_and_set_bit(FLG_ACTIVE, &dch->Flags); | ||
| 898 | if (test_bit(HFC_CFG_MASTER, &hc->cfg)) | ||
| 899 | hc->hw.mst_m |= HFCPCI_MASTER; | ||
| 900 | Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); | ||
| 901 | _queue_data(&dch->dev.D, PH_ACTIVATE_IND, | ||
| 902 | MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); | ||
| 903 | } | ||
| 904 | |||
| 905 | static void | ||
| 906 | ph_state_nt(struct dchannel *dch) | ||
| 907 | { | ||
| 908 | struct hfc_pci *hc = dch->hw; | ||
| 909 | |||
| 910 | if (dch->debug) | ||
| 911 | printk(KERN_DEBUG "%s: NT newstate %x\n", | ||
| 912 | __func__, dch->state); | ||
| 913 | switch (dch->state) { | ||
| 914 | case 2: | ||
| 915 | if (hc->hw.nt_timer < 0) { | ||
| 916 | hc->hw.nt_timer = 0; | ||
| 917 | test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); | ||
| 918 | test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags); | ||
| 919 | hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; | ||
| 920 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
| 921 | /* Clear already pending ints */ | ||
| 922 | if (Read_hfc(hc, HFCPCI_INT_S1)); | ||
| 923 | Write_hfc(hc, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE); | ||
| 924 | udelay(10); | ||
| 925 | Write_hfc(hc, HFCPCI_STATES, 4); | ||
| 926 | dch->state = 4; | ||
| 927 | } else if (hc->hw.nt_timer == 0) { | ||
| 928 | hc->hw.int_m1 |= HFCPCI_INTS_TIMER; | ||
| 929 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
| 930 | hc->hw.nt_timer = NT_T1_COUNT; | ||
| 931 | hc->hw.ctmt &= ~HFCPCI_AUTO_TIMER; | ||
| 932 | hc->hw.ctmt |= HFCPCI_TIM3_125; | ||
| 933 | Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | | ||
| 934 | HFCPCI_CLTIMER); | ||
| 935 | test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); | ||
| 936 | test_and_set_bit(FLG_HFC_TIMER_T1, &dch->Flags); | ||
| 937 | /* allow G2 -> G3 transition */ | ||
| 938 | Write_hfc(hc, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3); | ||
| 939 | } else { | ||
| 940 | Write_hfc(hc, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3); | ||
| 941 | } | ||
| 942 | break; | ||
| 943 | case 1: | ||
| 944 | hc->hw.nt_timer = 0; | ||
| 945 | test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); | ||
| 946 | test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags); | ||
| 947 | hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; | ||
| 948 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
| 949 | test_and_clear_bit(FLG_ACTIVE, &dch->Flags); | ||
| 950 | hc->hw.mst_m &= ~HFCPCI_MASTER; | ||
| 951 | Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); | ||
| 952 | test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); | ||
| 953 | _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, | ||
| 954 | MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); | ||
| 955 | break; | ||
| 956 | case 4: | ||
| 957 | hc->hw.nt_timer = 0; | ||
| 958 | test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags); | ||
| 959 | test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags); | ||
| 960 | hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; | ||
| 961 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
| 962 | break; | ||
| 963 | case 3: | ||
| 964 | if (!test_and_set_bit(FLG_HFC_TIMER_T3, &dch->Flags)) { | ||
| 965 | if (!test_and_clear_bit(FLG_L2_ACTIVATED, | ||
| 966 | &dch->Flags)) { | ||
| 967 | handle_nt_timer3(dch); | ||
| 968 | break; | ||
| 969 | } | ||
| 970 | test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags); | ||
| 971 | hc->hw.int_m1 |= HFCPCI_INTS_TIMER; | ||
| 972 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
| 973 | hc->hw.nt_timer = NT_T3_COUNT; | ||
| 974 | hc->hw.ctmt &= ~HFCPCI_AUTO_TIMER; | ||
| 975 | hc->hw.ctmt |= HFCPCI_TIM3_125; | ||
| 976 | Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | | ||
| 977 | HFCPCI_CLTIMER); | ||
| 978 | } | ||
| 979 | break; | ||
| 980 | } | ||
| 981 | } | ||
| 982 | |||
| 983 | static void | ||
| 984 | ph_state(struct dchannel *dch) | ||
| 985 | { | ||
| 986 | struct hfc_pci *hc = dch->hw; | ||
| 987 | |||
| 988 | if (hc->hw.protocol == ISDN_P_NT_S0) { | ||
| 989 | if (test_bit(FLG_HFC_TIMER_T3, &dch->Flags) && | ||
| 990 | hc->hw.nt_timer < 0) | ||
| 991 | handle_nt_timer3(dch); | ||
| 992 | else | ||
| 993 | ph_state_nt(dch); | ||
| 994 | } else | ||
| 995 | ph_state_te(dch); | ||
| 996 | } | ||
| 997 | |||
| 998 | /* | ||
| 999 | * Layer 1 callback function | ||
| 1000 | */ | ||
| 1001 | static int | ||
| 1002 | hfc_l1callback(struct dchannel *dch, u_int cmd) | ||
| 1003 | { | ||
| 1004 | struct hfc_pci *hc = dch->hw; | ||
| 1005 | |||
| 1006 | switch (cmd) { | ||
| 1007 | case INFO3_P8: | ||
| 1008 | case INFO3_P10: | ||
| 1009 | if (test_bit(HFC_CFG_MASTER, &hc->cfg)) | ||
| 1010 | hc->hw.mst_m |= HFCPCI_MASTER; | ||
| 1011 | Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); | ||
| 1012 | break; | ||
| 1013 | case HW_RESET_REQ: | ||
| 1014 | Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3); | ||
| 1015 | /* HFC ST 3 */ | ||
| 1016 | udelay(6); | ||
| 1017 | Write_hfc(hc, HFCPCI_STATES, 3); /* HFC ST 2 */ | ||
| 1018 | if (test_bit(HFC_CFG_MASTER, &hc->cfg)) | ||
| 1019 | hc->hw.mst_m |= HFCPCI_MASTER; | ||
| 1020 | Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); | ||
| 1021 | Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | | ||
| 1022 | HFCPCI_DO_ACTION); | ||
| 1023 | l1_event(dch->l1, HW_POWERUP_IND); | ||
| 1024 | break; | ||
| 1025 | case HW_DEACT_REQ: | ||
| 1026 | hc->hw.mst_m &= ~HFCPCI_MASTER; | ||
| 1027 | Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); | ||
| 1028 | skb_queue_purge(&dch->squeue); | ||
| 1029 | if (dch->tx_skb) { | ||
| 1030 | dev_kfree_skb(dch->tx_skb); | ||
| 1031 | dch->tx_skb = NULL; | ||
| 1032 | } | ||
| 1033 | dch->tx_idx = 0; | ||
| 1034 | if (dch->rx_skb) { | ||
| 1035 | dev_kfree_skb(dch->rx_skb); | ||
| 1036 | dch->rx_skb = NULL; | ||
| 1037 | } | ||
| 1038 | test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); | ||
| 1039 | if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) | ||
| 1040 | del_timer(&dch->timer); | ||
| 1041 | break; | ||
| 1042 | case HW_POWERUP_REQ: | ||
| 1043 | Write_hfc(hc, HFCPCI_STATES, HFCPCI_DO_ACTION); | ||
| 1044 | break; | ||
| 1045 | case PH_ACTIVATE_IND: | ||
| 1046 | test_and_set_bit(FLG_ACTIVE, &dch->Flags); | ||
| 1047 | _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, | ||
| 1048 | GFP_ATOMIC); | ||
| 1049 | break; | ||
| 1050 | case PH_DEACTIVATE_IND: | ||
| 1051 | test_and_clear_bit(FLG_ACTIVE, &dch->Flags); | ||
| 1052 | _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, | ||
| 1053 | GFP_ATOMIC); | ||
| 1054 | break; | ||
| 1055 | default: | ||
| 1056 | if (dch->debug & DEBUG_HW) | ||
| 1057 | printk(KERN_DEBUG "%s: unknown command %x\n", | ||
| 1058 | __func__, cmd); | ||
| 1059 | return -1; | ||
| 1060 | } | ||
| 1061 | return 0; | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | /* | ||
| 1065 | * Interrupt handler | ||
| 1066 | */ | ||
| 1067 | static inline void | ||
| 1068 | tx_birq(struct bchannel *bch) | ||
| 1069 | { | ||
| 1070 | if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len) | ||
| 1071 | hfcpci_fill_fifo(bch); | ||
| 1072 | else { | ||
| 1073 | if (bch->tx_skb) | ||
| 1074 | dev_kfree_skb(bch->tx_skb); | ||
| 1075 | if (get_next_bframe(bch)) | ||
| 1076 | hfcpci_fill_fifo(bch); | ||
| 1077 | } | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | static inline void | ||
| 1081 | tx_dirq(struct dchannel *dch) | ||
| 1082 | { | ||
| 1083 | if (dch->tx_skb && dch->tx_idx < dch->tx_skb->len) | ||
| 1084 | hfcpci_fill_dfifo(dch->hw); | ||
| 1085 | else { | ||
| 1086 | if (dch->tx_skb) | ||
| 1087 | dev_kfree_skb(dch->tx_skb); | ||
| 1088 | if (get_next_dframe(dch)) | ||
| 1089 | hfcpci_fill_dfifo(dch->hw); | ||
| 1090 | } | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | static irqreturn_t | ||
| 1094 | hfcpci_int(int intno, void *dev_id) | ||
| 1095 | { | ||
| 1096 | struct hfc_pci *hc = dev_id; | ||
| 1097 | u_char exval; | ||
| 1098 | struct bchannel *bch; | ||
| 1099 | u_char val, stat; | ||
| 1100 | |||
| 1101 | spin_lock(&hc->lock); | ||
| 1102 | if (!(hc->hw.int_m2 & 0x08)) { | ||
| 1103 | spin_unlock(&hc->lock); | ||
| 1104 | return IRQ_NONE; /* not initialised */ | ||
| 1105 | } | ||
| 1106 | stat = Read_hfc(hc, HFCPCI_STATUS); | ||
| 1107 | if (HFCPCI_ANYINT & stat) { | ||
| 1108 | val = Read_hfc(hc, HFCPCI_INT_S1); | ||
| 1109 | if (hc->dch.debug & DEBUG_HW_DCHANNEL) | ||
| 1110 | printk(KERN_DEBUG | ||
| 1111 | "HFC-PCI: stat(%02x) s1(%02x)\n", stat, val); | ||
| 1112 | } else { | ||
| 1113 | /* shared */ | ||
| 1114 | spin_unlock(&hc->lock); | ||
| 1115 | return IRQ_NONE; | ||
| 1116 | } | ||
| 1117 | hc->irqcnt++; | ||
| 1118 | |||
| 1119 | if (hc->dch.debug & DEBUG_HW_DCHANNEL) | ||
| 1120 | printk(KERN_DEBUG "HFC-PCI irq %x\n", val); | ||
| 1121 | val &= hc->hw.int_m1; | ||
| 1122 | if (val & 0x40) { /* state machine irq */ | ||
| 1123 | exval = Read_hfc(hc, HFCPCI_STATES) & 0xf; | ||
| 1124 | if (hc->dch.debug & DEBUG_HW_DCHANNEL) | ||
| 1125 | printk(KERN_DEBUG "ph_state chg %d->%d\n", | ||
| 1126 | hc->dch.state, exval); | ||
| 1127 | hc->dch.state = exval; | ||
| 1128 | schedule_event(&hc->dch, FLG_PHCHANGE); | ||
| 1129 | val &= ~0x40; | ||
| 1130 | } | ||
| 1131 | if (val & 0x80) { /* timer irq */ | ||
| 1132 | if (hc->hw.protocol == ISDN_P_NT_S0) { | ||
| 1133 | if ((--hc->hw.nt_timer) < 0) | ||
| 1134 | schedule_event(&hc->dch, FLG_PHCHANGE); | ||
| 1135 | } | ||
| 1136 | val &= ~0x80; | ||
| 1137 | Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER); | ||
| 1138 | } | ||
| 1139 | if (val & 0x08) { | ||
| 1140 | bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); | ||
| 1141 | if (bch) | ||
| 1142 | main_rec_hfcpci(bch); | ||
| 1143 | else if (hc->dch.debug) | ||
| 1144 | printk(KERN_DEBUG "hfcpci spurious 0x08 IRQ\n"); | ||
| 1145 | } | ||
| 1146 | if (val & 0x10) { | ||
| 1147 | bch = Sel_BCS(hc, 2); | ||
| 1148 | if (bch) | ||
| 1149 | main_rec_hfcpci(bch); | ||
| 1150 | else if (hc->dch.debug) | ||
| 1151 | printk(KERN_DEBUG "hfcpci spurious 0x10 IRQ\n"); | ||
| 1152 | } | ||
| 1153 | if (val & 0x01) { | ||
| 1154 | bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); | ||
| 1155 | if (bch) | ||
| 1156 | tx_birq(bch); | ||
| 1157 | else if (hc->dch.debug) | ||
| 1158 | printk(KERN_DEBUG "hfcpci spurious 0x01 IRQ\n"); | ||
| 1159 | } | ||
| 1160 | if (val & 0x02) { | ||
| 1161 | bch = Sel_BCS(hc, 2); | ||
| 1162 | if (bch) | ||
| 1163 | tx_birq(bch); | ||
| 1164 | else if (hc->dch.debug) | ||
| 1165 | printk(KERN_DEBUG "hfcpci spurious 0x02 IRQ\n"); | ||
| 1166 | } | ||
| 1167 | if (val & 0x20) | ||
| 1168 | receive_dmsg(hc); | ||
| 1169 | if (val & 0x04) { /* dframe transmitted */ | ||
| 1170 | if (test_and_clear_bit(FLG_BUSY_TIMER, &hc->dch.Flags)) | ||
| 1171 | del_timer(&hc->dch.timer); | ||
| 1172 | tx_dirq(&hc->dch); | ||
| 1173 | } | ||
| 1174 | spin_unlock(&hc->lock); | ||
| 1175 | return IRQ_HANDLED; | ||
| 1176 | } | ||
| 1177 | |||
| 1178 | /* | ||
| 1179 | * timer callback for D-chan busy resolution. Currently no function | ||
| 1180 | */ | ||
| 1181 | static void | ||
| 1182 | hfcpci_dbusy_timer(struct hfc_pci *hc) | ||
| 1183 | { | ||
| 1184 | } | ||
| 1185 | |||
| 1186 | /* | ||
| 1187 | * activate/deactivate hardware for selected channels and mode | ||
| 1188 | */ | ||
| 1189 | static int | ||
| 1190 | mode_hfcpci(struct bchannel *bch, int bc, int protocol) | ||
| 1191 | { | ||
| 1192 | struct hfc_pci *hc = bch->hw; | ||
| 1193 | int fifo2; | ||
| 1194 | u_char rx_slot = 0, tx_slot = 0, pcm_mode; | ||
| 1195 | |||
| 1196 | if (bch->debug & DEBUG_HW_BCHANNEL) | ||
| 1197 | printk(KERN_DEBUG | ||
| 1198 | "HFCPCI bchannel protocol %x-->%x ch %x-->%x\n", | ||
| 1199 | bch->state, protocol, bch->nr, bc); | ||
| 1200 | |||
| 1201 | fifo2 = bc; | ||
| 1202 | pcm_mode = (bc>>24) & 0xff; | ||
| 1203 | if (pcm_mode) { /* PCM SLOT USE */ | ||
| 1204 | if (!test_bit(HFC_CFG_PCM, &hc->cfg)) | ||
| 1205 | printk(KERN_WARNING | ||
| 1206 | "%s: pcm channel id without HFC_CFG_PCM\n", | ||
| 1207 | __func__); | ||
| 1208 | rx_slot = (bc>>8) & 0xff; | ||
| 1209 | tx_slot = (bc>>16) & 0xff; | ||
| 1210 | bc = bc & 0xff; | ||
| 1211 | } else if (test_bit(HFC_CFG_PCM, &hc->cfg) && | ||
| 1212 | (protocol > ISDN_P_NONE)) | ||
| 1213 | printk(KERN_WARNING "%s: no pcm channel id but HFC_CFG_PCM\n", | ||
| 1214 | __func__); | ||
| 1215 | if (hc->chanlimit > 1) { | ||
| 1216 | hc->hw.bswapped = 0; /* B1 and B2 normal mode */ | ||
| 1217 | hc->hw.sctrl_e &= ~0x80; | ||
| 1218 | } else { | ||
| 1219 | if (bc & 2) { | ||
| 1220 | if (protocol != ISDN_P_NONE) { | ||
| 1221 | hc->hw.bswapped = 1; /* B1 and B2 exchanged */ | ||
| 1222 | hc->hw.sctrl_e |= 0x80; | ||
| 1223 | } else { | ||
| 1224 | hc->hw.bswapped = 0; /* B1 and B2 normal mode */ | ||
| 1225 | hc->hw.sctrl_e &= ~0x80; | ||
| 1226 | } | ||
| 1227 | fifo2 = 1; | ||
| 1228 | } else { | ||
| 1229 | hc->hw.bswapped = 0; /* B1 and B2 normal mode */ | ||
| 1230 | hc->hw.sctrl_e &= ~0x80; | ||
| 1231 | } | ||
| 1232 | } | ||
| 1233 | switch (protocol) { | ||
| 1234 | case (-1): /* used for init */ | ||
| 1235 | bch->state = -1; | ||
| 1236 | bch->nr = bc; | ||
| 1237 | case (ISDN_P_NONE): | ||
| 1238 | if (bch->state == ISDN_P_NONE) | ||
| 1239 | return 0; | ||
| 1240 | if (bc & 2) { | ||
| 1241 | hc->hw.sctrl &= ~SCTRL_B2_ENA; | ||
| 1242 | hc->hw.sctrl_r &= ~SCTRL_B2_ENA; | ||
| 1243 | } else { | ||
| 1244 | hc->hw.sctrl &= ~SCTRL_B1_ENA; | ||
| 1245 | hc->hw.sctrl_r &= ~SCTRL_B1_ENA; | ||
| 1246 | } | ||
| 1247 | if (fifo2 & 2) { | ||
| 1248 | hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B2; | ||
| 1249 | hc->hw.int_m1 &= ~(HFCPCI_INTS_B2TRANS + | ||
| 1250 | HFCPCI_INTS_B2REC); | ||
| 1251 | } else { | ||
| 1252 | hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B1; | ||
| 1253 | hc->hw.int_m1 &= ~(HFCPCI_INTS_B1TRANS + | ||
| 1254 | HFCPCI_INTS_B1REC); | ||
| 1255 | } | ||
| 1256 | #ifdef REVERSE_BITORDER | ||
| 1257 | if (bch->nr & 2) | ||
| 1258 | hc->hw.cirm &= 0x7f; | ||
| 1259 | else | ||
| 1260 | hc->hw.cirm &= 0xbf; | ||
| 1261 | #endif | ||
| 1262 | bch->state = ISDN_P_NONE; | ||
| 1263 | bch->nr = bc; | ||
| 1264 | test_and_clear_bit(FLG_HDLC, &bch->Flags); | ||
| 1265 | test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags); | ||
| 1266 | break; | ||
| 1267 | case (ISDN_P_B_RAW): | ||
| 1268 | bch->state = protocol; | ||
| 1269 | bch->nr = bc; | ||
| 1270 | hfcpci_clear_fifo_rx(hc, (fifo2 & 2)?1:0); | ||
| 1271 | hfcpci_clear_fifo_tx(hc, (fifo2 & 2)?1:0); | ||
| 1272 | if (bc & 2) { | ||
| 1273 | hc->hw.sctrl |= SCTRL_B2_ENA; | ||
| 1274 | hc->hw.sctrl_r |= SCTRL_B2_ENA; | ||
| 1275 | #ifdef REVERSE_BITORDER | ||
| 1276 | hc->hw.cirm |= 0x80; | ||
| 1277 | #endif | ||
| 1278 | } else { | ||
| 1279 | hc->hw.sctrl |= SCTRL_B1_ENA; | ||
| 1280 | hc->hw.sctrl_r |= SCTRL_B1_ENA; | ||
| 1281 | #ifdef REVERSE_BITORDER | ||
| 1282 | hc->hw.cirm |= 0x40; | ||
| 1283 | #endif | ||
| 1284 | } | ||
| 1285 | if (fifo2 & 2) { | ||
| 1286 | hc->hw.fifo_en |= HFCPCI_FIFOEN_B2; | ||
| 1287 | hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS + | ||
| 1288 | HFCPCI_INTS_B2REC); | ||
| 1289 | hc->hw.ctmt |= 2; | ||
| 1290 | hc->hw.conn &= ~0x18; | ||
| 1291 | } else { | ||
| 1292 | hc->hw.fifo_en |= HFCPCI_FIFOEN_B1; | ||
| 1293 | hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS + | ||
| 1294 | HFCPCI_INTS_B1REC); | ||
| 1295 | hc->hw.ctmt |= 1; | ||
| 1296 | hc->hw.conn &= ~0x03; | ||
| 1297 | } | ||
| 1298 | test_and_set_bit(FLG_TRANSPARENT, &bch->Flags); | ||
| 1299 | break; | ||
| 1300 | case (ISDN_P_B_HDLC): | ||
| 1301 | bch->state = protocol; | ||
| 1302 | bch->nr = bc; | ||
| 1303 | hfcpci_clear_fifo_rx(hc, (fifo2 & 2)?1:0); | ||
| 1304 | hfcpci_clear_fifo_tx(hc, (fifo2 & 2)?1:0); | ||
| 1305 | if (bc & 2) { | ||
| 1306 | hc->hw.sctrl |= SCTRL_B2_ENA; | ||
| 1307 | hc->hw.sctrl_r |= SCTRL_B2_ENA; | ||
| 1308 | } else { | ||
| 1309 | hc->hw.sctrl |= SCTRL_B1_ENA; | ||
| 1310 | hc->hw.sctrl_r |= SCTRL_B1_ENA; | ||
| 1311 | } | ||
| 1312 | if (fifo2 & 2) { | ||
| 1313 | hc->hw.last_bfifo_cnt[1] = 0; | ||
| 1314 | hc->hw.fifo_en |= HFCPCI_FIFOEN_B2; | ||
| 1315 | hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS + | ||
| 1316 | HFCPCI_INTS_B2REC); | ||
| 1317 | hc->hw.ctmt &= ~2; | ||
| 1318 | hc->hw.conn &= ~0x18; | ||
| 1319 | } else { | ||
| 1320 | hc->hw.last_bfifo_cnt[0] = 0; | ||
| 1321 | hc->hw.fifo_en |= HFCPCI_FIFOEN_B1; | ||
| 1322 | hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS + | ||
| 1323 | HFCPCI_INTS_B1REC); | ||
| 1324 | hc->hw.ctmt &= ~1; | ||
| 1325 | hc->hw.conn &= ~0x03; | ||
| 1326 | } | ||
| 1327 | test_and_set_bit(FLG_HDLC, &bch->Flags); | ||
| 1328 | break; | ||
| 1329 | default: | ||
| 1330 | printk(KERN_DEBUG "prot not known %x\n", protocol); | ||
| 1331 | return -ENOPROTOOPT; | ||
| 1332 | } | ||
| 1333 | if (test_bit(HFC_CFG_PCM, &hc->cfg)) { | ||
| 1334 | if ((protocol == ISDN_P_NONE) || | ||
| 1335 | (protocol == -1)) { /* init case */ | ||
| 1336 | rx_slot = 0; | ||
| 1337 | tx_slot = 0; | ||
| 1338 | } else { | ||
| 1339 | if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) { | ||
| 1340 | rx_slot |= 0xC0; | ||
| 1341 | tx_slot |= 0xC0; | ||
| 1342 | } else { | ||
| 1343 | rx_slot |= 0x80; | ||
| 1344 | tx_slot |= 0x80; | ||
| 1345 | } | ||
| 1346 | } | ||
| 1347 | if (bc & 2) { | ||
| 1348 | hc->hw.conn &= 0xc7; | ||
| 1349 | hc->hw.conn |= 0x08; | ||
| 1350 | printk(KERN_DEBUG "%s: Write_hfc: B2_SSL 0x%x\n", | ||
| 1351 | __func__, tx_slot); | ||
| 1352 | printk(KERN_DEBUG "%s: Write_hfc: B2_RSL 0x%x\n", | ||
| 1353 | __func__, rx_slot); | ||
| 1354 | Write_hfc(hc, HFCPCI_B2_SSL, tx_slot); | ||
| 1355 | Write_hfc(hc, HFCPCI_B2_RSL, rx_slot); | ||
| 1356 | } else { | ||
| 1357 | hc->hw.conn &= 0xf8; | ||
| 1358 | hc->hw.conn |= 0x01; | ||
| 1359 | printk(KERN_DEBUG "%s: Write_hfc: B1_SSL 0x%x\n", | ||
| 1360 | __func__, tx_slot); | ||
| 1361 | printk(KERN_DEBUG "%s: Write_hfc: B1_RSL 0x%x\n", | ||
| 1362 | __func__, rx_slot); | ||
| 1363 | Write_hfc(hc, HFCPCI_B1_SSL, tx_slot); | ||
| 1364 | Write_hfc(hc, HFCPCI_B1_RSL, rx_slot); | ||
| 1365 | } | ||
| 1366 | } | ||
| 1367 | Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e); | ||
| 1368 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
| 1369 | Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); | ||
| 1370 | Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl); | ||
| 1371 | Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r); | ||
| 1372 | Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt); | ||
| 1373 | Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); | ||
| 1374 | #ifdef REVERSE_BITORDER | ||
| 1375 | Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); | ||
| 1376 | #endif | ||
| 1377 | return 0; | ||
| 1378 | } | ||
| 1379 | |||
| 1380 | static int | ||
| 1381 | set_hfcpci_rxtest(struct bchannel *bch, int protocol, int chan) | ||
| 1382 | { | ||
| 1383 | struct hfc_pci *hc = bch->hw; | ||
| 1384 | |||
| 1385 | if (bch->debug & DEBUG_HW_BCHANNEL) | ||
| 1386 | printk(KERN_DEBUG | ||
| 1387 | "HFCPCI bchannel test rx protocol %x-->%x ch %x-->%x\n", | ||
| 1388 | bch->state, protocol, bch->nr, chan); | ||
| 1389 | if (bch->nr != chan) { | ||
| 1390 | printk(KERN_DEBUG | ||
| 1391 | "HFCPCI rxtest wrong channel parameter %x/%x\n", | ||
| 1392 | bch->nr, chan); | ||
| 1393 | return -EINVAL; | ||
| 1394 | } | ||
| 1395 | switch (protocol) { | ||
| 1396 | case (ISDN_P_B_RAW): | ||
| 1397 | bch->state = protocol; | ||
| 1398 | hfcpci_clear_fifo_rx(hc, (chan & 2)?1:0); | ||
| 1399 | if (chan & 2) { | ||
| 1400 | hc->hw.sctrl_r |= SCTRL_B2_ENA; | ||
| 1401 | hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX; | ||
| 1402 | hc->hw.int_m1 |= HFCPCI_INTS_B2REC; | ||
| 1403 | hc->hw.ctmt |= 2; | ||
| 1404 | hc->hw.conn &= ~0x18; | ||
| 1405 | #ifdef REVERSE_BITORDER | ||
| 1406 | hc->hw.cirm |= 0x80; | ||
| 1407 | #endif | ||
| 1408 | } else { | ||
| 1409 | hc->hw.sctrl_r |= SCTRL_B1_ENA; | ||
| 1410 | hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX; | ||
| 1411 | hc->hw.int_m1 |= HFCPCI_INTS_B1REC; | ||
| 1412 | hc->hw.ctmt |= 1; | ||
| 1413 | hc->hw.conn &= ~0x03; | ||
| 1414 | #ifdef REVERSE_BITORDER | ||
| 1415 | hc->hw.cirm |= 0x40; | ||
| 1416 | #endif | ||
| 1417 | } | ||
| 1418 | break; | ||
| 1419 | case (ISDN_P_B_HDLC): | ||
| 1420 | bch->state = protocol; | ||
| 1421 | hfcpci_clear_fifo_rx(hc, (chan & 2)?1:0); | ||
| 1422 | if (chan & 2) { | ||
| 1423 | hc->hw.sctrl_r |= SCTRL_B2_ENA; | ||
| 1424 | hc->hw.last_bfifo_cnt[1] = 0; | ||
| 1425 | hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX; | ||
| 1426 | hc->hw.int_m1 |= HFCPCI_INTS_B2REC; | ||
| 1427 | hc->hw.ctmt &= ~2; | ||
| 1428 | hc->hw.conn &= ~0x18; | ||
| 1429 | } else { | ||
| 1430 | hc->hw.sctrl_r |= SCTRL_B1_ENA; | ||
| 1431 | hc->hw.last_bfifo_cnt[0] = 0; | ||
| 1432 | hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX; | ||
| 1433 | hc->hw.int_m1 |= HFCPCI_INTS_B1REC; | ||
| 1434 | hc->hw.ctmt &= ~1; | ||
| 1435 | hc->hw.conn &= ~0x03; | ||
| 1436 | } | ||
| 1437 | break; | ||
| 1438 | default: | ||
| 1439 | printk(KERN_DEBUG "prot not known %x\n", protocol); | ||
| 1440 | return -ENOPROTOOPT; | ||
| 1441 | } | ||
| 1442 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
| 1443 | Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); | ||
| 1444 | Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r); | ||
| 1445 | Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt); | ||
| 1446 | Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); | ||
| 1447 | #ifdef REVERSE_BITORDER | ||
| 1448 | Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); | ||
| 1449 | #endif | ||
| 1450 | return 0; | ||
| 1451 | } | ||
| 1452 | |||
| 1453 | static void | ||
| 1454 | deactivate_bchannel(struct bchannel *bch) | ||
| 1455 | { | ||
| 1456 | struct hfc_pci *hc = bch->hw; | ||
| 1457 | u_long flags; | ||
| 1458 | |||
| 1459 | spin_lock_irqsave(&hc->lock, flags); | ||
| 1460 | if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) { | ||
| 1461 | dev_kfree_skb(bch->next_skb); | ||
| 1462 | bch->next_skb = NULL; | ||
| 1463 | } | ||
| 1464 | if (bch->tx_skb) { | ||
| 1465 | dev_kfree_skb(bch->tx_skb); | ||
| 1466 | bch->tx_skb = NULL; | ||
| 1467 | } | ||
| 1468 | bch->tx_idx = 0; | ||
| 1469 | if (bch->rx_skb) { | ||
| 1470 | dev_kfree_skb(bch->rx_skb); | ||
| 1471 | bch->rx_skb = NULL; | ||
| 1472 | } | ||
| 1473 | mode_hfcpci(bch, bch->nr, ISDN_P_NONE); | ||
| 1474 | test_and_clear_bit(FLG_ACTIVE, &bch->Flags); | ||
| 1475 | test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); | ||
| 1476 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 1477 | } | ||
| 1478 | |||
| 1479 | /* | ||
| 1480 | * Layer 1 B-channel hardware access | ||
| 1481 | */ | ||
| 1482 | static int | ||
| 1483 | channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) | ||
| 1484 | { | ||
| 1485 | int ret = 0; | ||
| 1486 | |||
| 1487 | switch (cq->op) { | ||
| 1488 | case MISDN_CTRL_GETOP: | ||
| 1489 | cq->op = 0; | ||
| 1490 | break; | ||
| 1491 | default: | ||
| 1492 | printk(KERN_WARNING "%s: unknown Op %x\n", __func__, cq->op); | ||
| 1493 | ret = -EINVAL; | ||
| 1494 | break; | ||
| 1495 | } | ||
| 1496 | return ret; | ||
| 1497 | } | ||
| 1498 | static int | ||
| 1499 | hfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
| 1500 | { | ||
| 1501 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
| 1502 | struct hfc_pci *hc = bch->hw; | ||
| 1503 | int ret = -EINVAL; | ||
| 1504 | u_long flags; | ||
| 1505 | |||
| 1506 | if (bch->debug & DEBUG_HW) | ||
| 1507 | printk(KERN_DEBUG "%s: cmd:%x %p\n", __func__, cmd, arg); | ||
| 1508 | switch (cmd) { | ||
| 1509 | case HW_TESTRX_RAW: | ||
| 1510 | spin_lock_irqsave(&hc->lock, flags); | ||
| 1511 | ret = set_hfcpci_rxtest(bch, ISDN_P_B_RAW, (int)(long)arg); | ||
| 1512 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 1513 | break; | ||
| 1514 | case HW_TESTRX_HDLC: | ||
| 1515 | spin_lock_irqsave(&hc->lock, flags); | ||
| 1516 | ret = set_hfcpci_rxtest(bch, ISDN_P_B_HDLC, (int)(long)arg); | ||
| 1517 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 1518 | break; | ||
| 1519 | case HW_TESTRX_OFF: | ||
| 1520 | spin_lock_irqsave(&hc->lock, flags); | ||
| 1521 | mode_hfcpci(bch, bch->nr, ISDN_P_NONE); | ||
| 1522 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 1523 | ret = 0; | ||
| 1524 | break; | ||
| 1525 | case CLOSE_CHANNEL: | ||
| 1526 | test_and_clear_bit(FLG_OPEN, &bch->Flags); | ||
| 1527 | if (test_bit(FLG_ACTIVE, &bch->Flags)) | ||
| 1528 | deactivate_bchannel(bch); | ||
| 1529 | ch->protocol = ISDN_P_NONE; | ||
| 1530 | ch->peer = NULL; | ||
| 1531 | module_put(THIS_MODULE); | ||
| 1532 | ret = 0; | ||
| 1533 | break; | ||
| 1534 | case CONTROL_CHANNEL: | ||
| 1535 | ret = channel_bctrl(bch, arg); | ||
| 1536 | break; | ||
| 1537 | default: | ||
| 1538 | printk(KERN_WARNING "%s: unknown prim(%x)\n", | ||
| 1539 | __func__, cmd); | ||
| 1540 | } | ||
| 1541 | return ret; | ||
| 1542 | } | ||
| 1543 | |||
| 1544 | /* | ||
| 1545 | * Layer2 -> Layer 1 Dchannel data | ||
| 1546 | */ | ||
| 1547 | static int | ||
| 1548 | hfcpci_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb) | ||
| 1549 | { | ||
| 1550 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
| 1551 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
| 1552 | struct hfc_pci *hc = dch->hw; | ||
| 1553 | int ret = -EINVAL; | ||
| 1554 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
| 1555 | unsigned int id; | ||
| 1556 | u_long flags; | ||
| 1557 | |||
| 1558 | switch (hh->prim) { | ||
| 1559 | case PH_DATA_REQ: | ||
| 1560 | spin_lock_irqsave(&hc->lock, flags); | ||
| 1561 | ret = dchannel_senddata(dch, skb); | ||
| 1562 | if (ret > 0) { /* direct TX */ | ||
| 1563 | id = hh->id; /* skb can be freed */ | ||
| 1564 | hfcpci_fill_dfifo(dch->hw); | ||
| 1565 | ret = 0; | ||
| 1566 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 1567 | queue_ch_frame(ch, PH_DATA_CNF, id, NULL); | ||
| 1568 | } else | ||
| 1569 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 1570 | return ret; | ||
| 1571 | case PH_ACTIVATE_REQ: | ||
| 1572 | spin_lock_irqsave(&hc->lock, flags); | ||
| 1573 | if (hc->hw.protocol == ISDN_P_NT_S0) { | ||
| 1574 | ret = 0; | ||
| 1575 | if (test_bit(HFC_CFG_MASTER, &hc->cfg)) | ||
| 1576 | hc->hw.mst_m |= HFCPCI_MASTER; | ||
| 1577 | Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); | ||
| 1578 | if (test_bit(FLG_ACTIVE, &dch->Flags)) { | ||
| 1579 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 1580 | _queue_data(&dch->dev.D, PH_ACTIVATE_IND, | ||
| 1581 | MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); | ||
| 1582 | break; | ||
| 1583 | } | ||
| 1584 | test_and_set_bit(FLG_L2_ACTIVATED, &dch->Flags); | ||
| 1585 | Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | | ||
| 1586 | HFCPCI_DO_ACTION | 1); | ||
| 1587 | } else | ||
| 1588 | ret = l1_event(dch->l1, hh->prim); | ||
| 1589 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 1590 | break; | ||
| 1591 | case PH_DEACTIVATE_REQ: | ||
| 1592 | test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); | ||
| 1593 | spin_lock_irqsave(&hc->lock, flags); | ||
| 1594 | if (hc->hw.protocol == ISDN_P_NT_S0) { | ||
| 1595 | /* prepare deactivation */ | ||
| 1596 | Write_hfc(hc, HFCPCI_STATES, 0x40); | ||
| 1597 | skb_queue_purge(&dch->squeue); | ||
| 1598 | if (dch->tx_skb) { | ||
| 1599 | dev_kfree_skb(dch->tx_skb); | ||
| 1600 | dch->tx_skb = NULL; | ||
| 1601 | } | ||
| 1602 | dch->tx_idx = 0; | ||
| 1603 | if (dch->rx_skb) { | ||
| 1604 | dev_kfree_skb(dch->rx_skb); | ||
| 1605 | dch->rx_skb = NULL; | ||
| 1606 | } | ||
| 1607 | test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); | ||
| 1608 | if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) | ||
| 1609 | del_timer(&dch->timer); | ||
| 1610 | #ifdef FIXME | ||
| 1611 | if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) | ||
| 1612 | dchannel_sched_event(&hc->dch, D_CLEARBUSY); | ||
| 1613 | #endif | ||
| 1614 | hc->hw.mst_m &= ~HFCPCI_MASTER; | ||
| 1615 | Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); | ||
| 1616 | ret = 0; | ||
| 1617 | } else { | ||
| 1618 | ret = l1_event(dch->l1, hh->prim); | ||
| 1619 | } | ||
| 1620 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 1621 | break; | ||
| 1622 | } | ||
| 1623 | if (!ret) | ||
| 1624 | dev_kfree_skb(skb); | ||
| 1625 | return ret; | ||
| 1626 | } | ||
| 1627 | |||
| 1628 | /* | ||
| 1629 | * Layer2 -> Layer 1 Bchannel data | ||
| 1630 | */ | ||
| 1631 | static int | ||
| 1632 | hfcpci_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) | ||
| 1633 | { | ||
| 1634 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
| 1635 | struct hfc_pci *hc = bch->hw; | ||
| 1636 | int ret = -EINVAL; | ||
| 1637 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
| 1638 | unsigned int id; | ||
| 1639 | u_long flags; | ||
| 1640 | |||
| 1641 | switch (hh->prim) { | ||
| 1642 | case PH_DATA_REQ: | ||
| 1643 | spin_lock_irqsave(&hc->lock, flags); | ||
| 1644 | ret = bchannel_senddata(bch, skb); | ||
| 1645 | if (ret > 0) { /* direct TX */ | ||
| 1646 | id = hh->id; /* skb can be freed */ | ||
| 1647 | hfcpci_fill_fifo(bch); | ||
| 1648 | ret = 0; | ||
| 1649 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 1650 | if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
| 1651 | queue_ch_frame(ch, PH_DATA_CNF, id, NULL); | ||
| 1652 | } else | ||
| 1653 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 1654 | return ret; | ||
| 1655 | case PH_ACTIVATE_REQ: | ||
| 1656 | spin_lock_irqsave(&hc->lock, flags); | ||
| 1657 | if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) | ||
| 1658 | ret = mode_hfcpci(bch, bch->nr, ch->protocol); | ||
| 1659 | else | ||
| 1660 | ret = 0; | ||
| 1661 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 1662 | if (!ret) | ||
| 1663 | _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, | ||
| 1664 | NULL, GFP_KERNEL); | ||
| 1665 | break; | ||
| 1666 | case PH_DEACTIVATE_REQ: | ||
| 1667 | deactivate_bchannel(bch); | ||
| 1668 | _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, | ||
| 1669 | NULL, GFP_KERNEL); | ||
| 1670 | ret = 0; | ||
| 1671 | break; | ||
| 1672 | } | ||
| 1673 | if (!ret) | ||
| 1674 | dev_kfree_skb(skb); | ||
| 1675 | return ret; | ||
| 1676 | } | ||
| 1677 | |||
| 1678 | /* | ||
| 1679 | * called for card init message | ||
| 1680 | */ | ||
| 1681 | |||
| 1682 | void | ||
| 1683 | inithfcpci(struct hfc_pci *hc) | ||
| 1684 | { | ||
| 1685 | printk(KERN_DEBUG "inithfcpci: entered\n"); | ||
| 1686 | hc->dch.timer.function = (void *) hfcpci_dbusy_timer; | ||
| 1687 | hc->dch.timer.data = (long) &hc->dch; | ||
| 1688 | init_timer(&hc->dch.timer); | ||
| 1689 | hc->chanlimit = 2; | ||
| 1690 | mode_hfcpci(&hc->bch[0], 1, -1); | ||
| 1691 | mode_hfcpci(&hc->bch[1], 2, -1); | ||
| 1692 | } | ||
| 1693 | |||
| 1694 | |||
| 1695 | static int | ||
| 1696 | init_card(struct hfc_pci *hc) | ||
| 1697 | { | ||
| 1698 | int cnt = 3; | ||
| 1699 | u_long flags; | ||
| 1700 | |||
| 1701 | printk(KERN_DEBUG "init_card: entered\n"); | ||
| 1702 | |||
| 1703 | |||
| 1704 | spin_lock_irqsave(&hc->lock, flags); | ||
| 1705 | disable_hwirq(hc); | ||
| 1706 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 1707 | if (request_irq(hc->irq, hfcpci_int, IRQF_SHARED, "HFC PCI", hc)) { | ||
| 1708 | printk(KERN_WARNING | ||
| 1709 | "mISDN: couldn't get interrupt %d\n", hc->irq); | ||
| 1710 | return -EIO; | ||
| 1711 | } | ||
| 1712 | spin_lock_irqsave(&hc->lock, flags); | ||
| 1713 | reset_hfcpci(hc); | ||
| 1714 | while (cnt) { | ||
| 1715 | inithfcpci(hc); | ||
| 1716 | /* | ||
| 1717 | * Finally enable IRQ output | ||
| 1718 | * this is only allowed, if an IRQ routine is allready | ||
| 1719 | * established for this HFC, so don't do that earlier | ||
| 1720 | */ | ||
| 1721 | enable_hwirq(hc); | ||
| 1722 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 1723 | /* Timeout 80ms */ | ||
| 1724 | current->state = TASK_UNINTERRUPTIBLE; | ||
| 1725 | schedule_timeout((80*HZ)/1000); | ||
| 1726 | printk(KERN_INFO "HFC PCI: IRQ %d count %d\n", | ||
| 1727 | hc->irq, hc->irqcnt); | ||
| 1728 | /* now switch timer interrupt off */ | ||
| 1729 | spin_lock_irqsave(&hc->lock, flags); | ||
| 1730 | hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; | ||
| 1731 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
| 1732 | /* reinit mode reg */ | ||
| 1733 | Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); | ||
| 1734 | if (!hc->irqcnt) { | ||
| 1735 | printk(KERN_WARNING | ||
| 1736 | "HFC PCI: IRQ(%d) getting no interrupts " | ||
| 1737 | "during init %d\n", hc->irq, 4 - cnt); | ||
| 1738 | if (cnt == 1) { | ||
| 1739 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 1740 | return -EIO; | ||
| 1741 | } else { | ||
| 1742 | reset_hfcpci(hc); | ||
| 1743 | cnt--; | ||
| 1744 | } | ||
| 1745 | } else { | ||
| 1746 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 1747 | hc->initdone = 1; | ||
| 1748 | return 0; | ||
| 1749 | } | ||
| 1750 | } | ||
| 1751 | disable_hwirq(hc); | ||
| 1752 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 1753 | free_irq(hc->irq, hc); | ||
| 1754 | return -EIO; | ||
| 1755 | } | ||
| 1756 | |||
| 1757 | static int | ||
| 1758 | channel_ctrl(struct hfc_pci *hc, struct mISDN_ctrl_req *cq) | ||
| 1759 | { | ||
| 1760 | int ret = 0; | ||
| 1761 | u_char slot; | ||
| 1762 | |||
| 1763 | switch (cq->op) { | ||
| 1764 | case MISDN_CTRL_GETOP: | ||
| 1765 | cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_CONNECT | | ||
| 1766 | MISDN_CTRL_DISCONNECT; | ||
| 1767 | break; | ||
| 1768 | case MISDN_CTRL_LOOP: | ||
| 1769 | /* channel 0 disabled loop */ | ||
| 1770 | if (cq->channel < 0 || cq->channel > 2) { | ||
| 1771 | ret = -EINVAL; | ||
| 1772 | break; | ||
| 1773 | } | ||
| 1774 | if (cq->channel & 1) { | ||
| 1775 | if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) | ||
| 1776 | slot = 0xC0; | ||
| 1777 | else | ||
| 1778 | slot = 0x80; | ||
| 1779 | printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n", | ||
| 1780 | __func__, slot); | ||
| 1781 | Write_hfc(hc, HFCPCI_B1_SSL, slot); | ||
| 1782 | Write_hfc(hc, HFCPCI_B1_RSL, slot); | ||
| 1783 | hc->hw.conn = (hc->hw.conn & ~7) | 6; | ||
| 1784 | Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); | ||
| 1785 | } | ||
| 1786 | if (cq->channel & 2) { | ||
| 1787 | if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) | ||
| 1788 | slot = 0xC1; | ||
| 1789 | else | ||
| 1790 | slot = 0x81; | ||
| 1791 | printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n", | ||
| 1792 | __func__, slot); | ||
| 1793 | Write_hfc(hc, HFCPCI_B2_SSL, slot); | ||
| 1794 | Write_hfc(hc, HFCPCI_B2_RSL, slot); | ||
| 1795 | hc->hw.conn = (hc->hw.conn & ~0x38) | 0x30; | ||
| 1796 | Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); | ||
| 1797 | } | ||
| 1798 | if (cq->channel & 3) | ||
| 1799 | hc->hw.trm |= 0x80; /* enable IOM-loop */ | ||
| 1800 | else { | ||
| 1801 | hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x09; | ||
| 1802 | Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); | ||
| 1803 | hc->hw.trm &= 0x7f; /* disable IOM-loop */ | ||
| 1804 | } | ||
| 1805 | Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); | ||
| 1806 | break; | ||
| 1807 | case MISDN_CTRL_CONNECT: | ||
| 1808 | if (cq->channel == cq->p1) { | ||
| 1809 | ret = -EINVAL; | ||
| 1810 | break; | ||
| 1811 | } | ||
| 1812 | if (cq->channel < 1 || cq->channel > 2 || | ||
| 1813 | cq->p1 < 1 || cq->p1 > 2) { | ||
| 1814 | ret = -EINVAL; | ||
| 1815 | break; | ||
| 1816 | } | ||
| 1817 | if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) | ||
| 1818 | slot = 0xC0; | ||
| 1819 | else | ||
| 1820 | slot = 0x80; | ||
| 1821 | printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n", | ||
| 1822 | __func__, slot); | ||
| 1823 | Write_hfc(hc, HFCPCI_B1_SSL, slot); | ||
| 1824 | Write_hfc(hc, HFCPCI_B2_RSL, slot); | ||
| 1825 | if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) | ||
| 1826 | slot = 0xC1; | ||
| 1827 | else | ||
| 1828 | slot = 0x81; | ||
| 1829 | printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n", | ||
| 1830 | __func__, slot); | ||
| 1831 | Write_hfc(hc, HFCPCI_B2_SSL, slot); | ||
| 1832 | Write_hfc(hc, HFCPCI_B1_RSL, slot); | ||
| 1833 | hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x36; | ||
| 1834 | Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); | ||
| 1835 | hc->hw.trm |= 0x80; | ||
| 1836 | Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); | ||
| 1837 | break; | ||
| 1838 | case MISDN_CTRL_DISCONNECT: | ||
| 1839 | hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x09; | ||
| 1840 | Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); | ||
| 1841 | hc->hw.trm &= 0x7f; /* disable IOM-loop */ | ||
| 1842 | break; | ||
| 1843 | default: | ||
| 1844 | printk(KERN_WARNING "%s: unknown Op %x\n", | ||
| 1845 | __func__, cq->op); | ||
| 1846 | ret = -EINVAL; | ||
| 1847 | break; | ||
| 1848 | } | ||
| 1849 | return ret; | ||
| 1850 | } | ||
| 1851 | |||
| 1852 | static int | ||
| 1853 | open_dchannel(struct hfc_pci *hc, struct mISDNchannel *ch, | ||
| 1854 | struct channel_req *rq) | ||
| 1855 | { | ||
| 1856 | int err = 0; | ||
| 1857 | |||
| 1858 | if (debug & DEBUG_HW_OPEN) | ||
| 1859 | printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__, | ||
| 1860 | hc->dch.dev.id, __builtin_return_address(0)); | ||
| 1861 | if (rq->protocol == ISDN_P_NONE) | ||
| 1862 | return -EINVAL; | ||
| 1863 | if (!hc->initdone) { | ||
| 1864 | if (rq->protocol == ISDN_P_TE_S0) { | ||
| 1865 | err = create_l1(&hc->dch, hfc_l1callback); | ||
| 1866 | if (err) | ||
| 1867 | return err; | ||
| 1868 | } | ||
| 1869 | hc->hw.protocol = rq->protocol; | ||
| 1870 | ch->protocol = rq->protocol; | ||
| 1871 | err = init_card(hc); | ||
| 1872 | if (err) | ||
| 1873 | return err; | ||
| 1874 | } else { | ||
| 1875 | if (rq->protocol != ch->protocol) { | ||
| 1876 | if (hc->hw.protocol == ISDN_P_TE_S0) | ||
| 1877 | l1_event(hc->dch.l1, CLOSE_CHANNEL); | ||
| 1878 | hc->hw.protocol = rq->protocol; | ||
| 1879 | ch->protocol = rq->protocol; | ||
| 1880 | hfcpci_setmode(hc); | ||
| 1881 | } | ||
| 1882 | } | ||
| 1883 | |||
| 1884 | if (((ch->protocol == ISDN_P_NT_S0) && (hc->dch.state == 3)) || | ||
| 1885 | ((ch->protocol == ISDN_P_TE_S0) && (hc->dch.state == 7))) { | ||
| 1886 | _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, | ||
| 1887 | 0, NULL, GFP_KERNEL); | ||
| 1888 | } | ||
| 1889 | rq->ch = ch; | ||
| 1890 | if (!try_module_get(THIS_MODULE)) | ||
| 1891 | printk(KERN_WARNING "%s:cannot get module\n", __func__); | ||
| 1892 | return 0; | ||
| 1893 | } | ||
| 1894 | |||
| 1895 | static int | ||
| 1896 | open_bchannel(struct hfc_pci *hc, struct channel_req *rq) | ||
| 1897 | { | ||
| 1898 | struct bchannel *bch; | ||
| 1899 | |||
| 1900 | if (rq->adr.channel > 2) | ||
| 1901 | return -EINVAL; | ||
| 1902 | if (rq->protocol == ISDN_P_NONE) | ||
| 1903 | return -EINVAL; | ||
| 1904 | bch = &hc->bch[rq->adr.channel - 1]; | ||
| 1905 | if (test_and_set_bit(FLG_OPEN, &bch->Flags)) | ||
| 1906 | return -EBUSY; /* b-channel can be only open once */ | ||
| 1907 | bch->ch.protocol = rq->protocol; | ||
| 1908 | rq->ch = &bch->ch; /* TODO: E-channel */ | ||
| 1909 | if (!try_module_get(THIS_MODULE)) | ||
| 1910 | printk(KERN_WARNING "%s:cannot get module\n", __func__); | ||
| 1911 | return 0; | ||
| 1912 | } | ||
| 1913 | |||
| 1914 | /* | ||
| 1915 | * device control function | ||
| 1916 | */ | ||
| 1917 | static int | ||
| 1918 | hfc_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
| 1919 | { | ||
| 1920 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
| 1921 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
| 1922 | struct hfc_pci *hc = dch->hw; | ||
| 1923 | struct channel_req *rq; | ||
| 1924 | int err = 0; | ||
| 1925 | |||
| 1926 | if (dch->debug & DEBUG_HW) | ||
| 1927 | printk(KERN_DEBUG "%s: cmd:%x %p\n", | ||
| 1928 | __func__, cmd, arg); | ||
| 1929 | switch (cmd) { | ||
| 1930 | case OPEN_CHANNEL: | ||
| 1931 | rq = arg; | ||
| 1932 | if (rq->adr.channel == 0) | ||
| 1933 | err = open_dchannel(hc, ch, rq); | ||
| 1934 | else | ||
| 1935 | err = open_bchannel(hc, rq); | ||
| 1936 | break; | ||
| 1937 | case CLOSE_CHANNEL: | ||
| 1938 | if (debug & DEBUG_HW_OPEN) | ||
| 1939 | printk(KERN_DEBUG "%s: dev(%d) close from %p\n", | ||
| 1940 | __func__, hc->dch.dev.id, | ||
| 1941 | __builtin_return_address(0)); | ||
| 1942 | module_put(THIS_MODULE); | ||
| 1943 | break; | ||
| 1944 | case CONTROL_CHANNEL: | ||
| 1945 | err = channel_ctrl(hc, arg); | ||
| 1946 | break; | ||
| 1947 | default: | ||
| 1948 | if (dch->debug & DEBUG_HW) | ||
| 1949 | printk(KERN_DEBUG "%s: unknown command %x\n", | ||
| 1950 | __func__, cmd); | ||
| 1951 | return -EINVAL; | ||
| 1952 | } | ||
| 1953 | return err; | ||
| 1954 | } | ||
| 1955 | |||
| 1956 | static int | ||
| 1957 | setup_hw(struct hfc_pci *hc) | ||
| 1958 | { | ||
| 1959 | void *buffer; | ||
| 1960 | |||
| 1961 | printk(KERN_INFO "mISDN: HFC-PCI driver %s\n", hfcpci_revision); | ||
| 1962 | hc->hw.cirm = 0; | ||
| 1963 | hc->dch.state = 0; | ||
| 1964 | pci_set_master(hc->pdev); | ||
| 1965 | if (!hc->irq) { | ||
| 1966 | printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n"); | ||
| 1967 | return 1; | ||
| 1968 | } | ||
| 1969 | hc->hw.pci_io = (char *)(ulong)hc->pdev->resource[1].start; | ||
| 1970 | |||
| 1971 | if (!hc->hw.pci_io) { | ||
| 1972 | printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n"); | ||
| 1973 | return 1; | ||
| 1974 | } | ||
| 1975 | /* Allocate memory for FIFOS */ | ||
| 1976 | /* the memory needs to be on a 32k boundary within the first 4G */ | ||
| 1977 | pci_set_dma_mask(hc->pdev, 0xFFFF8000); | ||
| 1978 | buffer = pci_alloc_consistent(hc->pdev, 0x8000, &hc->hw.dmahandle); | ||
| 1979 | /* We silently assume the address is okay if nonzero */ | ||
| 1980 | if (!buffer) { | ||
| 1981 | printk(KERN_WARNING | ||
| 1982 | "HFC-PCI: Error allocating memory for FIFO!\n"); | ||
| 1983 | return 1; | ||
| 1984 | } | ||
| 1985 | hc->hw.fifos = buffer; | ||
| 1986 | pci_write_config_dword(hc->pdev, 0x80, hc->hw.dmahandle); | ||
| 1987 | hc->hw.pci_io = ioremap((ulong) hc->hw.pci_io, 256); | ||
| 1988 | printk(KERN_INFO | ||
| 1989 | "HFC-PCI: defined at mem %#lx fifo %#lx(%#lx) IRQ %d HZ %d\n", | ||
| 1990 | (u_long) hc->hw.pci_io, (u_long) hc->hw.fifos, | ||
| 1991 | (u_long) virt_to_bus(hc->hw.fifos), | ||
| 1992 | hc->irq, HZ); | ||
| 1993 | /* enable memory mapped ports, disable busmaster */ | ||
| 1994 | pci_write_config_word(hc->pdev, PCI_COMMAND, PCI_ENA_MEMIO); | ||
| 1995 | hc->hw.int_m2 = 0; | ||
| 1996 | disable_hwirq(hc); | ||
| 1997 | hc->hw.int_m1 = 0; | ||
| 1998 | Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); | ||
| 1999 | /* At this point the needed PCI config is done */ | ||
| 2000 | /* fifos are still not enabled */ | ||
| 2001 | hc->hw.timer.function = (void *) hfcpci_Timer; | ||
| 2002 | hc->hw.timer.data = (long) hc; | ||
| 2003 | init_timer(&hc->hw.timer); | ||
| 2004 | /* default PCM master */ | ||
| 2005 | test_and_set_bit(HFC_CFG_MASTER, &hc->cfg); | ||
| 2006 | return 0; | ||
| 2007 | } | ||
| 2008 | |||
| 2009 | static void | ||
| 2010 | release_card(struct hfc_pci *hc) { | ||
| 2011 | u_long flags; | ||
| 2012 | |||
| 2013 | spin_lock_irqsave(&hc->lock, flags); | ||
| 2014 | hc->hw.int_m2 = 0; /* interrupt output off ! */ | ||
| 2015 | disable_hwirq(hc); | ||
| 2016 | mode_hfcpci(&hc->bch[0], 1, ISDN_P_NONE); | ||
| 2017 | mode_hfcpci(&hc->bch[1], 2, ISDN_P_NONE); | ||
| 2018 | if (hc->dch.timer.function != NULL) { | ||
| 2019 | del_timer(&hc->dch.timer); | ||
| 2020 | hc->dch.timer.function = NULL; | ||
| 2021 | } | ||
| 2022 | spin_unlock_irqrestore(&hc->lock, flags); | ||
| 2023 | if (hc->hw.protocol == ISDN_P_TE_S0) | ||
| 2024 | l1_event(hc->dch.l1, CLOSE_CHANNEL); | ||
| 2025 | if (hc->initdone) | ||
| 2026 | free_irq(hc->irq, hc); | ||
| 2027 | release_io_hfcpci(hc); /* must release after free_irq! */ | ||
| 2028 | mISDN_unregister_device(&hc->dch.dev); | ||
| 2029 | mISDN_freebchannel(&hc->bch[1]); | ||
| 2030 | mISDN_freebchannel(&hc->bch[0]); | ||
| 2031 | mISDN_freedchannel(&hc->dch); | ||
| 2032 | list_del(&hc->list); | ||
| 2033 | pci_set_drvdata(hc->pdev, NULL); | ||
| 2034 | kfree(hc); | ||
| 2035 | } | ||
| 2036 | |||
| 2037 | static int | ||
| 2038 | setup_card(struct hfc_pci *card) | ||
| 2039 | { | ||
| 2040 | int err = -EINVAL; | ||
| 2041 | u_int i; | ||
| 2042 | u_long flags; | ||
| 2043 | char name[MISDN_MAX_IDLEN]; | ||
| 2044 | |||
| 2045 | if (HFC_cnt >= MAX_CARDS) | ||
| 2046 | return -EINVAL; /* maybe better value */ | ||
| 2047 | |||
| 2048 | card->dch.debug = debug; | ||
| 2049 | spin_lock_init(&card->lock); | ||
| 2050 | mISDN_initdchannel(&card->dch, MAX_DFRAME_LEN_L1, ph_state); | ||
| 2051 | card->dch.hw = card; | ||
| 2052 | card->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0); | ||
| 2053 | card->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | | ||
| 2054 | (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); | ||
| 2055 | card->dch.dev.D.send = hfcpci_l2l1D; | ||
| 2056 | card->dch.dev.D.ctrl = hfc_dctrl; | ||
| 2057 | card->dch.dev.nrbchan = 2; | ||
| 2058 | for (i = 0; i < 2; i++) { | ||
| 2059 | card->bch[i].nr = i + 1; | ||
| 2060 | test_and_set_bit(i + 1, &card->dch.dev.channelmap[0]); | ||
| 2061 | card->bch[i].debug = debug; | ||
| 2062 | mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM); | ||
| 2063 | card->bch[i].hw = card; | ||
| 2064 | card->bch[i].ch.send = hfcpci_l2l1B; | ||
| 2065 | card->bch[i].ch.ctrl = hfc_bctrl; | ||
| 2066 | card->bch[i].ch.nr = i + 1; | ||
| 2067 | list_add(&card->bch[i].ch.list, &card->dch.dev.bchannels); | ||
| 2068 | } | ||
| 2069 | err = setup_hw(card); | ||
| 2070 | if (err) | ||
| 2071 | goto error; | ||
| 2072 | snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-pci.%d", HFC_cnt + 1); | ||
| 2073 | err = mISDN_register_device(&card->dch.dev, name); | ||
| 2074 | if (err) | ||
| 2075 | goto error; | ||
| 2076 | HFC_cnt++; | ||
| 2077 | write_lock_irqsave(&HFClock, flags); | ||
| 2078 | list_add_tail(&card->list, &HFClist); | ||
| 2079 | write_unlock_irqrestore(&HFClock, flags); | ||
| 2080 | printk(KERN_INFO "HFC %d cards installed\n", HFC_cnt); | ||
| 2081 | return 0; | ||
| 2082 | error: | ||
| 2083 | mISDN_freebchannel(&card->bch[1]); | ||
| 2084 | mISDN_freebchannel(&card->bch[0]); | ||
| 2085 | mISDN_freedchannel(&card->dch); | ||
| 2086 | kfree(card); | ||
| 2087 | return err; | ||
| 2088 | } | ||
| 2089 | |||
| 2090 | /* private data in the PCI devices list */ | ||
| 2091 | struct _hfc_map { | ||
| 2092 | u_int subtype; | ||
| 2093 | u_int flag; | ||
| 2094 | char *name; | ||
| 2095 | }; | ||
| 2096 | |||
| 2097 | static const struct _hfc_map hfc_map[] = | ||
| 2098 | { | ||
| 2099 | {HFC_CCD_2BD0, 0, "CCD/Billion/Asuscom 2BD0"}, | ||
| 2100 | {HFC_CCD_B000, 0, "Billion B000"}, | ||
| 2101 | {HFC_CCD_B006, 0, "Billion B006"}, | ||
| 2102 | {HFC_CCD_B007, 0, "Billion B007"}, | ||
| 2103 | {HFC_CCD_B008, 0, "Billion B008"}, | ||
| 2104 | {HFC_CCD_B009, 0, "Billion B009"}, | ||
| 2105 | {HFC_CCD_B00A, 0, "Billion B00A"}, | ||
| 2106 | {HFC_CCD_B00B, 0, "Billion B00B"}, | ||
| 2107 | {HFC_CCD_B00C, 0, "Billion B00C"}, | ||
| 2108 | {HFC_CCD_B100, 0, "Seyeon B100"}, | ||
| 2109 | {HFC_CCD_B700, 0, "Primux II S0 B700"}, | ||
| 2110 | {HFC_CCD_B701, 0, "Primux II S0 NT B701"}, | ||
| 2111 | {HFC_ABOCOM_2BD1, 0, "Abocom/Magitek 2BD1"}, | ||
| 2112 | {HFC_ASUS_0675, 0, "Asuscom/Askey 675"}, | ||
| 2113 | {HFC_BERKOM_TCONCEPT, 0, "German telekom T-Concept"}, | ||
| 2114 | {HFC_BERKOM_A1T, 0, "German telekom A1T"}, | ||
| 2115 | {HFC_ANIGMA_MC145575, 0, "Motorola MC145575"}, | ||
| 2116 | {HFC_ZOLTRIX_2BD0, 0, "Zoltrix 2BD0"}, | ||
| 2117 | {HFC_DIGI_DF_M_IOM2_E, 0, | ||
| 2118 | "Digi International DataFire Micro V IOM2 (Europe)"}, | ||
| 2119 | {HFC_DIGI_DF_M_E, 0, | ||
| 2120 | "Digi International DataFire Micro V (Europe)"}, | ||
| 2121 | {HFC_DIGI_DF_M_IOM2_A, 0, | ||
| 2122 | "Digi International DataFire Micro V IOM2 (North America)"}, | ||
| 2123 | {HFC_DIGI_DF_M_A, 0, | ||
| 2124 | "Digi International DataFire Micro V (North America)"}, | ||
| 2125 | {HFC_SITECOM_DC105V2, 0, "Sitecom Connectivity DC-105 ISDN TA"}, | ||
| 2126 | {}, | ||
| 2127 | }; | ||
| 2128 | |||
| 2129 | static struct pci_device_id hfc_ids[] = | ||
| 2130 | { | ||
| 2131 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_2BD0, | ||
| 2132 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[0]}, | ||
| 2133 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B000, | ||
| 2134 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[1]}, | ||
| 2135 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B006, | ||
| 2136 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[2]}, | ||
| 2137 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B007, | ||
| 2138 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[3]}, | ||
| 2139 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B008, | ||
| 2140 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[4]}, | ||
| 2141 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B009, | ||
| 2142 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[5]}, | ||
| 2143 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00A, | ||
| 2144 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[6]}, | ||
| 2145 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00B, | ||
| 2146 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[7]}, | ||
| 2147 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00C, | ||
| 2148 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[8]}, | ||
| 2149 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B100, | ||
| 2150 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[9]}, | ||
| 2151 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B700, | ||
| 2152 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[10]}, | ||
| 2153 | {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B701, | ||
| 2154 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[11]}, | ||
| 2155 | {PCI_VENDOR_ID_ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1, | ||
| 2156 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[12]}, | ||
| 2157 | {PCI_VENDOR_ID_ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675, | ||
| 2158 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[13]}, | ||
| 2159 | {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT, | ||
| 2160 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[14]}, | ||
| 2161 | {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_A1T, | ||
| 2162 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[15]}, | ||
| 2163 | {PCI_VENDOR_ID_ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575, | ||
| 2164 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[16]}, | ||
| 2165 | {PCI_VENDOR_ID_ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0, | ||
| 2166 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[17]}, | ||
| 2167 | {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E, | ||
| 2168 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[18]}, | ||
| 2169 | {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E, | ||
| 2170 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[19]}, | ||
| 2171 | {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A, | ||
| 2172 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[20]}, | ||
| 2173 | {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A, | ||
| 2174 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[21]}, | ||
| 2175 | {PCI_VENDOR_ID_SITECOM, PCI_DEVICE_ID_SITECOM_DC105V2, | ||
| 2176 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &hfc_map[22]}, | ||
| 2177 | {}, | ||
| 2178 | }; | ||
| 2179 | |||
| 2180 | static int __devinit | ||
| 2181 | hfc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
| 2182 | { | ||
| 2183 | int err = -ENOMEM; | ||
| 2184 | struct hfc_pci *card; | ||
| 2185 | struct _hfc_map *m = (struct _hfc_map *)ent->driver_data; | ||
| 2186 | |||
| 2187 | card = kzalloc(sizeof(struct hfc_pci), GFP_ATOMIC); | ||
| 2188 | if (!card) { | ||
| 2189 | printk(KERN_ERR "No kmem for HFC card\n"); | ||
| 2190 | return err; | ||
| 2191 | } | ||
| 2192 | card->pdev = pdev; | ||
| 2193 | card->subtype = m->subtype; | ||
| 2194 | err = pci_enable_device(pdev); | ||
| 2195 | if (err) { | ||
| 2196 | kfree(card); | ||
| 2197 | return err; | ||
| 2198 | } | ||
| 2199 | |||
| 2200 | printk(KERN_INFO "mISDN_hfcpci: found adapter %s at %s\n", | ||
| 2201 | m->name, pci_name(pdev)); | ||
| 2202 | |||
| 2203 | card->irq = pdev->irq; | ||
| 2204 | pci_set_drvdata(pdev, card); | ||
| 2205 | err = setup_card(card); | ||
| 2206 | if (err) | ||
| 2207 | pci_set_drvdata(pdev, NULL); | ||
| 2208 | return err; | ||
| 2209 | } | ||
| 2210 | |||
| 2211 | static void __devexit | ||
| 2212 | hfc_remove_pci(struct pci_dev *pdev) | ||
| 2213 | { | ||
| 2214 | struct hfc_pci *card = pci_get_drvdata(pdev); | ||
| 2215 | u_long flags; | ||
| 2216 | |||
| 2217 | if (card) { | ||
| 2218 | write_lock_irqsave(&HFClock, flags); | ||
| 2219 | release_card(card); | ||
| 2220 | write_unlock_irqrestore(&HFClock, flags); | ||
| 2221 | } else | ||
| 2222 | if (debug) | ||
| 2223 | printk(KERN_WARNING "%s: drvdata allready removed\n", | ||
| 2224 | __func__); | ||
| 2225 | } | ||
| 2226 | |||
| 2227 | |||
| 2228 | static struct pci_driver hfc_driver = { | ||
| 2229 | .name = "hfcpci", | ||
| 2230 | .probe = hfc_probe, | ||
| 2231 | .remove = __devexit_p(hfc_remove_pci), | ||
| 2232 | .id_table = hfc_ids, | ||
| 2233 | }; | ||
| 2234 | |||
| 2235 | static int __init | ||
| 2236 | HFC_init(void) | ||
| 2237 | { | ||
| 2238 | int err; | ||
| 2239 | |||
| 2240 | err = pci_register_driver(&hfc_driver); | ||
| 2241 | return err; | ||
| 2242 | } | ||
| 2243 | |||
| 2244 | static void __exit | ||
| 2245 | HFC_cleanup(void) | ||
| 2246 | { | ||
| 2247 | struct hfc_pci *card, *next; | ||
| 2248 | |||
| 2249 | list_for_each_entry_safe(card, next, &HFClist, list) { | ||
| 2250 | release_card(card); | ||
| 2251 | } | ||
| 2252 | pci_unregister_driver(&hfc_driver); | ||
| 2253 | } | ||
| 2254 | |||
| 2255 | module_init(HFC_init); | ||
| 2256 | module_exit(HFC_cleanup); | ||
diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c index c0b4db2f8364..1925118122f8 100644 --- a/drivers/isdn/hisax/hisax_fcpcipnp.c +++ b/drivers/isdn/hisax/hisax_fcpcipnp.c | |||
| @@ -974,8 +974,6 @@ static struct pnp_driver fcpnp_driver = { | |||
| 974 | .remove = __devexit_p(fcpnp_remove), | 974 | .remove = __devexit_p(fcpnp_remove), |
| 975 | .id_table = fcpnp_ids, | 975 | .id_table = fcpnp_ids, |
| 976 | }; | 976 | }; |
| 977 | #else | ||
| 978 | static struct pnp_driver fcpnp_driver; | ||
| 979 | #endif | 977 | #endif |
| 980 | 978 | ||
| 981 | static void __devexit fcpci_remove(struct pci_dev *pdev) | 979 | static void __devexit fcpci_remove(struct pci_dev *pdev) |
diff --git a/drivers/isdn/mISDN/Kconfig b/drivers/isdn/mISDN/Kconfig new file mode 100644 index 000000000000..4938355c4072 --- /dev/null +++ b/drivers/isdn/mISDN/Kconfig | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | # | ||
| 2 | # modularer ISDN driver | ||
| 3 | # | ||
| 4 | |||
| 5 | menuconfig MISDN | ||
| 6 | tristate "Modular ISDN driver" | ||
| 7 | help | ||
| 8 | Enable support for the modular ISDN driver. | ||
| 9 | |||
| 10 | if MISDN != n | ||
| 11 | |||
| 12 | config MISDN_DSP | ||
| 13 | tristate "Digital Audio Processing of transparent data" | ||
| 14 | depends on MISDN | ||
| 15 | help | ||
| 16 | Enable support for digital audio processing capability. | ||
| 17 | This module may be used for special applications that require | ||
| 18 | cross connecting of bchannels, conferencing, dtmf decoding | ||
| 19 | echo cancelation, tone generation, and Blowfish encryption and | ||
| 20 | decryption. | ||
| 21 | It may use hardware features if available. | ||
| 22 | E.g. it is required for PBX4Linux. Go to http://isdn.eversberg.eu | ||
| 23 | and get more informations about this module and it's usage. | ||
| 24 | If unsure, say 'N'. | ||
| 25 | |||
| 26 | config MISDN_L1OIP | ||
| 27 | tristate "ISDN over IP tunnel" | ||
| 28 | depends on MISDN | ||
| 29 | help | ||
| 30 | Enable support for ISDN over IP tunnel. | ||
| 31 | |||
| 32 | It features: | ||
| 33 | - dynamic IP exchange, if one or both peers have dynamic IPs | ||
| 34 | - BRI (S0) and PRI (S2M) interface | ||
| 35 | - layer 1 control via network keepalive frames | ||
| 36 | - direct tunneling of physical interface via IP | ||
| 37 | |||
| 38 | NOTE: This protocol is called 'Layer 1 over IP' and is not | ||
| 39 | compatible with ISDNoIP (Agfeo) or TDMoIP. Protocol description is | ||
| 40 | provided in the source code. | ||
| 41 | |||
| 42 | source "drivers/isdn/hardware/mISDN/Kconfig" | ||
| 43 | |||
| 44 | endif #MISDN | ||
diff --git a/drivers/isdn/mISDN/Makefile b/drivers/isdn/mISDN/Makefile new file mode 100644 index 000000000000..1cb5e633cf75 --- /dev/null +++ b/drivers/isdn/mISDN/Makefile | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | # | ||
| 2 | # Makefile for the modular ISDN driver | ||
| 3 | # | ||
| 4 | |||
| 5 | obj-$(CONFIG_MISDN) += mISDN_core.o | ||
| 6 | obj-$(CONFIG_MISDN_DSP) += mISDN_dsp.o | ||
| 7 | obj-$(CONFIG_MISDN_L1OIP) += l1oip.o | ||
| 8 | |||
| 9 | # multi objects | ||
| 10 | |||
| 11 | mISDN_core-objs := core.o fsm.o socket.o hwchannel.o stack.o layer1.o layer2.o tei.o timerdev.o | ||
| 12 | mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_pipeline.o dsp_hwec.o | ||
| 13 | l1oip-objs := l1oip_core.o l1oip_codec.o | ||
diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c new file mode 100644 index 000000000000..33068177b7c9 --- /dev/null +++ b/drivers/isdn/mISDN/core.c | |||
| @@ -0,0 +1,244 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/types.h> | ||
| 16 | #include <linux/stddef.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/spinlock.h> | ||
| 19 | #include <linux/mISDNif.h> | ||
| 20 | #include "core.h" | ||
| 21 | |||
| 22 | static u_int debug; | ||
| 23 | |||
| 24 | MODULE_AUTHOR("Karsten Keil"); | ||
| 25 | MODULE_LICENSE("GPL"); | ||
| 26 | module_param(debug, uint, S_IRUGO | S_IWUSR); | ||
| 27 | |||
| 28 | static LIST_HEAD(devices); | ||
| 29 | DEFINE_RWLOCK(device_lock); | ||
| 30 | static u64 device_ids; | ||
| 31 | #define MAX_DEVICE_ID 63 | ||
| 32 | |||
| 33 | static LIST_HEAD(Bprotocols); | ||
| 34 | DEFINE_RWLOCK(bp_lock); | ||
| 35 | |||
| 36 | struct mISDNdevice | ||
| 37 | *get_mdevice(u_int id) | ||
| 38 | { | ||
| 39 | struct mISDNdevice *dev; | ||
| 40 | |||
| 41 | read_lock(&device_lock); | ||
| 42 | list_for_each_entry(dev, &devices, D.list) | ||
| 43 | if (dev->id == id) { | ||
| 44 | read_unlock(&device_lock); | ||
| 45 | return dev; | ||
| 46 | } | ||
| 47 | read_unlock(&device_lock); | ||
| 48 | return NULL; | ||
| 49 | } | ||
| 50 | |||
| 51 | int | ||
| 52 | get_mdevice_count(void) | ||
| 53 | { | ||
| 54 | struct mISDNdevice *dev; | ||
| 55 | int cnt = 0; | ||
| 56 | |||
| 57 | read_lock(&device_lock); | ||
| 58 | list_for_each_entry(dev, &devices, D.list) | ||
| 59 | cnt++; | ||
| 60 | read_unlock(&device_lock); | ||
| 61 | return cnt; | ||
| 62 | } | ||
| 63 | |||
| 64 | static int | ||
| 65 | get_free_devid(void) | ||
| 66 | { | ||
| 67 | u_int i; | ||
| 68 | |||
| 69 | for (i = 0; i <= MAX_DEVICE_ID; i++) | ||
| 70 | if (!test_and_set_bit(i, (u_long *)&device_ids)) | ||
| 71 | return i; | ||
| 72 | return -1; | ||
| 73 | } | ||
| 74 | |||
| 75 | int | ||
| 76 | mISDN_register_device(struct mISDNdevice *dev, char *name) | ||
| 77 | { | ||
| 78 | u_long flags; | ||
| 79 | int err; | ||
| 80 | |||
| 81 | dev->id = get_free_devid(); | ||
| 82 | if (dev->id < 0) | ||
| 83 | return -EBUSY; | ||
| 84 | if (name && name[0]) | ||
| 85 | strcpy(dev->name, name); | ||
| 86 | else | ||
| 87 | sprintf(dev->name, "mISDN%d", dev->id); | ||
| 88 | if (debug & DEBUG_CORE) | ||
| 89 | printk(KERN_DEBUG "mISDN_register %s %d\n", | ||
| 90 | dev->name, dev->id); | ||
| 91 | err = create_stack(dev); | ||
| 92 | if (err) | ||
| 93 | return err; | ||
| 94 | write_lock_irqsave(&device_lock, flags); | ||
| 95 | list_add_tail(&dev->D.list, &devices); | ||
| 96 | write_unlock_irqrestore(&device_lock, flags); | ||
| 97 | return 0; | ||
| 98 | } | ||
| 99 | EXPORT_SYMBOL(mISDN_register_device); | ||
| 100 | |||
| 101 | void | ||
| 102 | mISDN_unregister_device(struct mISDNdevice *dev) { | ||
| 103 | u_long flags; | ||
| 104 | |||
| 105 | if (debug & DEBUG_CORE) | ||
| 106 | printk(KERN_DEBUG "mISDN_unregister %s %d\n", | ||
| 107 | dev->name, dev->id); | ||
| 108 | write_lock_irqsave(&device_lock, flags); | ||
| 109 | list_del(&dev->D.list); | ||
| 110 | write_unlock_irqrestore(&device_lock, flags); | ||
| 111 | test_and_clear_bit(dev->id, (u_long *)&device_ids); | ||
| 112 | delete_stack(dev); | ||
| 113 | } | ||
| 114 | EXPORT_SYMBOL(mISDN_unregister_device); | ||
| 115 | |||
| 116 | u_int | ||
| 117 | get_all_Bprotocols(void) | ||
| 118 | { | ||
| 119 | struct Bprotocol *bp; | ||
| 120 | u_int m = 0; | ||
| 121 | |||
| 122 | read_lock(&bp_lock); | ||
| 123 | list_for_each_entry(bp, &Bprotocols, list) | ||
| 124 | m |= bp->Bprotocols; | ||
| 125 | read_unlock(&bp_lock); | ||
| 126 | return m; | ||
| 127 | } | ||
| 128 | |||
| 129 | struct Bprotocol * | ||
| 130 | get_Bprotocol4mask(u_int m) | ||
| 131 | { | ||
| 132 | struct Bprotocol *bp; | ||
| 133 | |||
| 134 | read_lock(&bp_lock); | ||
| 135 | list_for_each_entry(bp, &Bprotocols, list) | ||
| 136 | if (bp->Bprotocols & m) { | ||
| 137 | read_unlock(&bp_lock); | ||
| 138 | return bp; | ||
| 139 | } | ||
| 140 | read_unlock(&bp_lock); | ||
| 141 | return NULL; | ||
| 142 | } | ||
| 143 | |||
| 144 | struct Bprotocol * | ||
| 145 | get_Bprotocol4id(u_int id) | ||
| 146 | { | ||
| 147 | u_int m; | ||
| 148 | |||
| 149 | if (id < ISDN_P_B_START || id > 63) { | ||
| 150 | printk(KERN_WARNING "%s id not in range %d\n", | ||
| 151 | __func__, id); | ||
| 152 | return NULL; | ||
| 153 | } | ||
| 154 | m = 1 << (id & ISDN_P_B_MASK); | ||
| 155 | return get_Bprotocol4mask(m); | ||
| 156 | } | ||
| 157 | |||
| 158 | int | ||
| 159 | mISDN_register_Bprotocol(struct Bprotocol *bp) | ||
| 160 | { | ||
| 161 | u_long flags; | ||
| 162 | struct Bprotocol *old; | ||
| 163 | |||
| 164 | if (debug & DEBUG_CORE) | ||
| 165 | printk(KERN_DEBUG "%s: %s/%x\n", __func__, | ||
| 166 | bp->name, bp->Bprotocols); | ||
| 167 | old = get_Bprotocol4mask(bp->Bprotocols); | ||
| 168 | if (old) { | ||
| 169 | printk(KERN_WARNING | ||
| 170 | "register duplicate protocol old %s/%x new %s/%x\n", | ||
| 171 | old->name, old->Bprotocols, bp->name, bp->Bprotocols); | ||
| 172 | return -EBUSY; | ||
| 173 | } | ||
| 174 | write_lock_irqsave(&bp_lock, flags); | ||
| 175 | list_add_tail(&bp->list, &Bprotocols); | ||
| 176 | write_unlock_irqrestore(&bp_lock, flags); | ||
| 177 | return 0; | ||
| 178 | } | ||
| 179 | EXPORT_SYMBOL(mISDN_register_Bprotocol); | ||
| 180 | |||
| 181 | void | ||
| 182 | mISDN_unregister_Bprotocol(struct Bprotocol *bp) | ||
| 183 | { | ||
| 184 | u_long flags; | ||
| 185 | |||
| 186 | if (debug & DEBUG_CORE) | ||
| 187 | printk(KERN_DEBUG "%s: %s/%x\n", __func__, bp->name, | ||
| 188 | bp->Bprotocols); | ||
| 189 | write_lock_irqsave(&bp_lock, flags); | ||
| 190 | list_del(&bp->list); | ||
| 191 | write_unlock_irqrestore(&bp_lock, flags); | ||
| 192 | } | ||
| 193 | EXPORT_SYMBOL(mISDN_unregister_Bprotocol); | ||
| 194 | |||
| 195 | int | ||
| 196 | mISDNInit(void) | ||
| 197 | { | ||
| 198 | int err; | ||
| 199 | |||
| 200 | printk(KERN_INFO "Modular ISDN core version %d.%d.%d\n", | ||
| 201 | MISDN_MAJOR_VERSION, MISDN_MINOR_VERSION, MISDN_RELEASE); | ||
| 202 | mISDN_initstack(&debug); | ||
| 203 | err = mISDN_inittimer(&debug); | ||
| 204 | if (err) | ||
| 205 | goto error; | ||
| 206 | err = l1_init(&debug); | ||
| 207 | if (err) { | ||
| 208 | mISDN_timer_cleanup(); | ||
| 209 | goto error; | ||
| 210 | } | ||
| 211 | err = Isdnl2_Init(&debug); | ||
| 212 | if (err) { | ||
| 213 | mISDN_timer_cleanup(); | ||
| 214 | l1_cleanup(); | ||
| 215 | goto error; | ||
| 216 | } | ||
| 217 | err = misdn_sock_init(&debug); | ||
| 218 | if (err) { | ||
| 219 | mISDN_timer_cleanup(); | ||
| 220 | l1_cleanup(); | ||
| 221 | Isdnl2_cleanup(); | ||
| 222 | } | ||
| 223 | error: | ||
| 224 | return err; | ||
| 225 | } | ||
| 226 | |||
| 227 | void mISDN_cleanup(void) | ||
| 228 | { | ||
| 229 | misdn_sock_cleanup(); | ||
| 230 | mISDN_timer_cleanup(); | ||
| 231 | l1_cleanup(); | ||
| 232 | Isdnl2_cleanup(); | ||
| 233 | |||
| 234 | if (!list_empty(&devices)) | ||
| 235 | printk(KERN_ERR "%s devices still registered\n", __func__); | ||
| 236 | |||
| 237 | if (!list_empty(&Bprotocols)) | ||
| 238 | printk(KERN_ERR "%s Bprotocols still registered\n", __func__); | ||
| 239 | printk(KERN_DEBUG "mISDNcore unloaded\n"); | ||
| 240 | } | ||
| 241 | |||
| 242 | module_init(mISDNInit); | ||
| 243 | module_exit(mISDN_cleanup); | ||
| 244 | |||
diff --git a/drivers/isdn/mISDN/core.h b/drivers/isdn/mISDN/core.h new file mode 100644 index 000000000000..7da7233b4c1a --- /dev/null +++ b/drivers/isdn/mISDN/core.h | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | */ | ||
| 14 | |||
| 15 | #ifndef mISDN_CORE_H | ||
| 16 | #define mISDN_CORE_H | ||
| 17 | |||
| 18 | extern struct mISDNdevice *get_mdevice(u_int); | ||
| 19 | extern int get_mdevice_count(void); | ||
| 20 | |||
| 21 | /* stack status flag */ | ||
| 22 | #define mISDN_STACK_ACTION_MASK 0x0000ffff | ||
| 23 | #define mISDN_STACK_COMMAND_MASK 0x000f0000 | ||
| 24 | #define mISDN_STACK_STATUS_MASK 0xfff00000 | ||
| 25 | /* action bits 0-15 */ | ||
| 26 | #define mISDN_STACK_WORK 0 | ||
| 27 | #define mISDN_STACK_SETUP 1 | ||
| 28 | #define mISDN_STACK_CLEARING 2 | ||
| 29 | #define mISDN_STACK_RESTART 3 | ||
| 30 | #define mISDN_STACK_WAKEUP 4 | ||
| 31 | #define mISDN_STACK_ABORT 15 | ||
| 32 | /* command bits 16-19 */ | ||
| 33 | #define mISDN_STACK_STOPPED 16 | ||
| 34 | #define mISDN_STACK_INIT 17 | ||
| 35 | #define mISDN_STACK_THREADSTART 18 | ||
| 36 | /* status bits 20-31 */ | ||
| 37 | #define mISDN_STACK_BCHANNEL 20 | ||
| 38 | #define mISDN_STACK_ACTIVE 29 | ||
| 39 | #define mISDN_STACK_RUNNING 30 | ||
| 40 | #define mISDN_STACK_KILLED 31 | ||
| 41 | |||
| 42 | |||
| 43 | /* manager options */ | ||
| 44 | #define MGR_OPT_USER 24 | ||
| 45 | #define MGR_OPT_NETWORK 25 | ||
| 46 | |||
| 47 | extern int connect_Bstack(struct mISDNdevice *, struct mISDNchannel *, | ||
| 48 | u_int, struct sockaddr_mISDN *); | ||
| 49 | extern int connect_layer1(struct mISDNdevice *, struct mISDNchannel *, | ||
| 50 | u_int, struct sockaddr_mISDN *); | ||
| 51 | extern int create_l2entity(struct mISDNdevice *, struct mISDNchannel *, | ||
| 52 | u_int, struct sockaddr_mISDN *); | ||
| 53 | |||
| 54 | extern int create_stack(struct mISDNdevice *); | ||
| 55 | extern int create_teimanager(struct mISDNdevice *); | ||
| 56 | extern void delete_teimanager(struct mISDNchannel *); | ||
| 57 | extern void delete_channel(struct mISDNchannel *); | ||
| 58 | extern void delete_stack(struct mISDNdevice *); | ||
| 59 | extern void mISDN_initstack(u_int *); | ||
| 60 | extern int misdn_sock_init(u_int *); | ||
| 61 | extern void misdn_sock_cleanup(void); | ||
| 62 | extern void add_layer2(struct mISDNchannel *, struct mISDNstack *); | ||
| 63 | extern void __add_layer2(struct mISDNchannel *, struct mISDNstack *); | ||
| 64 | |||
| 65 | extern u_int get_all_Bprotocols(void); | ||
| 66 | struct Bprotocol *get_Bprotocol4mask(u_int); | ||
| 67 | struct Bprotocol *get_Bprotocol4id(u_int); | ||
| 68 | |||
| 69 | extern int mISDN_inittimer(u_int *); | ||
| 70 | extern void mISDN_timer_cleanup(void); | ||
| 71 | |||
| 72 | extern int l1_init(u_int *); | ||
| 73 | extern void l1_cleanup(void); | ||
| 74 | extern int Isdnl2_Init(u_int *); | ||
| 75 | extern void Isdnl2_cleanup(void); | ||
| 76 | |||
| 77 | #endif | ||
diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h new file mode 100644 index 000000000000..6c3fed6b8d4f --- /dev/null +++ b/drivers/isdn/mISDN/dsp.h | |||
| @@ -0,0 +1,263 @@ | |||
| 1 | /* | ||
| 2 | * Audio support data for ISDN4Linux. | ||
| 3 | * | ||
| 4 | * Copyright 2002/2003 by Andreas Eversberg (jolly@eversberg.eu) | ||
| 5 | * | ||
| 6 | * This software may be used and distributed according to the terms | ||
| 7 | * of the GNU General Public License, incorporated herein by reference. | ||
| 8 | * | ||
| 9 | */ | ||
| 10 | |||
| 11 | #define DEBUG_DSP_CTRL 0x0001 | ||
| 12 | #define DEBUG_DSP_CORE 0x0002 | ||
| 13 | #define DEBUG_DSP_DTMF 0x0004 | ||
| 14 | #define DEBUG_DSP_CMX 0x0010 | ||
| 15 | #define DEBUG_DSP_TONE 0x0020 | ||
| 16 | #define DEBUG_DSP_BLOWFISH 0x0040 | ||
| 17 | #define DEBUG_DSP_DELAY 0x0100 | ||
| 18 | #define DEBUG_DSP_DTMFCOEFF 0x8000 /* heavy output */ | ||
| 19 | |||
| 20 | /* options may be: | ||
| 21 | * | ||
| 22 | * bit 0 = use ulaw instead of alaw | ||
| 23 | * bit 1 = enable hfc hardware accelleration for all channels | ||
| 24 | * | ||
| 25 | */ | ||
| 26 | #define DSP_OPT_ULAW (1<<0) | ||
| 27 | #define DSP_OPT_NOHARDWARE (1<<1) | ||
| 28 | |||
| 29 | #include <linux/timer.h> | ||
| 30 | #include <linux/workqueue.h> | ||
| 31 | |||
| 32 | #include "dsp_ecdis.h" | ||
| 33 | |||
| 34 | extern int dsp_options; | ||
| 35 | extern int dsp_debug; | ||
| 36 | extern int dsp_poll; | ||
| 37 | extern int dsp_tics; | ||
| 38 | extern spinlock_t dsp_lock; | ||
| 39 | extern struct work_struct dsp_workq; | ||
| 40 | extern u32 dsp_poll_diff; /* calculated fix-comma corrected poll value */ | ||
| 41 | |||
| 42 | /*************** | ||
| 43 | * audio stuff * | ||
| 44 | ***************/ | ||
| 45 | |||
| 46 | extern s32 dsp_audio_alaw_to_s32[256]; | ||
| 47 | extern s32 dsp_audio_ulaw_to_s32[256]; | ||
| 48 | extern s32 *dsp_audio_law_to_s32; | ||
| 49 | extern u8 dsp_audio_s16_to_law[65536]; | ||
| 50 | extern u8 dsp_audio_alaw_to_ulaw[256]; | ||
| 51 | extern u8 dsp_audio_mix_law[65536]; | ||
| 52 | extern u8 dsp_audio_seven2law[128]; | ||
| 53 | extern u8 dsp_audio_law2seven[256]; | ||
| 54 | extern void dsp_audio_generate_law_tables(void); | ||
| 55 | extern void dsp_audio_generate_s2law_table(void); | ||
| 56 | extern void dsp_audio_generate_seven(void); | ||
| 57 | extern void dsp_audio_generate_mix_table(void); | ||
| 58 | extern void dsp_audio_generate_ulaw_samples(void); | ||
| 59 | extern void dsp_audio_generate_volume_changes(void); | ||
| 60 | extern u8 dsp_silence; | ||
| 61 | |||
| 62 | |||
| 63 | /************* | ||
| 64 | * cmx stuff * | ||
| 65 | *************/ | ||
| 66 | |||
| 67 | #define MAX_POLL 256 /* maximum number of send-chunks */ | ||
| 68 | |||
| 69 | #define CMX_BUFF_SIZE 0x8000 /* must be 2**n (0x1000 about 1/2 second) */ | ||
| 70 | #define CMX_BUFF_HALF 0x4000 /* CMX_BUFF_SIZE / 2 */ | ||
| 71 | #define CMX_BUFF_MASK 0x7fff /* CMX_BUFF_SIZE - 1 */ | ||
| 72 | |||
| 73 | /* how many seconds will we check the lowest delay until the jitter buffer | ||
| 74 | is reduced by that delay */ | ||
| 75 | #define MAX_SECONDS_JITTER_CHECK 5 | ||
| 76 | |||
| 77 | extern struct timer_list dsp_spl_tl; | ||
| 78 | extern u32 dsp_spl_jiffies; | ||
| 79 | |||
| 80 | /* the structure of conferences: | ||
| 81 | * | ||
| 82 | * each conference has a unique number, given by user space. | ||
| 83 | * the conferences are linked in a chain. | ||
| 84 | * each conference has members linked in a chain. | ||
| 85 | * each dsplayer points to a member, each member points to a dsplayer. | ||
| 86 | */ | ||
| 87 | |||
| 88 | /* all members within a conference (this is linked 1:1 with the dsp) */ | ||
| 89 | struct dsp; | ||
| 90 | struct dsp_conf_member { | ||
| 91 | struct list_head list; | ||
| 92 | struct dsp *dsp; | ||
| 93 | }; | ||
| 94 | |||
| 95 | /* the list of all conferences */ | ||
| 96 | struct dsp_conf { | ||
| 97 | struct list_head list; | ||
| 98 | u32 id; | ||
| 99 | /* all cmx stacks with the same ID are | ||
| 100 | connected */ | ||
| 101 | struct list_head mlist; | ||
| 102 | int software; /* conf is processed by software */ | ||
| 103 | int hardware; /* conf is processed by hardware */ | ||
| 104 | /* note: if both unset, has only one member */ | ||
| 105 | }; | ||
| 106 | |||
| 107 | |||
| 108 | /************** | ||
| 109 | * DTMF stuff * | ||
| 110 | **************/ | ||
| 111 | |||
| 112 | #define DSP_DTMF_NPOINTS 102 | ||
| 113 | |||
| 114 | #define ECHOCAN_BUFLEN (4*128) | ||
| 115 | |||
| 116 | struct dsp_dtmf { | ||
| 117 | int treshold; /* above this is dtmf (square of) */ | ||
| 118 | int software; /* dtmf uses software decoding */ | ||
| 119 | int hardware; /* dtmf uses hardware decoding */ | ||
| 120 | int size; /* number of bytes in buffer */ | ||
| 121 | signed short buffer[DSP_DTMF_NPOINTS]; | ||
| 122 | /* buffers one full dtmf frame */ | ||
| 123 | u8 lastwhat, lastdigit; | ||
| 124 | int count; | ||
| 125 | u8 digits[16]; /* just the dtmf result */ | ||
| 126 | }; | ||
| 127 | |||
| 128 | |||
| 129 | /****************** | ||
| 130 | * pipeline stuff * | ||
| 131 | ******************/ | ||
| 132 | struct dsp_pipeline { | ||
| 133 | rwlock_t lock; | ||
| 134 | struct list_head list; | ||
| 135 | int inuse; | ||
| 136 | }; | ||
| 137 | |||
| 138 | /*************** | ||
| 139 | * tones stuff * | ||
| 140 | ***************/ | ||
| 141 | |||
| 142 | struct dsp_tone { | ||
| 143 | int software; /* tones are generated by software */ | ||
| 144 | int hardware; /* tones are generated by hardware */ | ||
| 145 | int tone; | ||
| 146 | void *pattern; | ||
| 147 | int count; | ||
| 148 | int index; | ||
| 149 | struct timer_list tl; | ||
| 150 | }; | ||
| 151 | |||
| 152 | /***************** | ||
| 153 | * general stuff * | ||
| 154 | *****************/ | ||
| 155 | |||
| 156 | struct dsp { | ||
| 157 | struct list_head list; | ||
| 158 | struct mISDNchannel ch; | ||
| 159 | struct mISDNchannel *up; | ||
| 160 | unsigned char name[64]; | ||
| 161 | int b_active; | ||
| 162 | int echo; /* echo is enabled */ | ||
| 163 | int rx_disabled; /* what the user wants */ | ||
| 164 | int rx_is_off; /* what the card is */ | ||
| 165 | int tx_mix; | ||
| 166 | struct dsp_tone tone; | ||
| 167 | struct dsp_dtmf dtmf; | ||
| 168 | int tx_volume, rx_volume; | ||
| 169 | |||
| 170 | /* queue for sending frames */ | ||
| 171 | struct work_struct workq; | ||
| 172 | struct sk_buff_head sendq; | ||
| 173 | int hdlc; /* if mode is hdlc */ | ||
| 174 | int data_pending; /* currently an unconfirmed frame */ | ||
| 175 | |||
| 176 | /* conference stuff */ | ||
| 177 | u32 conf_id; | ||
| 178 | struct dsp_conf *conf; | ||
| 179 | struct dsp_conf_member | ||
| 180 | *member; | ||
| 181 | |||
| 182 | /* buffer stuff */ | ||
| 183 | int rx_W; /* current write pos for data without timestamp */ | ||
| 184 | int rx_R; /* current read pos for transmit clock */ | ||
| 185 | int rx_init; /* if set, pointers will be adjusted first */ | ||
| 186 | int tx_W; /* current write pos for transmit data */ | ||
| 187 | int tx_R; /* current read pos for transmit clock */ | ||
| 188 | int rx_delay[MAX_SECONDS_JITTER_CHECK]; | ||
| 189 | int tx_delay[MAX_SECONDS_JITTER_CHECK]; | ||
| 190 | u8 tx_buff[CMX_BUFF_SIZE]; | ||
| 191 | u8 rx_buff[CMX_BUFF_SIZE]; | ||
| 192 | int last_tx; /* if set, we transmitted last poll interval */ | ||
| 193 | int cmx_delay; /* initial delay of buffers, | ||
| 194 | or 0 for dynamic jitter buffer */ | ||
| 195 | int tx_dejitter; /* if set, dejitter tx buffer */ | ||
| 196 | int tx_data; /* enables tx-data of CMX to upper layer */ | ||
| 197 | |||
| 198 | /* hardware stuff */ | ||
| 199 | struct dsp_features features; | ||
| 200 | int features_rx_off; /* set if rx_off is featured */ | ||
| 201 | int pcm_slot_rx; /* current PCM slot (or -1) */ | ||
| 202 | int pcm_bank_rx; | ||
| 203 | int pcm_slot_tx; | ||
| 204 | int pcm_bank_tx; | ||
| 205 | int hfc_conf; /* unique id of current conference (or -1) */ | ||
| 206 | |||
| 207 | /* encryption stuff */ | ||
| 208 | int bf_enable; | ||
| 209 | u32 bf_p[18]; | ||
| 210 | u32 bf_s[1024]; | ||
| 211 | int bf_crypt_pos; | ||
| 212 | u8 bf_data_in[9]; | ||
| 213 | u8 bf_crypt_out[9]; | ||
| 214 | int bf_decrypt_in_pos; | ||
| 215 | int bf_decrypt_out_pos; | ||
| 216 | u8 bf_crypt_inring[16]; | ||
| 217 | u8 bf_data_out[9]; | ||
| 218 | int bf_sync; | ||
| 219 | |||
| 220 | struct dsp_pipeline | ||
| 221 | pipeline; | ||
| 222 | }; | ||
| 223 | |||
| 224 | /* functions */ | ||
| 225 | |||
| 226 | extern void dsp_change_volume(struct sk_buff *skb, int volume); | ||
| 227 | |||
| 228 | extern struct list_head dsp_ilist; | ||
| 229 | extern struct list_head conf_ilist; | ||
| 230 | extern void dsp_cmx_debug(struct dsp *dsp); | ||
| 231 | extern void dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp); | ||
| 232 | extern int dsp_cmx_conf(struct dsp *dsp, u32 conf_id); | ||
| 233 | extern void dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb); | ||
| 234 | extern void dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb); | ||
| 235 | extern void dsp_cmx_send(void *arg); | ||
| 236 | extern void dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb); | ||
| 237 | extern int dsp_cmx_del_conf_member(struct dsp *dsp); | ||
| 238 | extern int dsp_cmx_del_conf(struct dsp_conf *conf); | ||
| 239 | |||
| 240 | extern void dsp_dtmf_goertzel_init(struct dsp *dsp); | ||
| 241 | extern void dsp_dtmf_hardware(struct dsp *dsp); | ||
| 242 | extern u8 *dsp_dtmf_goertzel_decode(struct dsp *dsp, u8 *data, int len, | ||
| 243 | int fmt); | ||
| 244 | |||
| 245 | extern int dsp_tone(struct dsp *dsp, int tone); | ||
| 246 | extern void dsp_tone_copy(struct dsp *dsp, u8 *data, int len); | ||
| 247 | extern void dsp_tone_timeout(void *arg); | ||
| 248 | |||
| 249 | extern void dsp_bf_encrypt(struct dsp *dsp, u8 *data, int len); | ||
| 250 | extern void dsp_bf_decrypt(struct dsp *dsp, u8 *data, int len); | ||
| 251 | extern int dsp_bf_init(struct dsp *dsp, const u8 *key, unsigned int keylen); | ||
| 252 | extern void dsp_bf_cleanup(struct dsp *dsp); | ||
| 253 | |||
| 254 | extern int dsp_pipeline_module_init(void); | ||
| 255 | extern void dsp_pipeline_module_exit(void); | ||
| 256 | extern int dsp_pipeline_init(struct dsp_pipeline *pipeline); | ||
| 257 | extern void dsp_pipeline_destroy(struct dsp_pipeline *pipeline); | ||
| 258 | extern int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg); | ||
| 259 | extern void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, | ||
| 260 | int len); | ||
| 261 | extern void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, | ||
| 262 | int len); | ||
| 263 | |||
diff --git a/drivers/isdn/mISDN/dsp_audio.c b/drivers/isdn/mISDN/dsp_audio.c new file mode 100644 index 000000000000..1c2dd5694773 --- /dev/null +++ b/drivers/isdn/mISDN/dsp_audio.c | |||
| @@ -0,0 +1,434 @@ | |||
| 1 | /* | ||
| 2 | * Audio support data for mISDN_dsp. | ||
| 3 | * | ||
| 4 | * Copyright 2002/2003 by Andreas Eversberg (jolly@eversberg.eu) | ||
| 5 | * Rewritten by Peter | ||
| 6 | * | ||
| 7 | * This software may be used and distributed according to the terms | ||
| 8 | * of the GNU General Public License, incorporated herein by reference. | ||
| 9 | * | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/delay.h> | ||
| 13 | #include <linux/mISDNif.h> | ||
| 14 | #include <linux/mISDNdsp.h> | ||
| 15 | #include "core.h" | ||
| 16 | #include "dsp.h" | ||
| 17 | |||
| 18 | /* ulaw[unsigned char] -> signed 16-bit */ | ||
| 19 | s32 dsp_audio_ulaw_to_s32[256]; | ||
| 20 | /* alaw[unsigned char] -> signed 16-bit */ | ||
| 21 | s32 dsp_audio_alaw_to_s32[256]; | ||
| 22 | |||
| 23 | s32 *dsp_audio_law_to_s32; | ||
| 24 | EXPORT_SYMBOL(dsp_audio_law_to_s32); | ||
| 25 | |||
| 26 | /* signed 16-bit -> law */ | ||
| 27 | u8 dsp_audio_s16_to_law[65536]; | ||
| 28 | EXPORT_SYMBOL(dsp_audio_s16_to_law); | ||
| 29 | |||
| 30 | /* alaw -> ulaw */ | ||
| 31 | u8 dsp_audio_alaw_to_ulaw[256]; | ||
| 32 | /* ulaw -> alaw */ | ||
| 33 | u8 dsp_audio_ulaw_to_alaw[256]; | ||
| 34 | u8 dsp_silence; | ||
| 35 | |||
| 36 | |||
| 37 | /***************************************************** | ||
| 38 | * generate table for conversion of s16 to alaw/ulaw * | ||
| 39 | *****************************************************/ | ||
| 40 | |||
| 41 | #define AMI_MASK 0x55 | ||
| 42 | |||
| 43 | static inline unsigned char linear2alaw(short int linear) | ||
| 44 | { | ||
| 45 | int mask; | ||
| 46 | int seg; | ||
| 47 | int pcm_val; | ||
| 48 | static int seg_end[8] = { | ||
| 49 | 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF | ||
| 50 | }; | ||
| 51 | |||
| 52 | pcm_val = linear; | ||
| 53 | if (pcm_val >= 0) { | ||
| 54 | /* Sign (7th) bit = 1 */ | ||
| 55 | mask = AMI_MASK | 0x80; | ||
| 56 | } else { | ||
| 57 | /* Sign bit = 0 */ | ||
| 58 | mask = AMI_MASK; | ||
| 59 | pcm_val = -pcm_val; | ||
| 60 | } | ||
| 61 | |||
| 62 | /* Convert the scaled magnitude to segment number. */ | ||
| 63 | for (seg = 0; seg < 8; seg++) { | ||
| 64 | if (pcm_val <= seg_end[seg]) | ||
| 65 | break; | ||
| 66 | } | ||
| 67 | /* Combine the sign, segment, and quantization bits. */ | ||
| 68 | return ((seg << 4) | | ||
| 69 | ((pcm_val >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask; | ||
| 70 | } | ||
| 71 | |||
| 72 | |||
| 73 | static inline short int alaw2linear(unsigned char alaw) | ||
| 74 | { | ||
| 75 | int i; | ||
| 76 | int seg; | ||
| 77 | |||
| 78 | alaw ^= AMI_MASK; | ||
| 79 | i = ((alaw & 0x0F) << 4) + 8 /* rounding error */; | ||
| 80 | seg = (((int) alaw & 0x70) >> 4); | ||
| 81 | if (seg) | ||
| 82 | i = (i + 0x100) << (seg - 1); | ||
| 83 | return (short int) ((alaw & 0x80) ? i : -i); | ||
| 84 | } | ||
| 85 | |||
| 86 | static inline short int ulaw2linear(unsigned char ulaw) | ||
| 87 | { | ||
| 88 | short mu, e, f, y; | ||
| 89 | static short etab[] = {0, 132, 396, 924, 1980, 4092, 8316, 16764}; | ||
| 90 | |||
| 91 | mu = 255 - ulaw; | ||
| 92 | e = (mu & 0x70) / 16; | ||
| 93 | f = mu & 0x0f; | ||
| 94 | y = f * (1 << (e + 3)); | ||
| 95 | y += etab[e]; | ||
| 96 | if (mu & 0x80) | ||
| 97 | y = -y; | ||
| 98 | return y; | ||
| 99 | } | ||
| 100 | |||
| 101 | #define BIAS 0x84 /*!< define the add-in bias for 16 bit samples */ | ||
| 102 | |||
| 103 | static unsigned char linear2ulaw(short sample) | ||
| 104 | { | ||
| 105 | static int exp_lut[256] = { | ||
| 106 | 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, | ||
| 107 | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, | ||
| 108 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, | ||
| 109 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, | ||
| 110 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | ||
| 111 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | ||
| 112 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | ||
| 113 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | ||
| 114 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
| 115 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
| 116 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
| 117 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
| 118 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
| 119 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
| 120 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
| 121 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; | ||
| 122 | int sign, exponent, mantissa; | ||
| 123 | unsigned char ulawbyte; | ||
| 124 | |||
| 125 | /* Get the sample into sign-magnitude. */ | ||
| 126 | sign = (sample >> 8) & 0x80; /* set aside the sign */ | ||
| 127 | if (sign != 0) | ||
| 128 | sample = -sample; /* get magnitude */ | ||
| 129 | |||
| 130 | /* Convert from 16 bit linear to ulaw. */ | ||
| 131 | sample = sample + BIAS; | ||
| 132 | exponent = exp_lut[(sample >> 7) & 0xFF]; | ||
| 133 | mantissa = (sample >> (exponent + 3)) & 0x0F; | ||
| 134 | ulawbyte = ~(sign | (exponent << 4) | mantissa); | ||
| 135 | |||
| 136 | return ulawbyte; | ||
| 137 | } | ||
| 138 | |||
| 139 | static int reverse_bits(int i) | ||
| 140 | { | ||
| 141 | int z, j; | ||
| 142 | z = 0; | ||
| 143 | |||
| 144 | for (j = 0; j < 8; j++) { | ||
| 145 | if ((i & (1 << j)) != 0) | ||
| 146 | z |= 1 << (7 - j); | ||
| 147 | } | ||
| 148 | return z; | ||
| 149 | } | ||
| 150 | |||
| 151 | |||
| 152 | void dsp_audio_generate_law_tables(void) | ||
| 153 | { | ||
| 154 | int i; | ||
| 155 | for (i = 0; i < 256; i++) | ||
| 156 | dsp_audio_alaw_to_s32[i] = alaw2linear(reverse_bits(i)); | ||
| 157 | |||
| 158 | for (i = 0; i < 256; i++) | ||
| 159 | dsp_audio_ulaw_to_s32[i] = ulaw2linear(reverse_bits(i)); | ||
| 160 | |||
| 161 | for (i = 0; i < 256; i++) { | ||
| 162 | dsp_audio_alaw_to_ulaw[i] = | ||
| 163 | linear2ulaw(dsp_audio_alaw_to_s32[i]); | ||
| 164 | dsp_audio_ulaw_to_alaw[i] = | ||
| 165 | linear2alaw(dsp_audio_ulaw_to_s32[i]); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | void | ||
| 170 | dsp_audio_generate_s2law_table(void) | ||
| 171 | { | ||
| 172 | int i; | ||
| 173 | |||
| 174 | if (dsp_options & DSP_OPT_ULAW) { | ||
| 175 | /* generating ulaw-table */ | ||
| 176 | for (i = -32768; i < 32768; i++) { | ||
| 177 | dsp_audio_s16_to_law[i & 0xffff] = | ||
| 178 | reverse_bits(linear2ulaw(i)); | ||
| 179 | } | ||
| 180 | } else { | ||
| 181 | /* generating alaw-table */ | ||
| 182 | for (i = -32768; i < 32768; i++) { | ||
| 183 | dsp_audio_s16_to_law[i & 0xffff] = | ||
| 184 | reverse_bits(linear2alaw(i)); | ||
| 185 | } | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | |||
| 190 | /* | ||
| 191 | * the seven bit sample is the number of every second alaw-sample ordered by | ||
| 192 | * aplitude. 0x00 is negative, 0x7f is positive amplitude. | ||
| 193 | */ | ||
| 194 | u8 dsp_audio_seven2law[128]; | ||
| 195 | u8 dsp_audio_law2seven[256]; | ||
| 196 | |||
| 197 | /******************************************************************** | ||
| 198 | * generate table for conversion law from/to 7-bit alaw-like sample * | ||
| 199 | ********************************************************************/ | ||
| 200 | |||
| 201 | void | ||
| 202 | dsp_audio_generate_seven(void) | ||
| 203 | { | ||
| 204 | int i, j, k; | ||
| 205 | u8 spl; | ||
| 206 | u8 sorted_alaw[256]; | ||
| 207 | |||
| 208 | /* generate alaw table, sorted by the linear value */ | ||
| 209 | for (i = 0; i < 256; i++) { | ||
| 210 | j = 0; | ||
| 211 | for (k = 0; k < 256; k++) { | ||
| 212 | if (dsp_audio_alaw_to_s32[k] | ||
| 213 | < dsp_audio_alaw_to_s32[i]) { | ||
| 214 | j++; | ||
| 215 | } | ||
| 216 | } | ||
| 217 | sorted_alaw[j] = i; | ||
| 218 | } | ||
| 219 | |||
| 220 | /* generate tabels */ | ||
| 221 | for (i = 0; i < 256; i++) { | ||
| 222 | /* spl is the source: the law-sample (converted to alaw) */ | ||
| 223 | spl = i; | ||
| 224 | if (dsp_options & DSP_OPT_ULAW) | ||
| 225 | spl = dsp_audio_ulaw_to_alaw[i]; | ||
| 226 | /* find the 7-bit-sample */ | ||
| 227 | for (j = 0; j < 256; j++) { | ||
| 228 | if (sorted_alaw[j] == spl) | ||
| 229 | break; | ||
| 230 | } | ||
| 231 | /* write 7-bit audio value */ | ||
| 232 | dsp_audio_law2seven[i] = j >> 1; | ||
| 233 | } | ||
| 234 | for (i = 0; i < 128; i++) { | ||
| 235 | spl = sorted_alaw[i << 1]; | ||
| 236 | if (dsp_options & DSP_OPT_ULAW) | ||
| 237 | spl = dsp_audio_alaw_to_ulaw[spl]; | ||
| 238 | dsp_audio_seven2law[i] = spl; | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | |||
| 243 | /* mix 2*law -> law */ | ||
| 244 | u8 dsp_audio_mix_law[65536]; | ||
| 245 | |||
| 246 | /****************************************************** | ||
| 247 | * generate mix table to mix two law samples into one * | ||
| 248 | ******************************************************/ | ||
| 249 | |||
| 250 | void | ||
| 251 | dsp_audio_generate_mix_table(void) | ||
| 252 | { | ||
| 253 | int i, j; | ||
| 254 | s32 sample; | ||
| 255 | |||
| 256 | i = 0; | ||
| 257 | while (i < 256) { | ||
| 258 | j = 0; | ||
| 259 | while (j < 256) { | ||
| 260 | sample = dsp_audio_law_to_s32[i]; | ||
| 261 | sample += dsp_audio_law_to_s32[j]; | ||
| 262 | if (sample > 32767) | ||
| 263 | sample = 32767; | ||
| 264 | if (sample < -32768) | ||
| 265 | sample = -32768; | ||
| 266 | dsp_audio_mix_law[(i<<8)|j] = | ||
| 267 | dsp_audio_s16_to_law[sample & 0xffff]; | ||
| 268 | j++; | ||
| 269 | } | ||
| 270 | i++; | ||
| 271 | } | ||
| 272 | } | ||
| 273 | |||
| 274 | |||
| 275 | /************************************* | ||
| 276 | * generate different volume changes * | ||
| 277 | *************************************/ | ||
| 278 | |||
| 279 | static u8 dsp_audio_reduce8[256]; | ||
| 280 | static u8 dsp_audio_reduce7[256]; | ||
| 281 | static u8 dsp_audio_reduce6[256]; | ||
| 282 | static u8 dsp_audio_reduce5[256]; | ||
| 283 | static u8 dsp_audio_reduce4[256]; | ||
| 284 | static u8 dsp_audio_reduce3[256]; | ||
| 285 | static u8 dsp_audio_reduce2[256]; | ||
| 286 | static u8 dsp_audio_reduce1[256]; | ||
| 287 | static u8 dsp_audio_increase1[256]; | ||
| 288 | static u8 dsp_audio_increase2[256]; | ||
| 289 | static u8 dsp_audio_increase3[256]; | ||
| 290 | static u8 dsp_audio_increase4[256]; | ||
| 291 | static u8 dsp_audio_increase5[256]; | ||
| 292 | static u8 dsp_audio_increase6[256]; | ||
| 293 | static u8 dsp_audio_increase7[256]; | ||
| 294 | static u8 dsp_audio_increase8[256]; | ||
| 295 | |||
| 296 | static u8 *dsp_audio_volume_change[16] = { | ||
| 297 | dsp_audio_reduce8, | ||
| 298 | dsp_audio_reduce7, | ||
| 299 | dsp_audio_reduce6, | ||
| 300 | dsp_audio_reduce5, | ||
| 301 | dsp_audio_reduce4, | ||
| 302 | dsp_audio_reduce3, | ||
| 303 | dsp_audio_reduce2, | ||
| 304 | dsp_audio_reduce1, | ||
| 305 | dsp_audio_increase1, | ||
| 306 | dsp_audio_increase2, | ||
| 307 | dsp_audio_increase3, | ||
| 308 | dsp_audio_increase4, | ||
| 309 | dsp_audio_increase5, | ||
| 310 | dsp_audio_increase6, | ||
| 311 | dsp_audio_increase7, | ||
| 312 | dsp_audio_increase8, | ||
| 313 | }; | ||
| 314 | |||
| 315 | void | ||
| 316 | dsp_audio_generate_volume_changes(void) | ||
| 317 | { | ||
| 318 | register s32 sample; | ||
| 319 | int i; | ||
| 320 | int num[] = { 110, 125, 150, 175, 200, 300, 400, 500 }; | ||
| 321 | int denum[] = { 100, 100, 100, 100, 100, 100, 100, 100 }; | ||
| 322 | |||
| 323 | i = 0; | ||
| 324 | while (i < 256) { | ||
| 325 | dsp_audio_reduce8[i] = dsp_audio_s16_to_law[ | ||
| 326 | (dsp_audio_law_to_s32[i] * denum[7] / num[7]) & 0xffff]; | ||
| 327 | dsp_audio_reduce7[i] = dsp_audio_s16_to_law[ | ||
| 328 | (dsp_audio_law_to_s32[i] * denum[6] / num[6]) & 0xffff]; | ||
| 329 | dsp_audio_reduce6[i] = dsp_audio_s16_to_law[ | ||
| 330 | (dsp_audio_law_to_s32[i] * denum[5] / num[5]) & 0xffff]; | ||
| 331 | dsp_audio_reduce5[i] = dsp_audio_s16_to_law[ | ||
| 332 | (dsp_audio_law_to_s32[i] * denum[4] / num[4]) & 0xffff]; | ||
| 333 | dsp_audio_reduce4[i] = dsp_audio_s16_to_law[ | ||
| 334 | (dsp_audio_law_to_s32[i] * denum[3] / num[3]) & 0xffff]; | ||
| 335 | dsp_audio_reduce3[i] = dsp_audio_s16_to_law[ | ||
| 336 | (dsp_audio_law_to_s32[i] * denum[2] / num[2]) & 0xffff]; | ||
| 337 | dsp_audio_reduce2[i] = dsp_audio_s16_to_law[ | ||
| 338 | (dsp_audio_law_to_s32[i] * denum[1] / num[1]) & 0xffff]; | ||
| 339 | dsp_audio_reduce1[i] = dsp_audio_s16_to_law[ | ||
| 340 | (dsp_audio_law_to_s32[i] * denum[0] / num[0]) & 0xffff]; | ||
| 341 | sample = dsp_audio_law_to_s32[i] * num[0] / denum[0]; | ||
| 342 | if (sample < -32768) | ||
| 343 | sample = -32768; | ||
| 344 | else if (sample > 32767) | ||
| 345 | sample = 32767; | ||
| 346 | dsp_audio_increase1[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
| 347 | sample = dsp_audio_law_to_s32[i] * num[1] / denum[1]; | ||
| 348 | if (sample < -32768) | ||
| 349 | sample = -32768; | ||
| 350 | else if (sample > 32767) | ||
| 351 | sample = 32767; | ||
| 352 | dsp_audio_increase2[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
| 353 | sample = dsp_audio_law_to_s32[i] * num[2] / denum[2]; | ||
| 354 | if (sample < -32768) | ||
| 355 | sample = -32768; | ||
| 356 | else if (sample > 32767) | ||
| 357 | sample = 32767; | ||
| 358 | dsp_audio_increase3[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
| 359 | sample = dsp_audio_law_to_s32[i] * num[3] / denum[3]; | ||
| 360 | if (sample < -32768) | ||
| 361 | sample = -32768; | ||
| 362 | else if (sample > 32767) | ||
| 363 | sample = 32767; | ||
| 364 | dsp_audio_increase4[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
| 365 | sample = dsp_audio_law_to_s32[i] * num[4] / denum[4]; | ||
| 366 | if (sample < -32768) | ||
| 367 | sample = -32768; | ||
| 368 | else if (sample > 32767) | ||
| 369 | sample = 32767; | ||
| 370 | dsp_audio_increase5[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
| 371 | sample = dsp_audio_law_to_s32[i] * num[5] / denum[5]; | ||
| 372 | if (sample < -32768) | ||
| 373 | sample = -32768; | ||
| 374 | else if (sample > 32767) | ||
| 375 | sample = 32767; | ||
| 376 | dsp_audio_increase6[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
| 377 | sample = dsp_audio_law_to_s32[i] * num[6] / denum[6]; | ||
| 378 | if (sample < -32768) | ||
| 379 | sample = -32768; | ||
| 380 | else if (sample > 32767) | ||
| 381 | sample = 32767; | ||
| 382 | dsp_audio_increase7[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
| 383 | sample = dsp_audio_law_to_s32[i] * num[7] / denum[7]; | ||
| 384 | if (sample < -32768) | ||
| 385 | sample = -32768; | ||
| 386 | else if (sample > 32767) | ||
| 387 | sample = 32767; | ||
| 388 | dsp_audio_increase8[i] = dsp_audio_s16_to_law[sample & 0xffff]; | ||
| 389 | |||
| 390 | i++; | ||
| 391 | } | ||
| 392 | } | ||
| 393 | |||
| 394 | |||
| 395 | /************************************** | ||
| 396 | * change the volume of the given skb * | ||
| 397 | **************************************/ | ||
| 398 | |||
| 399 | /* this is a helper function for changing volume of skb. the range may be | ||
| 400 | * -8 to 8, which is a shift to the power of 2. 0 == no volume, 3 == volume*8 | ||
| 401 | */ | ||
| 402 | void | ||
| 403 | dsp_change_volume(struct sk_buff *skb, int volume) | ||
| 404 | { | ||
| 405 | u8 *volume_change; | ||
| 406 | int i, ii; | ||
| 407 | u8 *p; | ||
| 408 | int shift; | ||
| 409 | |||
| 410 | if (volume == 0) | ||
| 411 | return; | ||
| 412 | |||
| 413 | /* get correct conversion table */ | ||
| 414 | if (volume < 0) { | ||
| 415 | shift = volume + 8; | ||
| 416 | if (shift < 0) | ||
| 417 | shift = 0; | ||
| 418 | } else { | ||
| 419 | shift = volume + 7; | ||
| 420 | if (shift > 15) | ||
| 421 | shift = 15; | ||
| 422 | } | ||
| 423 | volume_change = dsp_audio_volume_change[shift]; | ||
| 424 | i = 0; | ||
| 425 | ii = skb->len; | ||
| 426 | p = skb->data; | ||
| 427 | /* change volume */ | ||
| 428 | while (i < ii) { | ||
| 429 | *p = volume_change[*p]; | ||
| 430 | p++; | ||
| 431 | i++; | ||
| 432 | } | ||
| 433 | } | ||
| 434 | |||
diff --git a/drivers/isdn/mISDN/dsp_biquad.h b/drivers/isdn/mISDN/dsp_biquad.h new file mode 100644 index 000000000000..038191bc45f5 --- /dev/null +++ b/drivers/isdn/mISDN/dsp_biquad.h | |||
| @@ -0,0 +1,65 @@ | |||
| 1 | /* | ||
| 2 | * SpanDSP - a series of DSP components for telephony | ||
| 3 | * | ||
| 4 | * biquad.h - General telephony bi-quad section routines (currently this just | ||
| 5 | * handles canonic/type 2 form) | ||
| 6 | * | ||
| 7 | * Written by Steve Underwood <steveu@coppice.org> | ||
| 8 | * | ||
| 9 | * Copyright (C) 2001 Steve Underwood | ||
| 10 | * | ||
| 11 | * All rights reserved. | ||
| 12 | * | ||
| 13 | * This program is free software; you can redistribute it and/or modify | ||
| 14 | * it under the terms of the GNU General Public License as published by | ||
| 15 | * the Free Software Foundation; either version 2 of the License, or | ||
| 16 | * (at your option) any later version. | ||
| 17 | * | ||
| 18 | * This program is distributed in the hope that it will be useful, | ||
| 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 21 | * GNU General Public License for more details. | ||
| 22 | * | ||
| 23 | * You should have received a copy of the GNU General Public License | ||
| 24 | * along with this program; if not, write to the Free Software | ||
| 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 26 | * | ||
| 27 | */ | ||
| 28 | |||
| 29 | struct biquad2_state { | ||
| 30 | int32_t gain; | ||
| 31 | int32_t a1; | ||
| 32 | int32_t a2; | ||
| 33 | int32_t b1; | ||
| 34 | int32_t b2; | ||
| 35 | |||
| 36 | int32_t z1; | ||
| 37 | int32_t z2; | ||
| 38 | }; | ||
| 39 | |||
| 40 | static inline void biquad2_init(struct biquad2_state *bq, | ||
| 41 | int32_t gain, int32_t a1, int32_t a2, int32_t b1, int32_t b2) | ||
| 42 | { | ||
| 43 | bq->gain = gain; | ||
| 44 | bq->a1 = a1; | ||
| 45 | bq->a2 = a2; | ||
| 46 | bq->b1 = b1; | ||
| 47 | bq->b2 = b2; | ||
| 48 | |||
| 49 | bq->z1 = 0; | ||
| 50 | bq->z2 = 0; | ||
| 51 | } | ||
| 52 | |||
| 53 | static inline int16_t biquad2(struct biquad2_state *bq, int16_t sample) | ||
| 54 | { | ||
| 55 | int32_t y; | ||
| 56 | int32_t z0; | ||
| 57 | |||
| 58 | z0 = sample*bq->gain + bq->z1*bq->a1 + bq->z2*bq->a2; | ||
| 59 | y = z0 + bq->z1*bq->b1 + bq->z2*bq->b2; | ||
| 60 | |||
| 61 | bq->z2 = bq->z1; | ||
| 62 | bq->z1 = z0 >> 15; | ||
| 63 | y >>= 15; | ||
| 64 | return y; | ||
| 65 | } | ||
diff --git a/drivers/isdn/mISDN/dsp_blowfish.c b/drivers/isdn/mISDN/dsp_blowfish.c new file mode 100644 index 000000000000..18e411e95bba --- /dev/null +++ b/drivers/isdn/mISDN/dsp_blowfish.c | |||
| @@ -0,0 +1,672 @@ | |||
| 1 | /* | ||
| 2 | * Blowfish encryption/decryption for mISDN_dsp. | ||
| 3 | * | ||
| 4 | * Copyright Andreas Eversberg (jolly@eversberg.eu) | ||
| 5 | * | ||
| 6 | * This software may be used and distributed according to the terms | ||
| 7 | * of the GNU General Public License, incorporated herein by reference. | ||
| 8 | * | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/mISDNif.h> | ||
| 12 | #include <linux/mISDNdsp.h> | ||
| 13 | #include "core.h" | ||
| 14 | #include "dsp.h" | ||
| 15 | |||
| 16 | /* | ||
| 17 | * how to encode a sample stream to 64-bit blocks that will be encryped | ||
| 18 | * | ||
| 19 | * first of all, data is collected until a block of 9 samples are received. | ||
| 20 | * of course, a packet may have much more than 9 sample, but is may have | ||
| 21 | * not excacly the multiple of 9 samples. if there is a rest, the next | ||
| 22 | * received data will complete the block. | ||
| 23 | * | ||
| 24 | * the block is then converted to 9 uLAW samples without the least sigificant | ||
| 25 | * bit. the result is a 7-bit encoded sample. | ||
| 26 | * | ||
| 27 | * the samples will be reoganised to form 8 bytes of data: | ||
| 28 | * (5(6) means: encoded sample no. 5, bit 6) | ||
| 29 | * | ||
| 30 | * 0(6) 0(5) 0(4) 0(3) 0(2) 0(1) 0(0) 1(6) | ||
| 31 | * 1(5) 1(4) 1(3) 1(2) 1(1) 1(0) 2(6) 2(5) | ||
| 32 | * 2(4) 2(3) 2(2) 2(1) 2(0) 3(6) 3(5) 3(4) | ||
| 33 | * 3(3) 3(2) 3(1) 3(0) 4(6) 4(5) 4(4) 4(3) | ||
| 34 | * 4(2) 4(1) 4(0) 5(6) 5(5) 5(4) 5(3) 5(2) | ||
| 35 | * 5(1) 5(0) 6(6) 6(5) 6(4) 6(3) 6(2) 6(1) | ||
| 36 | * 6(0) 7(6) 7(5) 7(4) 7(3) 7(2) 7(1) 7(0) | ||
| 37 | * 8(6) 8(5) 8(4) 8(3) 8(2) 8(1) 8(0) | ||
| 38 | * | ||
| 39 | * the missing bit 0 of the last byte is filled with some | ||
| 40 | * random noise, to fill all 8 bytes. | ||
| 41 | * | ||
| 42 | * the 8 bytes will be encrypted using blowfish. | ||
| 43 | * | ||
| 44 | * the result will be converted into 9 bytes. the bit 7 is used for | ||
| 45 | * checksumme (CS) for sync (0, 1) and for the last bit: | ||
| 46 | * (5(6) means: crypted byte 5, bit 6) | ||
| 47 | * | ||
| 48 | * 1 0(7) 0(6) 0(5) 0(4) 0(3) 0(2) 0(1) | ||
| 49 | * 0 0(0) 1(7) 1(6) 1(5) 1(4) 1(3) 1(2) | ||
| 50 | * 0 1(1) 1(0) 2(7) 2(6) 2(5) 2(4) 2(3) | ||
| 51 | * 0 2(2) 2(1) 2(0) 3(7) 3(6) 3(5) 3(4) | ||
| 52 | * 0 3(3) 3(2) 3(1) 3(0) 4(7) 4(6) 4(5) | ||
| 53 | * CS 4(4) 4(3) 4(2) 4(1) 4(0) 5(7) 5(6) | ||
| 54 | * CS 5(5) 5(4) 5(3) 5(2) 5(1) 5(0) 6(7) | ||
| 55 | * CS 6(6) 6(5) 6(4) 6(3) 6(2) 6(1) 6(0) | ||
| 56 | * 7(0) 7(6) 7(5) 7(4) 7(3) 7(2) 7(1) 7(0) | ||
| 57 | * | ||
| 58 | * the checksum is used to detect transmission errors and frame drops. | ||
| 59 | * | ||
| 60 | * synchronisation of received block is done by shifting the upper bit of each | ||
| 61 | * byte (bit 7) to a shift register. if the rigister has the first five bits | ||
| 62 | * (10000), this is used to find the sync. only if sync has been found, the | ||
| 63 | * current block of 9 received bytes are decrypted. before that the check | ||
| 64 | * sum is calculated. if it is incorrect the block is dropped. | ||
| 65 | * this will avoid loud noise due to corrupt encrypted data. | ||
| 66 | * | ||
| 67 | * if the last block is corrupt, the current decoded block is repeated | ||
| 68 | * until a valid block has been received. | ||
| 69 | */ | ||
| 70 | |||
| 71 | /* | ||
| 72 | * some blowfish parts are taken from the | ||
| 73 | * crypto-api for faster implementation | ||
| 74 | */ | ||
| 75 | |||
| 76 | struct bf_ctx { | ||
| 77 | u32 p[18]; | ||
| 78 | u32 s[1024]; | ||
| 79 | }; | ||
| 80 | |||
| 81 | static const u32 bf_pbox[16 + 2] = { | ||
| 82 | 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, | ||
| 83 | 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, | ||
| 84 | 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, | ||
| 85 | 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, | ||
| 86 | 0x9216d5d9, 0x8979fb1b, | ||
| 87 | }; | ||
| 88 | |||
| 89 | static const u32 bf_sbox[256 * 4] = { | ||
| 90 | 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, | ||
| 91 | 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, | ||
| 92 | 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, | ||
| 93 | 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, | ||
| 94 | 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, | ||
| 95 | 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, | ||
| 96 | 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, | ||
| 97 | 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, | ||
| 98 | 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, | ||
| 99 | 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, | ||
| 100 | 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, | ||
| 101 | 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, | ||
| 102 | 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, | ||
| 103 | 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, | ||
| 104 | 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, | ||
| 105 | 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, | ||
| 106 | 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, | ||
| 107 | 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, | ||
| 108 | 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, | ||
| 109 | 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, | ||
| 110 | 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, | ||
| 111 | 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, | ||
| 112 | 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, | ||
| 113 | 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, | ||
| 114 | 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, | ||
| 115 | 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, | ||
| 116 | 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, | ||
| 117 | 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, | ||
| 118 | 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, | ||
| 119 | 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, | ||
| 120 | 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, | ||
| 121 | 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, | ||
| 122 | 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, | ||
| 123 | 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, | ||
| 124 | 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, | ||
| 125 | 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, | ||
| 126 | 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, | ||
| 127 | 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, | ||
| 128 | 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, | ||
| 129 | 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, | ||
| 130 | 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, | ||
| 131 | 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, | ||
| 132 | 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, | ||
| 133 | 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, | ||
| 134 | 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, | ||
| 135 | 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, | ||
| 136 | 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, | ||
| 137 | 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, | ||
| 138 | 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, | ||
| 139 | 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, | ||
| 140 | 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, | ||
| 141 | 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, | ||
| 142 | 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, | ||
| 143 | 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, | ||
| 144 | 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, | ||
| 145 | 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, | ||
| 146 | 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, | ||
| 147 | 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, | ||
| 148 | 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, | ||
| 149 | 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, | ||
| 150 | 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, | ||
| 151 | 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, | ||
| 152 | 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, | ||
| 153 | 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, | ||
| 154 | 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, | ||
| 155 | 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, | ||
| 156 | 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, | ||
| 157 | 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, | ||
| 158 | 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, | ||
| 159 | 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, | ||
| 160 | 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, | ||
| 161 | 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, | ||
| 162 | 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, | ||
| 163 | 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, | ||
| 164 | 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, | ||
| 165 | 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, | ||
| 166 | 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, | ||
| 167 | 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, | ||
| 168 | 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, | ||
| 169 | 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, | ||
| 170 | 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, | ||
| 171 | 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, | ||
| 172 | 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, | ||
| 173 | 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, | ||
| 174 | 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, | ||
| 175 | 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, | ||
| 176 | 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, | ||
| 177 | 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, | ||
| 178 | 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, | ||
| 179 | 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, | ||
| 180 | 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, | ||
| 181 | 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, | ||
| 182 | 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, | ||
| 183 | 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, | ||
| 184 | 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, | ||
| 185 | 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, | ||
| 186 | 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, | ||
| 187 | 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, | ||
| 188 | 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, | ||
| 189 | 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, | ||
| 190 | 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, | ||
| 191 | 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, | ||
| 192 | 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, | ||
| 193 | 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, | ||
| 194 | 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, | ||
| 195 | 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, | ||
| 196 | 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, | ||
| 197 | 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, | ||
| 198 | 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, | ||
| 199 | 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, | ||
| 200 | 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, | ||
| 201 | 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, | ||
| 202 | 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, | ||
| 203 | 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, | ||
| 204 | 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, | ||
| 205 | 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, | ||
| 206 | 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, | ||
| 207 | 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, | ||
| 208 | 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, | ||
| 209 | 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, | ||
| 210 | 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, | ||
| 211 | 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, | ||
| 212 | 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, | ||
| 213 | 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, | ||
| 214 | 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, | ||
| 215 | 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, | ||
| 216 | 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, | ||
| 217 | 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, | ||
| 218 | 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, | ||
| 219 | 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, | ||
| 220 | 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, | ||
| 221 | 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, | ||
| 222 | 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, | ||
| 223 | 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, | ||
| 224 | 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, | ||
| 225 | 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, | ||
| 226 | 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, | ||
| 227 | 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, | ||
| 228 | 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, | ||
| 229 | 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, | ||
| 230 | 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, | ||
| 231 | 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, | ||
| 232 | 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, | ||
| 233 | 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, | ||
| 234 | 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, | ||
| 235 | 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, | ||
| 236 | 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, | ||
| 237 | 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, | ||
| 238 | 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, | ||
| 239 | 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, | ||
| 240 | 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, | ||
| 241 | 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, | ||
| 242 | 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, | ||
| 243 | 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, | ||
| 244 | 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, | ||
| 245 | 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, | ||
| 246 | 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, | ||
| 247 | 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, | ||
| 248 | 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, | ||
| 249 | 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, | ||
| 250 | 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, | ||
| 251 | 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, | ||
| 252 | 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, | ||
| 253 | 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, | ||
| 254 | 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, | ||
| 255 | 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, | ||
| 256 | 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, | ||
| 257 | 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, | ||
| 258 | 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, | ||
| 259 | 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, | ||
| 260 | 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, | ||
| 261 | 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, | ||
| 262 | 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, | ||
| 263 | 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, | ||
| 264 | 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, | ||
| 265 | 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, | ||
| 266 | 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, | ||
| 267 | 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, | ||
| 268 | 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, | ||
| 269 | 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, | ||
| 270 | 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, | ||
| 271 | 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, | ||
| 272 | 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, | ||
| 273 | 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, | ||
| 274 | 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, | ||
| 275 | 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, | ||
| 276 | 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, | ||
| 277 | 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, | ||
| 278 | 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, | ||
| 279 | 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, | ||
| 280 | 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, | ||
| 281 | 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, | ||
| 282 | 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, | ||
| 283 | 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, | ||
| 284 | 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, | ||
| 285 | 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, | ||
| 286 | 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, | ||
| 287 | 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, | ||
| 288 | 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, | ||
| 289 | 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, | ||
| 290 | 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, | ||
| 291 | 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, | ||
| 292 | 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, | ||
| 293 | 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, | ||
| 294 | 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, | ||
| 295 | 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, | ||
| 296 | 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, | ||
| 297 | 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, | ||
| 298 | 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, | ||
| 299 | 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, | ||
| 300 | 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, | ||
| 301 | 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, | ||
| 302 | 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, | ||
| 303 | 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, | ||
| 304 | 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, | ||
| 305 | 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, | ||
| 306 | 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, | ||
| 307 | 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, | ||
| 308 | 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, | ||
| 309 | 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, | ||
| 310 | 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, | ||
| 311 | 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, | ||
| 312 | 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, | ||
| 313 | 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, | ||
| 314 | 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, | ||
| 315 | 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, | ||
| 316 | 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, | ||
| 317 | 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, | ||
| 318 | 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, | ||
| 319 | 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, | ||
| 320 | 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, | ||
| 321 | 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, | ||
| 322 | 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, | ||
| 323 | 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, | ||
| 324 | 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, | ||
| 325 | 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, | ||
| 326 | 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, | ||
| 327 | 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, | ||
| 328 | 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, | ||
| 329 | 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, | ||
| 330 | 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, | ||
| 331 | 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, | ||
| 332 | 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, | ||
| 333 | 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, | ||
| 334 | 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, | ||
| 335 | 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, | ||
| 336 | 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, | ||
| 337 | 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, | ||
| 338 | 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, | ||
| 339 | 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, | ||
| 340 | 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, | ||
| 341 | 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, | ||
| 342 | 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, | ||
| 343 | 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, | ||
| 344 | 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, | ||
| 345 | 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6, | ||
| 346 | }; | ||
| 347 | |||
| 348 | /* | ||
| 349 | * Round loop unrolling macros, S is a pointer to a S-Box array | ||
| 350 | * organized in 4 unsigned longs at a row. | ||
| 351 | */ | ||
| 352 | #define GET32_3(x) (((x) & 0xff)) | ||
| 353 | #define GET32_2(x) (((x) >> (8)) & (0xff)) | ||
| 354 | #define GET32_1(x) (((x) >> (16)) & (0xff)) | ||
| 355 | #define GET32_0(x) (((x) >> (24)) & (0xff)) | ||
| 356 | |||
| 357 | #define bf_F(x) (((S[GET32_0(x)] + S[256 + GET32_1(x)]) ^ \ | ||
| 358 | S[512 + GET32_2(x)]) + S[768 + GET32_3(x)]) | ||
| 359 | |||
| 360 | #define EROUND(a, b, n) do { b ^= P[n]; a ^= bf_F(b); } while (0) | ||
| 361 | #define DROUND(a, b, n) do { a ^= bf_F(b); b ^= P[n]; } while (0) | ||
| 362 | |||
| 363 | |||
| 364 | /* | ||
| 365 | * encrypt isdn data frame | ||
| 366 | * every block with 9 samples is encrypted | ||
| 367 | */ | ||
| 368 | void | ||
| 369 | dsp_bf_encrypt(struct dsp *dsp, u8 *data, int len) | ||
| 370 | { | ||
| 371 | int i = 0, j = dsp->bf_crypt_pos; | ||
| 372 | u8 *bf_data_in = dsp->bf_data_in; | ||
| 373 | u8 *bf_crypt_out = dsp->bf_crypt_out; | ||
| 374 | u32 *P = dsp->bf_p; | ||
| 375 | u32 *S = dsp->bf_s; | ||
| 376 | u32 yl, yr; | ||
| 377 | u32 cs; | ||
| 378 | u8 nibble; | ||
| 379 | |||
| 380 | while (i < len) { | ||
| 381 | /* collect a block of 9 samples */ | ||
| 382 | if (j < 9) { | ||
| 383 | bf_data_in[j] = *data; | ||
| 384 | *data++ = bf_crypt_out[j++]; | ||
| 385 | i++; | ||
| 386 | continue; | ||
| 387 | } | ||
| 388 | j = 0; | ||
| 389 | /* transcode 9 samples xlaw to 8 bytes */ | ||
| 390 | yl = dsp_audio_law2seven[bf_data_in[0]]; | ||
| 391 | yl = (yl<<7) | dsp_audio_law2seven[bf_data_in[1]]; | ||
| 392 | yl = (yl<<7) | dsp_audio_law2seven[bf_data_in[2]]; | ||
| 393 | yl = (yl<<7) | dsp_audio_law2seven[bf_data_in[3]]; | ||
| 394 | nibble = dsp_audio_law2seven[bf_data_in[4]]; | ||
| 395 | yr = nibble; | ||
| 396 | yl = (yl<<4) | (nibble>>3); | ||
| 397 | yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[5]]; | ||
| 398 | yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[6]]; | ||
| 399 | yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[7]]; | ||
| 400 | yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[8]]; | ||
| 401 | yr = (yr<<1) | (bf_data_in[0] & 1); | ||
| 402 | |||
| 403 | /* fill unused bit with random noise of audio input */ | ||
| 404 | /* encrypt */ | ||
| 405 | |||
| 406 | EROUND(yr, yl, 0); | ||
| 407 | EROUND(yl, yr, 1); | ||
| 408 | EROUND(yr, yl, 2); | ||
| 409 | EROUND(yl, yr, 3); | ||
| 410 | EROUND(yr, yl, 4); | ||
| 411 | EROUND(yl, yr, 5); | ||
| 412 | EROUND(yr, yl, 6); | ||
| 413 | EROUND(yl, yr, 7); | ||
| 414 | EROUND(yr, yl, 8); | ||
| 415 | EROUND(yl, yr, 9); | ||
| 416 | EROUND(yr, yl, 10); | ||
| 417 | EROUND(yl, yr, 11); | ||
| 418 | EROUND(yr, yl, 12); | ||
| 419 | EROUND(yl, yr, 13); | ||
| 420 | EROUND(yr, yl, 14); | ||
| 421 | EROUND(yl, yr, 15); | ||
| 422 | yl ^= P[16]; | ||
| 423 | yr ^= P[17]; | ||
| 424 | |||
| 425 | /* calculate 3-bit checksumme */ | ||
| 426 | cs = yl ^ (yl>>3) ^ (yl>>6) ^ (yl>>9) ^ (yl>>12) ^ (yl>>15) | ||
| 427 | ^ (yl>>18) ^ (yl>>21) ^ (yl>>24) ^ (yl>>27) ^ (yl>>30) | ||
| 428 | ^ (yr<<2) ^ (yr>>1) ^ (yr>>4) ^ (yr>>7) ^ (yr>>10) | ||
| 429 | ^ (yr>>13) ^ (yr>>16) ^ (yr>>19) ^ (yr>>22) ^ (yr>>25) | ||
| 430 | ^ (yr>>28) ^ (yr>>31); | ||
| 431 | |||
| 432 | /* | ||
| 433 | * transcode 8 crypted bytes to 9 data bytes with sync | ||
| 434 | * and checksum information | ||
| 435 | */ | ||
| 436 | bf_crypt_out[0] = (yl>>25) | 0x80; | ||
| 437 | bf_crypt_out[1] = (yl>>18) & 0x7f; | ||
| 438 | bf_crypt_out[2] = (yl>>11) & 0x7f; | ||
| 439 | bf_crypt_out[3] = (yl>>4) & 0x7f; | ||
| 440 | bf_crypt_out[4] = ((yl<<3) & 0x78) | ((yr>>29) & 0x07); | ||
| 441 | bf_crypt_out[5] = ((yr>>22) & 0x7f) | ((cs<<5) & 0x80); | ||
| 442 | bf_crypt_out[6] = ((yr>>15) & 0x7f) | ((cs<<6) & 0x80); | ||
| 443 | bf_crypt_out[7] = ((yr>>8) & 0x7f) | (cs<<7); | ||
| 444 | bf_crypt_out[8] = yr; | ||
| 445 | } | ||
| 446 | |||
| 447 | /* write current count */ | ||
| 448 | dsp->bf_crypt_pos = j; | ||
| 449 | |||
| 450 | } | ||
| 451 | |||
| 452 | |||
| 453 | /* | ||
| 454 | * decrypt isdn data frame | ||
| 455 | * every block with 9 bytes is decrypted | ||
| 456 | */ | ||
| 457 | void | ||
| 458 | dsp_bf_decrypt(struct dsp *dsp, u8 *data, int len) | ||
| 459 | { | ||
| 460 | int i = 0; | ||
| 461 | u8 j = dsp->bf_decrypt_in_pos; | ||
| 462 | u8 k = dsp->bf_decrypt_out_pos; | ||
| 463 | u8 *bf_crypt_inring = dsp->bf_crypt_inring; | ||
| 464 | u8 *bf_data_out = dsp->bf_data_out; | ||
| 465 | u16 sync = dsp->bf_sync; | ||
| 466 | u32 *P = dsp->bf_p; | ||
| 467 | u32 *S = dsp->bf_s; | ||
| 468 | u32 yl, yr; | ||
| 469 | u8 nibble; | ||
| 470 | u8 cs, cs0, cs1, cs2; | ||
| 471 | |||
| 472 | while (i < len) { | ||
| 473 | /* | ||
| 474 | * shift upper bit and rotate data to buffer ring | ||
| 475 | * send current decrypted data | ||
| 476 | */ | ||
| 477 | sync = (sync<<1) | ((*data)>>7); | ||
| 478 | bf_crypt_inring[j++ & 15] = *data; | ||
| 479 | *data++ = bf_data_out[k++]; | ||
| 480 | i++; | ||
| 481 | if (k == 9) | ||
| 482 | k = 0; /* repeat if no sync has been found */ | ||
| 483 | /* check if not in sync */ | ||
| 484 | if ((sync&0x1f0) != 0x100) | ||
| 485 | continue; | ||
| 486 | j -= 9; | ||
| 487 | /* transcode receive data to 64 bit block of encrypted data */ | ||
| 488 | yl = bf_crypt_inring[j++ & 15]; | ||
| 489 | yl = (yl<<7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ | ||
| 490 | yl = (yl<<7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ | ||
| 491 | yl = (yl<<7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ | ||
| 492 | nibble = bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ | ||
| 493 | yr = nibble; | ||
| 494 | yl = (yl<<4) | (nibble>>3); | ||
| 495 | cs2 = bf_crypt_inring[j++ & 15]; | ||
| 496 | yr = (yr<<7) | (cs2 & 0x7f); | ||
| 497 | cs1 = bf_crypt_inring[j++ & 15]; | ||
| 498 | yr = (yr<<7) | (cs1 & 0x7f); | ||
| 499 | cs0 = bf_crypt_inring[j++ & 15]; | ||
| 500 | yr = (yr<<7) | (cs0 & 0x7f); | ||
| 501 | yr = (yr<<8) | bf_crypt_inring[j++ & 15]; | ||
| 502 | |||
| 503 | /* calculate 3-bit checksumme */ | ||
| 504 | cs = yl ^ (yl>>3) ^ (yl>>6) ^ (yl>>9) ^ (yl>>12) ^ (yl>>15) | ||
| 505 | ^ (yl>>18) ^ (yl>>21) ^ (yl>>24) ^ (yl>>27) ^ (yl>>30) | ||
| 506 | ^ (yr<<2) ^ (yr>>1) ^ (yr>>4) ^ (yr>>7) ^ (yr>>10) | ||
| 507 | ^ (yr>>13) ^ (yr>>16) ^ (yr>>19) ^ (yr>>22) ^ (yr>>25) | ||
| 508 | ^ (yr>>28) ^ (yr>>31); | ||
| 509 | |||
| 510 | /* check if frame is valid */ | ||
| 511 | if ((cs&0x7) != (((cs2>>5)&4) | ((cs1>>6)&2) | (cs0 >> 7))) { | ||
| 512 | if (dsp_debug & DEBUG_DSP_BLOWFISH) | ||
| 513 | printk(KERN_DEBUG | ||
| 514 | "DSP BLOWFISH: received corrupt frame, " | ||
| 515 | "checksumme is not correct\n"); | ||
| 516 | continue; | ||
| 517 | } | ||
| 518 | |||
| 519 | /* decrypt */ | ||
| 520 | yr ^= P[17]; | ||
| 521 | yl ^= P[16]; | ||
| 522 | DROUND(yl, yr, 15); | ||
| 523 | DROUND(yr, yl, 14); | ||
| 524 | DROUND(yl, yr, 13); | ||
| 525 | DROUND(yr, yl, 12); | ||
| 526 | DROUND(yl, yr, 11); | ||
| 527 | DROUND(yr, yl, 10); | ||
| 528 | DROUND(yl, yr, 9); | ||
| 529 | DROUND(yr, yl, 8); | ||
| 530 | DROUND(yl, yr, 7); | ||
| 531 | DROUND(yr, yl, 6); | ||
| 532 | DROUND(yl, yr, 5); | ||
| 533 | DROUND(yr, yl, 4); | ||
| 534 | DROUND(yl, yr, 3); | ||
| 535 | DROUND(yr, yl, 2); | ||
| 536 | DROUND(yl, yr, 1); | ||
| 537 | DROUND(yr, yl, 0); | ||
| 538 | |||
| 539 | /* transcode 8 crypted bytes to 9 sample bytes */ | ||
| 540 | bf_data_out[0] = dsp_audio_seven2law[(yl>>25) & 0x7f]; | ||
| 541 | bf_data_out[1] = dsp_audio_seven2law[(yl>>18) & 0x7f]; | ||
| 542 | bf_data_out[2] = dsp_audio_seven2law[(yl>>11) & 0x7f]; | ||
| 543 | bf_data_out[3] = dsp_audio_seven2law[(yl>>4) & 0x7f]; | ||
| 544 | bf_data_out[4] = dsp_audio_seven2law[((yl<<3) & 0x78) | | ||
| 545 | ((yr>>29) & 0x07)]; | ||
| 546 | |||
| 547 | bf_data_out[5] = dsp_audio_seven2law[(yr>>22) & 0x7f]; | ||
| 548 | bf_data_out[6] = dsp_audio_seven2law[(yr>>15) & 0x7f]; | ||
| 549 | bf_data_out[7] = dsp_audio_seven2law[(yr>>8) & 0x7f]; | ||
| 550 | bf_data_out[8] = dsp_audio_seven2law[(yr>>1) & 0x7f]; | ||
| 551 | k = 0; /* start with new decoded frame */ | ||
| 552 | } | ||
| 553 | |||
| 554 | /* write current count and sync */ | ||
| 555 | dsp->bf_decrypt_in_pos = j; | ||
| 556 | dsp->bf_decrypt_out_pos = k; | ||
| 557 | dsp->bf_sync = sync; | ||
| 558 | } | ||
| 559 | |||
| 560 | |||
| 561 | /* used to encrypt S and P boxes */ | ||
| 562 | static inline void | ||
| 563 | encrypt_block(const u32 *P, const u32 *S, u32 *dst, u32 *src) | ||
| 564 | { | ||
| 565 | u32 yl = src[0]; | ||
| 566 | u32 yr = src[1]; | ||
| 567 | |||
| 568 | EROUND(yr, yl, 0); | ||
| 569 | EROUND(yl, yr, 1); | ||
| 570 | EROUND(yr, yl, 2); | ||
| 571 | EROUND(yl, yr, 3); | ||
| 572 | EROUND(yr, yl, 4); | ||
| 573 | EROUND(yl, yr, 5); | ||
| 574 | EROUND(yr, yl, 6); | ||
| 575 | EROUND(yl, yr, 7); | ||
| 576 | EROUND(yr, yl, 8); | ||
| 577 | EROUND(yl, yr, 9); | ||
| 578 | EROUND(yr, yl, 10); | ||
| 579 | EROUND(yl, yr, 11); | ||
| 580 | EROUND(yr, yl, 12); | ||
| 581 | EROUND(yl, yr, 13); | ||
| 582 | EROUND(yr, yl, 14); | ||
| 583 | EROUND(yl, yr, 15); | ||
| 584 | |||
| 585 | yl ^= P[16]; | ||
| 586 | yr ^= P[17]; | ||
| 587 | |||
| 588 | dst[0] = yr; | ||
| 589 | dst[1] = yl; | ||
| 590 | } | ||
| 591 | |||
| 592 | /* | ||
| 593 | * initialize the dsp for encryption and decryption using the same key | ||
| 594 | * Calculates the blowfish S and P boxes for encryption and decryption. | ||
| 595 | * The margin of keylen must be 4-56 bytes. | ||
| 596 | * returns 0 if ok. | ||
| 597 | */ | ||
| 598 | int | ||
| 599 | dsp_bf_init(struct dsp *dsp, const u8 *key, uint keylen) | ||
| 600 | { | ||
| 601 | short i, j, count; | ||
| 602 | u32 data[2], temp; | ||
| 603 | u32 *P = (u32 *)dsp->bf_p; | ||
| 604 | u32 *S = (u32 *)dsp->bf_s; | ||
| 605 | |||
| 606 | if (keylen < 4 || keylen > 56) | ||
| 607 | return 1; | ||
| 608 | |||
| 609 | /* Set dsp states */ | ||
| 610 | i = 0; | ||
| 611 | while (i < 9) { | ||
| 612 | dsp->bf_crypt_out[i] = 0xff; | ||
| 613 | dsp->bf_data_out[i] = dsp_silence; | ||
| 614 | i++; | ||
| 615 | } | ||
| 616 | dsp->bf_crypt_pos = 0; | ||
| 617 | dsp->bf_decrypt_in_pos = 0; | ||
| 618 | dsp->bf_decrypt_out_pos = 0; | ||
| 619 | dsp->bf_sync = 0x1ff; | ||
| 620 | dsp->bf_enable = 1; | ||
| 621 | |||
| 622 | /* Copy the initialization s-boxes */ | ||
| 623 | for (i = 0, count = 0; i < 256; i++) | ||
| 624 | for (j = 0; j < 4; j++, count++) | ||
| 625 | S[count] = bf_sbox[count]; | ||
| 626 | |||
| 627 | /* Set the p-boxes */ | ||
| 628 | for (i = 0; i < 16 + 2; i++) | ||
| 629 | P[i] = bf_pbox[i]; | ||
| 630 | |||
| 631 | /* Actual subkey generation */ | ||
| 632 | for (j = 0, i = 0; i < 16 + 2; i++) { | ||
| 633 | temp = (((u32)key[j] << 24) | | ||
| 634 | ((u32)key[(j + 1) % keylen] << 16) | | ||
| 635 | ((u32)key[(j + 2) % keylen] << 8) | | ||
| 636 | ((u32)key[(j + 3) % keylen])); | ||
| 637 | |||
| 638 | P[i] = P[i] ^ temp; | ||
| 639 | j = (j + 4) % keylen; | ||
| 640 | } | ||
| 641 | |||
| 642 | data[0] = 0x00000000; | ||
| 643 | data[1] = 0x00000000; | ||
| 644 | |||
| 645 | for (i = 0; i < 16 + 2; i += 2) { | ||
| 646 | encrypt_block(P, S, data, data); | ||
| 647 | |||
| 648 | P[i] = data[0]; | ||
| 649 | P[i + 1] = data[1]; | ||
| 650 | } | ||
| 651 | |||
| 652 | for (i = 0; i < 4; i++) { | ||
| 653 | for (j = 0, count = i * 256; j < 256; j += 2, count += 2) { | ||
| 654 | encrypt_block(P, S, data, data); | ||
| 655 | |||
| 656 | S[count] = data[0]; | ||
| 657 | S[count + 1] = data[1]; | ||
| 658 | } | ||
| 659 | } | ||
| 660 | |||
| 661 | return 0; | ||
| 662 | } | ||
| 663 | |||
| 664 | |||
| 665 | /* | ||
| 666 | * turn encryption off | ||
| 667 | */ | ||
| 668 | void | ||
| 669 | dsp_bf_cleanup(struct dsp *dsp) | ||
| 670 | { | ||
| 671 | dsp->bf_enable = 0; | ||
| 672 | } | ||
diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c new file mode 100644 index 000000000000..e92b1ba4b45e --- /dev/null +++ b/drivers/isdn/mISDN/dsp_cmx.c | |||
| @@ -0,0 +1,1886 @@ | |||
| 1 | /* | ||
| 2 | * Audio crossconnecting/conferrencing (hardware level). | ||
| 3 | * | ||
| 4 | * Copyright 2002 by Andreas Eversberg (jolly@eversberg.eu) | ||
| 5 | * | ||
| 6 | * This software may be used and distributed according to the terms | ||
| 7 | * of the GNU General Public License, incorporated herein by reference. | ||
| 8 | * | ||
| 9 | */ | ||
| 10 | |||
| 11 | /* | ||
| 12 | * The process of adding and removing parties to/from a conference: | ||
| 13 | * | ||
| 14 | * There is a chain of struct dsp_conf which has one or more members in a chain | ||
| 15 | * of struct dsp_conf_member. | ||
| 16 | * | ||
| 17 | * After a party is added, the conference is checked for hardware capability. | ||
| 18 | * Also if a party is removed, the conference is checked again. | ||
| 19 | * | ||
| 20 | * There are 3 different solutions: -1 = software, 0 = hardware-crossconnect | ||
| 21 | * 1-n = hardware-conference. The n will give the conference number. | ||
| 22 | * | ||
| 23 | * Depending on the change after removal or insertion of a party, hardware | ||
| 24 | * commands are given. | ||
| 25 | * | ||
| 26 | * The current solution is stored within the struct dsp_conf entry. | ||
| 27 | */ | ||
| 28 | |||
| 29 | /* | ||
| 30 | * HOW THE CMX WORKS: | ||
| 31 | * | ||
| 32 | * There are 3 types of interaction: One member is alone, in this case only | ||
| 33 | * data flow from upper to lower layer is done. | ||
| 34 | * Two members will also exchange their data so they are crossconnected. | ||
| 35 | * Three or more members will be added in a conference and will hear each | ||
| 36 | * other but will not receive their own speech (echo) if not enabled. | ||
| 37 | * | ||
| 38 | * Features of CMX are: | ||
| 39 | * - Crossconnecting or even conference, if more than two members are together. | ||
| 40 | * - Force mixing of transmit data with other crossconnect/conference members. | ||
| 41 | * - Echo generation to benchmark the delay of audio processing. | ||
| 42 | * - Use hardware to minimize cpu load, disable FIFO load and minimize delay. | ||
| 43 | * - Dejittering and clock generation. | ||
| 44 | * | ||
| 45 | * There are 2 buffers: | ||
| 46 | * | ||
| 47 | * | ||
| 48 | * RX-Buffer | ||
| 49 | * R W | ||
| 50 | * | | | ||
| 51 | * ----------------+-------------+------------------- | ||
| 52 | * | ||
| 53 | * The rx-buffer is a ring buffer used to store the received data for each | ||
| 54 | * individual member. This is only the case if data needs to be dejittered | ||
| 55 | * or in case of a conference where different clocks require reclocking. | ||
| 56 | * The transmit-clock (R) will read the buffer. | ||
| 57 | * If the clock overruns the write-pointer, we will have a buffer underrun. | ||
| 58 | * If the write pointer always has a certain distance from the transmit- | ||
| 59 | * clock, we will have a delay. The delay will dynamically be increased and | ||
| 60 | * reduced. | ||
| 61 | * | ||
| 62 | * | ||
| 63 | * TX-Buffer | ||
| 64 | * R W | ||
| 65 | * | | | ||
| 66 | * -----------------+--------+----------------------- | ||
| 67 | * | ||
| 68 | * The tx-buffer is a ring buffer to queue the transmit data from user space | ||
| 69 | * until it will be mixed or sent. There are two pointers, R and W. If the write | ||
| 70 | * pointer W would reach or overrun R, the buffer would overrun. In this case | ||
| 71 | * (some) data is dropped so that it will not overrun. | ||
| 72 | * Additionally a dynamic dejittering can be enabled. this allows data from | ||
| 73 | * user space that have jitter and different clock source. | ||
| 74 | * | ||
| 75 | * | ||
| 76 | * Clock: | ||
| 77 | * | ||
| 78 | * A Clock is not required, if the data source has exactly one clock. In this | ||
| 79 | * case the data source is forwarded to the destination. | ||
| 80 | * | ||
| 81 | * A Clock is required, because the data source | ||
| 82 | * - has multiple clocks. | ||
| 83 | * - has no usable clock due to jitter or packet loss (VoIP). | ||
| 84 | * In this case the system's clock is used. The clock resolution depends on | ||
| 85 | * the jiffie resolution. | ||
| 86 | * | ||
| 87 | * If a member joins a conference: | ||
| 88 | * | ||
| 89 | * - If a member joins, its rx_buff is set to silence and change read pointer | ||
| 90 | * to transmit clock. | ||
| 91 | * | ||
| 92 | * The procedure of received data from card is explained in cmx_receive. | ||
| 93 | * The procedure of received data from user space is explained in cmx_transmit. | ||
| 94 | * The procedure of transmit data to card is cmx_send. | ||
| 95 | * | ||
| 96 | * | ||
| 97 | * Interaction with other features: | ||
| 98 | * | ||
| 99 | * DTMF: | ||
| 100 | * DTMF decoding is done before the data is crossconnected. | ||
| 101 | * | ||
| 102 | * Volume change: | ||
| 103 | * Changing rx-volume is done before the data is crossconnected. The tx-volume | ||
| 104 | * must be changed whenever data is transmitted to the card by the cmx. | ||
| 105 | * | ||
| 106 | * Tones: | ||
| 107 | * If a tone is enabled, it will be processed whenever data is transmitted to | ||
| 108 | * the card. It will replace the tx-data from the user space. | ||
| 109 | * If tones are generated by hardware, this conference member is removed for | ||
| 110 | * this time. | ||
| 111 | * | ||
| 112 | * Disable rx-data: | ||
| 113 | * If cmx is realized in hardware, rx data will be disabled if requested by | ||
| 114 | * the upper layer. If dtmf decoding is done by software and enabled, rx data | ||
| 115 | * will not be diabled but blocked to the upper layer. | ||
| 116 | * | ||
| 117 | * HFC conference engine: | ||
| 118 | * If it is possible to realize all features using hardware, hardware will be | ||
| 119 | * used if not forbidden by control command. Disabling rx-data provides | ||
| 120 | * absolutely traffic free audio processing. (except for the quick 1-frame | ||
| 121 | * upload of a tone loop, only once for a new tone) | ||
| 122 | * | ||
| 123 | */ | ||
| 124 | |||
| 125 | /* delay.h is required for hw_lock.h */ | ||
| 126 | |||
| 127 | #include <linux/delay.h> | ||
| 128 | #include <linux/mISDNif.h> | ||
| 129 | #include <linux/mISDNdsp.h> | ||
| 130 | #include "core.h" | ||
| 131 | #include "dsp.h" | ||
| 132 | /* | ||
| 133 | * debugging of multi party conference, | ||
| 134 | * by using conference even with two members | ||
| 135 | */ | ||
| 136 | |||
| 137 | /* #define CMX_CONF_DEBUG */ | ||
| 138 | |||
| 139 | /*#define CMX_DEBUG * massive read/write pointer output */ | ||
| 140 | /*#define CMX_TX_DEBUG * massive read/write on tx-buffer with content */ | ||
| 141 | |||
| 142 | static inline int | ||
| 143 | count_list_member(struct list_head *head) | ||
| 144 | { | ||
| 145 | int cnt = 0; | ||
| 146 | struct list_head *m; | ||
| 147 | |||
| 148 | list_for_each(m, head) | ||
| 149 | cnt++; | ||
| 150 | return cnt; | ||
| 151 | } | ||
| 152 | |||
| 153 | /* | ||
| 154 | * debug cmx memory structure | ||
| 155 | */ | ||
| 156 | void | ||
| 157 | dsp_cmx_debug(struct dsp *dsp) | ||
| 158 | { | ||
| 159 | struct dsp_conf *conf; | ||
| 160 | struct dsp_conf_member *member; | ||
| 161 | struct dsp *odsp; | ||
| 162 | |||
| 163 | printk(KERN_DEBUG "-----Current DSP\n"); | ||
| 164 | list_for_each_entry(odsp, &dsp_ilist, list) { | ||
| 165 | printk(KERN_DEBUG "* %s echo=%d txmix=%d", | ||
| 166 | odsp->name, odsp->echo, odsp->tx_mix); | ||
| 167 | if (odsp->conf) | ||
| 168 | printk(" (Conf %d)", odsp->conf->id); | ||
| 169 | if (dsp == odsp) | ||
| 170 | printk(" *this*"); | ||
| 171 | printk("\n"); | ||
| 172 | } | ||
| 173 | printk(KERN_DEBUG "-----Current Conf:\n"); | ||
| 174 | list_for_each_entry(conf, &conf_ilist, list) { | ||
| 175 | printk(KERN_DEBUG "* Conf %d (%p)\n", conf->id, conf); | ||
| 176 | list_for_each_entry(member, &conf->mlist, list) { | ||
| 177 | printk(KERN_DEBUG | ||
| 178 | " - member = %s (slot_tx %d, bank_tx %d, " | ||
| 179 | "slot_rx %d, bank_rx %d hfc_conf %d)%s\n", | ||
| 180 | member->dsp->name, member->dsp->pcm_slot_tx, | ||
| 181 | member->dsp->pcm_bank_tx, member->dsp->pcm_slot_rx, | ||
| 182 | member->dsp->pcm_bank_rx, member->dsp->hfc_conf, | ||
| 183 | (member->dsp == dsp) ? " *this*" : ""); | ||
| 184 | } | ||
| 185 | } | ||
| 186 | printk(KERN_DEBUG "-----end\n"); | ||
| 187 | } | ||
| 188 | |||
| 189 | /* | ||
| 190 | * search conference | ||
| 191 | */ | ||
| 192 | static struct dsp_conf * | ||
| 193 | dsp_cmx_search_conf(u32 id) | ||
| 194 | { | ||
| 195 | struct dsp_conf *conf; | ||
| 196 | |||
| 197 | if (!id) { | ||
| 198 | printk(KERN_WARNING "%s: conference ID is 0.\n", __func__); | ||
| 199 | return NULL; | ||
| 200 | } | ||
| 201 | |||
| 202 | /* search conference */ | ||
| 203 | list_for_each_entry(conf, &conf_ilist, list) | ||
| 204 | if (conf->id == id) | ||
| 205 | return conf; | ||
| 206 | |||
| 207 | return NULL; | ||
| 208 | } | ||
| 209 | |||
| 210 | |||
| 211 | /* | ||
| 212 | * add member to conference | ||
| 213 | */ | ||
| 214 | static int | ||
| 215 | dsp_cmx_add_conf_member(struct dsp *dsp, struct dsp_conf *conf) | ||
| 216 | { | ||
| 217 | struct dsp_conf_member *member; | ||
| 218 | |||
| 219 | if (!conf || !dsp) { | ||
| 220 | printk(KERN_WARNING "%s: conf or dsp is 0.\n", __func__); | ||
| 221 | return -EINVAL; | ||
| 222 | } | ||
| 223 | if (dsp->member) { | ||
| 224 | printk(KERN_WARNING "%s: dsp is already member in a conf.\n", | ||
| 225 | __func__); | ||
| 226 | return -EINVAL; | ||
| 227 | } | ||
| 228 | |||
| 229 | if (dsp->conf) { | ||
| 230 | printk(KERN_WARNING "%s: dsp is already in a conf.\n", | ||
| 231 | __func__); | ||
| 232 | return -EINVAL; | ||
| 233 | } | ||
| 234 | |||
| 235 | member = kzalloc(sizeof(struct dsp_conf_member), GFP_ATOMIC); | ||
| 236 | if (!member) { | ||
| 237 | printk(KERN_ERR "kmalloc struct dsp_conf_member failed\n"); | ||
| 238 | return -ENOMEM; | ||
| 239 | } | ||
| 240 | member->dsp = dsp; | ||
| 241 | /* clear rx buffer */ | ||
| 242 | memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff)); | ||
| 243 | dsp->rx_init = 1; /* rx_W and rx_R will be adjusted on first frame */ | ||
| 244 | dsp->rx_W = 0; | ||
| 245 | dsp->rx_R = 0; | ||
| 246 | |||
| 247 | list_add_tail(&member->list, &conf->mlist); | ||
| 248 | |||
| 249 | dsp->conf = conf; | ||
| 250 | dsp->member = member; | ||
| 251 | |||
| 252 | return 0; | ||
| 253 | } | ||
| 254 | |||
| 255 | |||
| 256 | /* | ||
| 257 | * del member from conference | ||
| 258 | */ | ||
| 259 | int | ||
| 260 | dsp_cmx_del_conf_member(struct dsp *dsp) | ||
| 261 | { | ||
| 262 | struct dsp_conf_member *member; | ||
| 263 | |||
| 264 | if (!dsp) { | ||
| 265 | printk(KERN_WARNING "%s: dsp is 0.\n", | ||
| 266 | __func__); | ||
| 267 | return -EINVAL; | ||
| 268 | } | ||
| 269 | |||
| 270 | if (!dsp->conf) { | ||
| 271 | printk(KERN_WARNING "%s: dsp is not in a conf.\n", | ||
| 272 | __func__); | ||
| 273 | return -EINVAL; | ||
| 274 | } | ||
| 275 | |||
| 276 | if (list_empty(&dsp->conf->mlist)) { | ||
| 277 | printk(KERN_WARNING "%s: dsp has linked an empty conf.\n", | ||
| 278 | __func__); | ||
| 279 | return -EINVAL; | ||
| 280 | } | ||
| 281 | |||
| 282 | /* find us in conf */ | ||
| 283 | list_for_each_entry(member, &dsp->conf->mlist, list) { | ||
| 284 | if (member->dsp == dsp) { | ||
| 285 | list_del(&member->list); | ||
| 286 | dsp->conf = NULL; | ||
| 287 | dsp->member = NULL; | ||
| 288 | kfree(member); | ||
| 289 | return 0; | ||
| 290 | } | ||
| 291 | } | ||
| 292 | printk(KERN_WARNING | ||
| 293 | "%s: dsp is not present in its own conf_meber list.\n", | ||
| 294 | __func__); | ||
| 295 | |||
| 296 | return -EINVAL; | ||
| 297 | } | ||
| 298 | |||
| 299 | |||
| 300 | /* | ||
| 301 | * new conference | ||
| 302 | */ | ||
| 303 | static struct dsp_conf | ||
| 304 | *dsp_cmx_new_conf(u32 id) | ||
| 305 | { | ||
| 306 | struct dsp_conf *conf; | ||
| 307 | |||
| 308 | if (!id) { | ||
| 309 | printk(KERN_WARNING "%s: id is 0.\n", | ||
| 310 | __func__); | ||
| 311 | return NULL; | ||
| 312 | } | ||
| 313 | |||
| 314 | conf = kzalloc(sizeof(struct dsp_conf), GFP_ATOMIC); | ||
| 315 | if (!conf) { | ||
| 316 | printk(KERN_ERR "kmalloc struct dsp_conf failed\n"); | ||
| 317 | return NULL; | ||
| 318 | } | ||
| 319 | INIT_LIST_HEAD(&conf->mlist); | ||
| 320 | conf->id = id; | ||
| 321 | |||
| 322 | list_add_tail(&conf->list, &conf_ilist); | ||
| 323 | |||
| 324 | return conf; | ||
| 325 | } | ||
| 326 | |||
| 327 | |||
| 328 | /* | ||
| 329 | * del conference | ||
| 330 | */ | ||
| 331 | int | ||
| 332 | dsp_cmx_del_conf(struct dsp_conf *conf) | ||
| 333 | { | ||
| 334 | if (!conf) { | ||
| 335 | printk(KERN_WARNING "%s: conf is null.\n", | ||
| 336 | __func__); | ||
| 337 | return -EINVAL; | ||
| 338 | } | ||
| 339 | |||
| 340 | if (!list_empty(&conf->mlist)) { | ||
| 341 | printk(KERN_WARNING "%s: conf not empty.\n", | ||
| 342 | __func__); | ||
| 343 | return -EINVAL; | ||
| 344 | } | ||
| 345 | list_del(&conf->list); | ||
| 346 | kfree(conf); | ||
| 347 | |||
| 348 | return 0; | ||
| 349 | } | ||
| 350 | |||
| 351 | |||
| 352 | /* | ||
| 353 | * send HW message to hfc card | ||
| 354 | */ | ||
| 355 | static void | ||
| 356 | dsp_cmx_hw_message(struct dsp *dsp, u32 message, u32 param1, u32 param2, | ||
| 357 | u32 param3, u32 param4) | ||
| 358 | { | ||
| 359 | struct mISDN_ctrl_req cq; | ||
| 360 | |||
| 361 | memset(&cq, 0, sizeof(cq)); | ||
| 362 | cq.op = message; | ||
| 363 | cq.p1 = param1 | (param2 << 8); | ||
| 364 | cq.p2 = param3 | (param4 << 8); | ||
| 365 | if (dsp->ch.peer) | ||
| 366 | dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq); | ||
| 367 | } | ||
| 368 | |||
| 369 | |||
| 370 | /* | ||
| 371 | * do hardware update and set the software/hardware flag | ||
| 372 | * | ||
| 373 | * either a conference or a dsp instance can be given | ||
| 374 | * if only dsp instance is given, the instance is not associated with a conf | ||
| 375 | * and therefore removed. if a conference is given, the dsp is expected to | ||
| 376 | * be member of that conference. | ||
| 377 | */ | ||
| 378 | void | ||
| 379 | dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp) | ||
| 380 | { | ||
| 381 | struct dsp_conf_member *member, *nextm; | ||
| 382 | struct dsp *finddsp; | ||
| 383 | int memb = 0, i, ii, i1, i2; | ||
| 384 | int freeunits[8]; | ||
| 385 | u_char freeslots[256]; | ||
| 386 | int same_hfc = -1, same_pcm = -1, current_conf = -1, | ||
| 387 | all_conf = 1; | ||
| 388 | |||
| 389 | /* dsp gets updated (no conf) */ | ||
| 390 | if (!conf) { | ||
| 391 | if (!dsp) | ||
| 392 | return; | ||
| 393 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 394 | printk(KERN_DEBUG "%s checking dsp %s\n", | ||
| 395 | __func__, dsp->name); | ||
| 396 | one_member: | ||
| 397 | /* remove HFC conference if enabled */ | ||
| 398 | if (dsp->hfc_conf >= 0) { | ||
| 399 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 400 | printk(KERN_DEBUG | ||
| 401 | "%s removing %s from HFC conf %d " | ||
| 402 | "because dsp is split\n", __func__, | ||
| 403 | dsp->name, dsp->hfc_conf); | ||
| 404 | dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_CONF_SPLIT, | ||
| 405 | 0, 0, 0, 0); | ||
| 406 | dsp->hfc_conf = -1; | ||
| 407 | } | ||
| 408 | /* process hw echo */ | ||
| 409 | if (dsp->features.pcm_banks < 1) | ||
| 410 | return; | ||
| 411 | if (!dsp->echo) { | ||
| 412 | /* NO ECHO: remove PCM slot if assigned */ | ||
| 413 | if (dsp->pcm_slot_tx >= 0 || dsp->pcm_slot_rx >= 0) { | ||
| 414 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 415 | printk(KERN_DEBUG "%s removing %s from" | ||
| 416 | " PCM slot %d (TX) %d (RX) because" | ||
| 417 | " dsp is split (no echo)\n", | ||
| 418 | __func__, dsp->name, | ||
| 419 | dsp->pcm_slot_tx, dsp->pcm_slot_rx); | ||
| 420 | dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_DISC, | ||
| 421 | 0, 0, 0, 0); | ||
| 422 | dsp->pcm_slot_tx = -1; | ||
| 423 | dsp->pcm_bank_tx = -1; | ||
| 424 | dsp->pcm_slot_rx = -1; | ||
| 425 | dsp->pcm_bank_rx = -1; | ||
| 426 | } | ||
| 427 | return; | ||
| 428 | } | ||
| 429 | /* ECHO: already echo */ | ||
| 430 | if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_rx < 0 && | ||
| 431 | dsp->pcm_bank_tx == 2 && dsp->pcm_bank_rx == 2) | ||
| 432 | return; | ||
| 433 | /* ECHO: if slot already assigned */ | ||
| 434 | if (dsp->pcm_slot_tx >= 0) { | ||
| 435 | dsp->pcm_slot_rx = dsp->pcm_slot_tx; | ||
| 436 | dsp->pcm_bank_tx = 2; /* 2 means loop */ | ||
| 437 | dsp->pcm_bank_rx = 2; | ||
| 438 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 439 | printk(KERN_DEBUG | ||
| 440 | "%s refresh %s for echo using slot %d\n", | ||
| 441 | __func__, dsp->name, | ||
| 442 | dsp->pcm_slot_tx); | ||
| 443 | dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
| 444 | dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); | ||
| 445 | return; | ||
| 446 | } | ||
| 447 | /* ECHO: find slot */ | ||
| 448 | dsp->pcm_slot_tx = -1; | ||
| 449 | dsp->pcm_slot_rx = -1; | ||
| 450 | memset(freeslots, 1, sizeof(freeslots)); | ||
| 451 | list_for_each_entry(finddsp, &dsp_ilist, list) { | ||
| 452 | if (finddsp->features.pcm_id == dsp->features.pcm_id) { | ||
| 453 | if (finddsp->pcm_slot_rx >= 0 && | ||
| 454 | finddsp->pcm_slot_rx < sizeof(freeslots)) | ||
| 455 | freeslots[finddsp->pcm_slot_tx] = 0; | ||
| 456 | if (finddsp->pcm_slot_tx >= 0 && | ||
| 457 | finddsp->pcm_slot_tx < sizeof(freeslots)) | ||
| 458 | freeslots[finddsp->pcm_slot_rx] = 0; | ||
| 459 | } | ||
| 460 | } | ||
| 461 | i = 0; | ||
| 462 | ii = dsp->features.pcm_slots; | ||
| 463 | while (i < ii) { | ||
| 464 | if (freeslots[i]) | ||
| 465 | break; | ||
| 466 | i++; | ||
| 467 | } | ||
| 468 | if (i == ii) { | ||
| 469 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 470 | printk(KERN_DEBUG | ||
| 471 | "%s no slot available for echo\n", | ||
| 472 | __func__); | ||
| 473 | /* no more slots available */ | ||
| 474 | return; | ||
| 475 | } | ||
| 476 | /* assign free slot */ | ||
| 477 | dsp->pcm_slot_tx = i; | ||
| 478 | dsp->pcm_slot_rx = i; | ||
| 479 | dsp->pcm_bank_tx = 2; /* loop */ | ||
| 480 | dsp->pcm_bank_rx = 2; | ||
| 481 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 482 | printk(KERN_DEBUG | ||
| 483 | "%s assign echo for %s using slot %d\n", | ||
| 484 | __func__, dsp->name, dsp->pcm_slot_tx); | ||
| 485 | dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
| 486 | dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); | ||
| 487 | return; | ||
| 488 | } | ||
| 489 | |||
| 490 | /* conf gets updated (all members) */ | ||
| 491 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 492 | printk(KERN_DEBUG "%s checking conference %d\n", | ||
| 493 | __func__, conf->id); | ||
| 494 | |||
| 495 | if (list_empty(&conf->mlist)) { | ||
| 496 | printk(KERN_ERR "%s: conference whithout members\n", | ||
| 497 | __func__); | ||
| 498 | return; | ||
| 499 | } | ||
| 500 | member = list_entry(conf->mlist.next, struct dsp_conf_member, list); | ||
| 501 | same_hfc = member->dsp->features.hfc_id; | ||
| 502 | same_pcm = member->dsp->features.pcm_id; | ||
| 503 | /* check all members in our conference */ | ||
| 504 | list_for_each_entry(member, &conf->mlist, list) { | ||
| 505 | /* check if member uses mixing */ | ||
| 506 | if (member->dsp->tx_mix) { | ||
| 507 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 508 | printk(KERN_DEBUG | ||
| 509 | "%s dsp %s cannot form a conf, because " | ||
| 510 | "tx_mix is turned on\n", __func__, | ||
| 511 | member->dsp->name); | ||
| 512 | conf_software: | ||
| 513 | list_for_each_entry(member, &conf->mlist, list) { | ||
| 514 | dsp = member->dsp; | ||
| 515 | /* remove HFC conference if enabled */ | ||
| 516 | if (dsp->hfc_conf >= 0) { | ||
| 517 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 518 | printk(KERN_DEBUG | ||
| 519 | "%s removing %s from HFC " | ||
| 520 | "conf %d because not " | ||
| 521 | "possible with hardware\n", | ||
| 522 | __func__, | ||
| 523 | dsp->name, | ||
| 524 | dsp->hfc_conf); | ||
| 525 | dsp_cmx_hw_message(dsp, | ||
| 526 | MISDN_CTRL_HFC_CONF_SPLIT, | ||
| 527 | 0, 0, 0, 0); | ||
| 528 | dsp->hfc_conf = -1; | ||
| 529 | } | ||
| 530 | /* remove PCM slot if assigned */ | ||
| 531 | if (dsp->pcm_slot_tx >= 0 || | ||
| 532 | dsp->pcm_slot_rx >= 0) { | ||
| 533 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 534 | printk(KERN_DEBUG "%s removing " | ||
| 535 | "%s from PCM slot %d (TX)" | ||
| 536 | " slot %d (RX) because not" | ||
| 537 | " possible with hardware\n", | ||
| 538 | __func__, | ||
| 539 | dsp->name, | ||
| 540 | dsp->pcm_slot_tx, | ||
| 541 | dsp->pcm_slot_rx); | ||
| 542 | dsp_cmx_hw_message(dsp, | ||
| 543 | MISDN_CTRL_HFC_PCM_DISC, | ||
| 544 | 0, 0, 0, 0); | ||
| 545 | dsp->pcm_slot_tx = -1; | ||
| 546 | dsp->pcm_bank_tx = -1; | ||
| 547 | dsp->pcm_slot_rx = -1; | ||
| 548 | dsp->pcm_bank_rx = -1; | ||
| 549 | } | ||
| 550 | } | ||
| 551 | conf->hardware = 0; | ||
| 552 | conf->software = 1; | ||
| 553 | return; | ||
| 554 | } | ||
| 555 | /* check if member has echo turned on */ | ||
| 556 | if (member->dsp->echo) { | ||
| 557 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 558 | printk(KERN_DEBUG | ||
| 559 | "%s dsp %s cannot form a conf, because " | ||
| 560 | "echo is turned on\n", __func__, | ||
| 561 | member->dsp->name); | ||
| 562 | goto conf_software; | ||
| 563 | } | ||
| 564 | /* check if member has tx_mix turned on */ | ||
| 565 | if (member->dsp->tx_mix) { | ||
| 566 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 567 | printk(KERN_DEBUG | ||
| 568 | "%s dsp %s cannot form a conf, because " | ||
| 569 | "tx_mix is turned on\n", | ||
| 570 | __func__, member->dsp->name); | ||
| 571 | goto conf_software; | ||
| 572 | } | ||
| 573 | /* check if member changes volume at an not suppoted level */ | ||
| 574 | if (member->dsp->tx_volume) { | ||
| 575 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 576 | printk(KERN_DEBUG | ||
| 577 | "%s dsp %s cannot form a conf, because " | ||
| 578 | "tx_volume is changed\n", | ||
| 579 | __func__, member->dsp->name); | ||
| 580 | goto conf_software; | ||
| 581 | } | ||
| 582 | if (member->dsp->rx_volume) { | ||
| 583 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 584 | printk(KERN_DEBUG | ||
| 585 | "%s dsp %s cannot form a conf, because " | ||
| 586 | "rx_volume is changed\n", | ||
| 587 | __func__, member->dsp->name); | ||
| 588 | goto conf_software; | ||
| 589 | } | ||
| 590 | /* check if tx-data turned on */ | ||
| 591 | if (member->dsp->tx_data) { | ||
| 592 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 593 | printk(KERN_DEBUG | ||
| 594 | "%s dsp %s cannot form a conf, because " | ||
| 595 | "tx_data is turned on\n", | ||
| 596 | __func__, member->dsp->name); | ||
| 597 | goto conf_software; | ||
| 598 | } | ||
| 599 | /* check if pipeline exists */ | ||
| 600 | if (member->dsp->pipeline.inuse) { | ||
| 601 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 602 | printk(KERN_DEBUG | ||
| 603 | "%s dsp %s cannot form a conf, because " | ||
| 604 | "pipeline exists\n", __func__, | ||
| 605 | member->dsp->name); | ||
| 606 | goto conf_software; | ||
| 607 | } | ||
| 608 | /* check if encryption is enabled */ | ||
| 609 | if (member->dsp->bf_enable) { | ||
| 610 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 611 | printk(KERN_DEBUG "%s dsp %s cannot form a " | ||
| 612 | "conf, because encryption is enabled\n", | ||
| 613 | __func__, member->dsp->name); | ||
| 614 | goto conf_software; | ||
| 615 | } | ||
| 616 | /* check if member is on a card with PCM support */ | ||
| 617 | if (member->dsp->features.pcm_id < 0) { | ||
| 618 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 619 | printk(KERN_DEBUG | ||
| 620 | "%s dsp %s cannot form a conf, because " | ||
| 621 | "dsp has no PCM bus\n", | ||
| 622 | __func__, member->dsp->name); | ||
| 623 | goto conf_software; | ||
| 624 | } | ||
| 625 | /* check if relations are on the same PCM bus */ | ||
| 626 | if (member->dsp->features.pcm_id != same_pcm) { | ||
| 627 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 628 | printk(KERN_DEBUG | ||
| 629 | "%s dsp %s cannot form a conf, because " | ||
| 630 | "dsp is on a different PCM bus than the " | ||
| 631 | "first dsp\n", | ||
| 632 | __func__, member->dsp->name); | ||
| 633 | goto conf_software; | ||
| 634 | } | ||
| 635 | /* determine if members are on the same hfc chip */ | ||
| 636 | if (same_hfc != member->dsp->features.hfc_id) | ||
| 637 | same_hfc = -1; | ||
| 638 | /* if there are members already in a conference */ | ||
| 639 | if (current_conf < 0 && member->dsp->hfc_conf >= 0) | ||
| 640 | current_conf = member->dsp->hfc_conf; | ||
| 641 | /* if any member is not in a conference */ | ||
| 642 | if (member->dsp->hfc_conf < 0) | ||
| 643 | all_conf = 0; | ||
| 644 | |||
| 645 | memb++; | ||
| 646 | } | ||
| 647 | |||
| 648 | /* if no member, this is an error */ | ||
| 649 | if (memb < 1) | ||
| 650 | return; | ||
| 651 | |||
| 652 | /* one member */ | ||
| 653 | if (memb == 1) { | ||
| 654 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 655 | printk(KERN_DEBUG | ||
| 656 | "%s conf %d cannot form a HW conference, " | ||
| 657 | "because dsp is alone\n", __func__, conf->id); | ||
| 658 | conf->hardware = 0; | ||
| 659 | conf->software = 0; | ||
| 660 | member = list_entry(conf->mlist.next, struct dsp_conf_member, | ||
| 661 | list); | ||
| 662 | dsp = member->dsp; | ||
| 663 | goto one_member; | ||
| 664 | } | ||
| 665 | |||
| 666 | /* | ||
| 667 | * ok, now we are sure that all members are on the same pcm. | ||
| 668 | * now we will see if we have only two members, so we can do | ||
| 669 | * crossconnections, which don't have any limitations. | ||
| 670 | */ | ||
| 671 | |||
| 672 | /* if we have only two members */ | ||
| 673 | if (memb == 2) { | ||
| 674 | member = list_entry(conf->mlist.next, struct dsp_conf_member, | ||
| 675 | list); | ||
| 676 | nextm = list_entry(member->list.next, struct dsp_conf_member, | ||
| 677 | list); | ||
| 678 | /* remove HFC conference if enabled */ | ||
| 679 | if (member->dsp->hfc_conf >= 0) { | ||
| 680 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 681 | printk(KERN_DEBUG | ||
| 682 | "%s removing %s from HFC conf %d because " | ||
| 683 | "two parties require only a PCM slot\n", | ||
| 684 | __func__, member->dsp->name, | ||
| 685 | member->dsp->hfc_conf); | ||
| 686 | dsp_cmx_hw_message(member->dsp, | ||
| 687 | MISDN_CTRL_HFC_CONF_SPLIT, 0, 0, 0, 0); | ||
| 688 | member->dsp->hfc_conf = -1; | ||
| 689 | } | ||
| 690 | if (nextm->dsp->hfc_conf >= 0) { | ||
| 691 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 692 | printk(KERN_DEBUG | ||
| 693 | "%s removing %s from HFC conf %d because " | ||
| 694 | "two parties require only a PCM slot\n", | ||
| 695 | __func__, nextm->dsp->name, | ||
| 696 | nextm->dsp->hfc_conf); | ||
| 697 | dsp_cmx_hw_message(nextm->dsp, | ||
| 698 | MISDN_CTRL_HFC_CONF_SPLIT, 0, 0, 0, 0); | ||
| 699 | nextm->dsp->hfc_conf = -1; | ||
| 700 | } | ||
| 701 | /* if members have two banks (and not on the same chip) */ | ||
| 702 | if (member->dsp->features.pcm_banks > 1 && | ||
| 703 | nextm->dsp->features.pcm_banks > 1 && | ||
| 704 | member->dsp->features.hfc_id != | ||
| 705 | nextm->dsp->features.hfc_id) { | ||
| 706 | /* if both members have same slots with crossed banks */ | ||
| 707 | if (member->dsp->pcm_slot_tx >= 0 && | ||
| 708 | member->dsp->pcm_slot_rx >= 0 && | ||
| 709 | nextm->dsp->pcm_slot_tx >= 0 && | ||
| 710 | nextm->dsp->pcm_slot_rx >= 0 && | ||
| 711 | nextm->dsp->pcm_slot_tx == | ||
| 712 | member->dsp->pcm_slot_rx && | ||
| 713 | nextm->dsp->pcm_slot_rx == | ||
| 714 | member->dsp->pcm_slot_tx && | ||
| 715 | nextm->dsp->pcm_slot_tx == | ||
| 716 | member->dsp->pcm_slot_tx && | ||
| 717 | member->dsp->pcm_bank_tx != | ||
| 718 | member->dsp->pcm_bank_rx && | ||
| 719 | nextm->dsp->pcm_bank_tx != | ||
| 720 | nextm->dsp->pcm_bank_rx) { | ||
| 721 | /* all members have same slot */ | ||
| 722 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 723 | printk(KERN_DEBUG | ||
| 724 | "%s dsp %s & %s stay joined on " | ||
| 725 | "PCM slot %d bank %d (TX) bank %d " | ||
| 726 | "(RX) (on different chips)\n", | ||
| 727 | __func__, | ||
| 728 | member->dsp->name, | ||
| 729 | nextm->dsp->name, | ||
| 730 | member->dsp->pcm_slot_tx, | ||
| 731 | member->dsp->pcm_bank_tx, | ||
| 732 | member->dsp->pcm_bank_rx); | ||
| 733 | conf->hardware = 0; | ||
| 734 | conf->software = 1; | ||
| 735 | return; | ||
| 736 | } | ||
| 737 | /* find a new slot */ | ||
| 738 | memset(freeslots, 1, sizeof(freeslots)); | ||
| 739 | list_for_each_entry(dsp, &dsp_ilist, list) { | ||
| 740 | if (dsp != member->dsp && | ||
| 741 | dsp != nextm->dsp && | ||
| 742 | member->dsp->features.pcm_id == | ||
| 743 | dsp->features.pcm_id) { | ||
| 744 | if (dsp->pcm_slot_rx >= 0 && | ||
| 745 | dsp->pcm_slot_rx < | ||
| 746 | sizeof(freeslots)) | ||
| 747 | freeslots[dsp->pcm_slot_tx] = 0; | ||
| 748 | if (dsp->pcm_slot_tx >= 0 && | ||
| 749 | dsp->pcm_slot_tx < | ||
| 750 | sizeof(freeslots)) | ||
| 751 | freeslots[dsp->pcm_slot_rx] = 0; | ||
| 752 | } | ||
| 753 | } | ||
| 754 | i = 0; | ||
| 755 | ii = member->dsp->features.pcm_slots; | ||
| 756 | while (i < ii) { | ||
| 757 | if (freeslots[i]) | ||
| 758 | break; | ||
| 759 | i++; | ||
| 760 | } | ||
| 761 | if (i == ii) { | ||
| 762 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 763 | printk(KERN_DEBUG | ||
| 764 | "%s no slot available for " | ||
| 765 | "%s & %s\n", __func__, | ||
| 766 | member->dsp->name, | ||
| 767 | nextm->dsp->name); | ||
| 768 | /* no more slots available */ | ||
| 769 | goto conf_software; | ||
| 770 | } | ||
| 771 | /* assign free slot */ | ||
| 772 | member->dsp->pcm_slot_tx = i; | ||
| 773 | member->dsp->pcm_slot_rx = i; | ||
| 774 | nextm->dsp->pcm_slot_tx = i; | ||
| 775 | nextm->dsp->pcm_slot_rx = i; | ||
| 776 | member->dsp->pcm_bank_rx = 0; | ||
| 777 | member->dsp->pcm_bank_tx = 1; | ||
| 778 | nextm->dsp->pcm_bank_rx = 1; | ||
| 779 | nextm->dsp->pcm_bank_tx = 0; | ||
| 780 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 781 | printk(KERN_DEBUG | ||
| 782 | "%s adding %s & %s to new PCM slot %d " | ||
| 783 | "(TX and RX on different chips) because " | ||
| 784 | "both members have not same slots\n", | ||
| 785 | __func__, | ||
| 786 | member->dsp->name, | ||
| 787 | nextm->dsp->name, | ||
| 788 | member->dsp->pcm_slot_tx); | ||
| 789 | dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
| 790 | member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, | ||
| 791 | member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx); | ||
| 792 | dsp_cmx_hw_message(nextm->dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
| 793 | nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, | ||
| 794 | nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); | ||
| 795 | conf->hardware = 1; | ||
| 796 | conf->software = 0; | ||
| 797 | return; | ||
| 798 | /* if members have one bank (or on the same chip) */ | ||
| 799 | } else { | ||
| 800 | /* if both members have different crossed slots */ | ||
| 801 | if (member->dsp->pcm_slot_tx >= 0 && | ||
| 802 | member->dsp->pcm_slot_rx >= 0 && | ||
| 803 | nextm->dsp->pcm_slot_tx >= 0 && | ||
| 804 | nextm->dsp->pcm_slot_rx >= 0 && | ||
| 805 | nextm->dsp->pcm_slot_tx == | ||
| 806 | member->dsp->pcm_slot_rx && | ||
| 807 | nextm->dsp->pcm_slot_rx == | ||
| 808 | member->dsp->pcm_slot_tx && | ||
| 809 | member->dsp->pcm_slot_tx != | ||
| 810 | member->dsp->pcm_slot_rx && | ||
| 811 | member->dsp->pcm_bank_tx == 0 && | ||
| 812 | member->dsp->pcm_bank_rx == 0 && | ||
| 813 | nextm->dsp->pcm_bank_tx == 0 && | ||
| 814 | nextm->dsp->pcm_bank_rx == 0) { | ||
| 815 | /* all members have same slot */ | ||
| 816 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 817 | printk(KERN_DEBUG | ||
| 818 | "%s dsp %s & %s stay joined on PCM " | ||
| 819 | "slot %d (TX) %d (RX) on same chip " | ||
| 820 | "or one bank PCM)\n", __func__, | ||
| 821 | member->dsp->name, | ||
| 822 | nextm->dsp->name, | ||
| 823 | member->dsp->pcm_slot_tx, | ||
| 824 | member->dsp->pcm_slot_rx); | ||
| 825 | conf->hardware = 0; | ||
| 826 | conf->software = 1; | ||
| 827 | return; | ||
| 828 | } | ||
| 829 | /* find two new slot */ | ||
| 830 | memset(freeslots, 1, sizeof(freeslots)); | ||
| 831 | list_for_each_entry(dsp, &dsp_ilist, list) { | ||
| 832 | if (dsp != member->dsp && | ||
| 833 | dsp != nextm->dsp && | ||
| 834 | member->dsp->features.pcm_id == | ||
| 835 | dsp->features.pcm_id) { | ||
| 836 | if (dsp->pcm_slot_rx >= 0 && | ||
| 837 | dsp->pcm_slot_rx < | ||
| 838 | sizeof(freeslots)) | ||
| 839 | freeslots[dsp->pcm_slot_tx] = 0; | ||
| 840 | if (dsp->pcm_slot_tx >= 0 && | ||
| 841 | dsp->pcm_slot_tx < | ||
| 842 | sizeof(freeslots)) | ||
| 843 | freeslots[dsp->pcm_slot_rx] = 0; | ||
| 844 | } | ||
| 845 | } | ||
| 846 | i1 = 0; | ||
| 847 | ii = member->dsp->features.pcm_slots; | ||
| 848 | while (i1 < ii) { | ||
| 849 | if (freeslots[i1]) | ||
| 850 | break; | ||
| 851 | i1++; | ||
| 852 | } | ||
| 853 | if (i1 == ii) { | ||
| 854 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 855 | printk(KERN_DEBUG | ||
| 856 | "%s no slot available " | ||
| 857 | "for %s & %s\n", __func__, | ||
| 858 | member->dsp->name, | ||
| 859 | nextm->dsp->name); | ||
| 860 | /* no more slots available */ | ||
| 861 | goto conf_software; | ||
| 862 | } | ||
| 863 | i2 = i1+1; | ||
| 864 | while (i2 < ii) { | ||
| 865 | if (freeslots[i2]) | ||
| 866 | break; | ||
| 867 | i2++; | ||
| 868 | } | ||
| 869 | if (i2 == ii) { | ||
| 870 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 871 | printk(KERN_DEBUG | ||
| 872 | "%s no slot available " | ||
| 873 | "for %s & %s\n", | ||
| 874 | __func__, | ||
| 875 | member->dsp->name, | ||
| 876 | nextm->dsp->name); | ||
| 877 | /* no more slots available */ | ||
| 878 | goto conf_software; | ||
| 879 | } | ||
| 880 | /* assign free slots */ | ||
| 881 | member->dsp->pcm_slot_tx = i1; | ||
| 882 | member->dsp->pcm_slot_rx = i2; | ||
| 883 | nextm->dsp->pcm_slot_tx = i2; | ||
| 884 | nextm->dsp->pcm_slot_rx = i1; | ||
| 885 | member->dsp->pcm_bank_rx = 0; | ||
| 886 | member->dsp->pcm_bank_tx = 0; | ||
| 887 | nextm->dsp->pcm_bank_rx = 0; | ||
| 888 | nextm->dsp->pcm_bank_tx = 0; | ||
| 889 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 890 | printk(KERN_DEBUG | ||
| 891 | "%s adding %s & %s to new PCM slot %d " | ||
| 892 | "(TX) %d (RX) on same chip or one bank " | ||
| 893 | "PCM, because both members have not " | ||
| 894 | "crossed slots\n", __func__, | ||
| 895 | member->dsp->name, | ||
| 896 | nextm->dsp->name, | ||
| 897 | member->dsp->pcm_slot_tx, | ||
| 898 | member->dsp->pcm_slot_rx); | ||
| 899 | dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
| 900 | member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, | ||
| 901 | member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx); | ||
| 902 | dsp_cmx_hw_message(nextm->dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
| 903 | nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, | ||
| 904 | nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); | ||
| 905 | conf->hardware = 1; | ||
| 906 | conf->software = 0; | ||
| 907 | return; | ||
| 908 | } | ||
| 909 | } | ||
| 910 | |||
| 911 | /* | ||
| 912 | * if we have more than two, we may check if we have a conference | ||
| 913 | * unit available on the chip. also all members must be on the same | ||
| 914 | */ | ||
| 915 | |||
| 916 | /* if not the same HFC chip */ | ||
| 917 | if (same_hfc < 0) { | ||
| 918 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 919 | printk(KERN_DEBUG | ||
| 920 | "%s conference %d cannot be formed, because " | ||
| 921 | "members are on different chips or not " | ||
| 922 | "on HFC chip\n", | ||
| 923 | __func__, conf->id); | ||
| 924 | goto conf_software; | ||
| 925 | } | ||
| 926 | |||
| 927 | /* for more than two members.. */ | ||
| 928 | |||
| 929 | /* in case of hdlc, we change to software */ | ||
| 930 | if (dsp->hdlc) | ||
| 931 | goto conf_software; | ||
| 932 | |||
| 933 | /* if all members already have the same conference */ | ||
| 934 | if (all_conf) | ||
| 935 | return; | ||
| 936 | |||
| 937 | /* | ||
| 938 | * if there is an existing conference, but not all members have joined | ||
| 939 | */ | ||
| 940 | if (current_conf >= 0) { | ||
| 941 | join_members: | ||
| 942 | list_for_each_entry(member, &conf->mlist, list) { | ||
| 943 | /* join to current conference */ | ||
| 944 | if (member->dsp->hfc_conf == current_conf) | ||
| 945 | continue; | ||
| 946 | /* get a free timeslot first */ | ||
| 947 | memset(freeslots, 1, sizeof(freeslots)); | ||
| 948 | list_for_each_entry(dsp, &dsp_ilist, list) { | ||
| 949 | /* | ||
| 950 | * not checking current member, because | ||
| 951 | * slot will be overwritten. | ||
| 952 | */ | ||
| 953 | if ( | ||
| 954 | dsp != member->dsp && | ||
| 955 | /* dsp must be on the same PCM */ | ||
| 956 | member->dsp->features.pcm_id == | ||
| 957 | dsp->features.pcm_id) { | ||
| 958 | /* dsp must be on a slot */ | ||
| 959 | if (dsp->pcm_slot_tx >= 0 && | ||
| 960 | dsp->pcm_slot_tx < | ||
| 961 | sizeof(freeslots)) | ||
| 962 | freeslots[dsp->pcm_slot_tx] = 0; | ||
| 963 | if (dsp->pcm_slot_rx >= 0 && | ||
| 964 | dsp->pcm_slot_rx < | ||
| 965 | sizeof(freeslots)) | ||
| 966 | freeslots[dsp->pcm_slot_rx] = 0; | ||
| 967 | } | ||
| 968 | } | ||
| 969 | i = 0; | ||
| 970 | ii = member->dsp->features.pcm_slots; | ||
| 971 | while (i < ii) { | ||
| 972 | if (freeslots[i]) | ||
| 973 | break; | ||
| 974 | i++; | ||
| 975 | } | ||
| 976 | if (i == ii) { | ||
| 977 | /* no more slots available */ | ||
| 978 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 979 | printk(KERN_DEBUG | ||
| 980 | "%s conference %d cannot be formed," | ||
| 981 | " because no slot free\n", | ||
| 982 | __func__, conf->id); | ||
| 983 | goto conf_software; | ||
| 984 | } | ||
| 985 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 986 | printk(KERN_DEBUG | ||
| 987 | "%s changing dsp %s to HW conference " | ||
| 988 | "%d slot %d\n", __func__, | ||
| 989 | member->dsp->name, current_conf, i); | ||
| 990 | /* assign free slot & set PCM & join conf */ | ||
| 991 | member->dsp->pcm_slot_tx = i; | ||
| 992 | member->dsp->pcm_slot_rx = i; | ||
| 993 | member->dsp->pcm_bank_tx = 2; /* loop */ | ||
| 994 | member->dsp->pcm_bank_rx = 2; | ||
| 995 | member->dsp->hfc_conf = current_conf; | ||
| 996 | dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN, | ||
| 997 | i, 2, i, 2); | ||
| 998 | dsp_cmx_hw_message(member->dsp, | ||
| 999 | MISDN_CTRL_HFC_CONF_JOIN, current_conf, 0, 0, 0); | ||
| 1000 | } | ||
| 1001 | return; | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | /* | ||
| 1005 | * no member is in a conference yet, so we find a free one | ||
| 1006 | */ | ||
| 1007 | memset(freeunits, 1, sizeof(freeunits)); | ||
| 1008 | list_for_each_entry(dsp, &dsp_ilist, list) { | ||
| 1009 | /* dsp must be on the same chip */ | ||
| 1010 | if (dsp->features.hfc_id == same_hfc && | ||
| 1011 | /* dsp must have joined a HW conference */ | ||
| 1012 | dsp->hfc_conf >= 0 && | ||
| 1013 | /* slot must be within range */ | ||
| 1014 | dsp->hfc_conf < 8) | ||
| 1015 | freeunits[dsp->hfc_conf] = 0; | ||
| 1016 | } | ||
| 1017 | i = 0; | ||
| 1018 | ii = 8; | ||
| 1019 | while (i < ii) { | ||
| 1020 | if (freeunits[i]) | ||
| 1021 | break; | ||
| 1022 | i++; | ||
| 1023 | } | ||
| 1024 | if (i == ii) { | ||
| 1025 | /* no more conferences available */ | ||
| 1026 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 1027 | printk(KERN_DEBUG | ||
| 1028 | "%s conference %d cannot be formed, because " | ||
| 1029 | "no conference number free\n", | ||
| 1030 | __func__, conf->id); | ||
| 1031 | goto conf_software; | ||
| 1032 | } | ||
| 1033 | /* join all members */ | ||
| 1034 | current_conf = i; | ||
| 1035 | goto join_members; | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | |||
| 1039 | /* | ||
| 1040 | * conf_id != 0: join or change conference | ||
| 1041 | * conf_id == 0: split from conference if not already | ||
| 1042 | */ | ||
| 1043 | int | ||
| 1044 | dsp_cmx_conf(struct dsp *dsp, u32 conf_id) | ||
| 1045 | { | ||
| 1046 | int err; | ||
| 1047 | struct dsp_conf *conf; | ||
| 1048 | struct dsp_conf_member *member; | ||
| 1049 | |||
| 1050 | /* if conference doesn't change */ | ||
| 1051 | if (dsp->conf_id == conf_id) | ||
| 1052 | return 0; | ||
| 1053 | |||
| 1054 | /* first remove us from current conf */ | ||
| 1055 | if (dsp->conf_id) { | ||
| 1056 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 1057 | printk(KERN_DEBUG "removing us from conference %d\n", | ||
| 1058 | dsp->conf->id); | ||
| 1059 | /* remove us from conf */ | ||
| 1060 | conf = dsp->conf; | ||
| 1061 | err = dsp_cmx_del_conf_member(dsp); | ||
| 1062 | if (err) | ||
| 1063 | return err; | ||
| 1064 | dsp->conf_id = 0; | ||
| 1065 | |||
| 1066 | /* update hardware */ | ||
| 1067 | dsp_cmx_hardware(NULL, dsp); | ||
| 1068 | |||
| 1069 | /* conf now empty? */ | ||
| 1070 | if (list_empty(&conf->mlist)) { | ||
| 1071 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 1072 | printk(KERN_DEBUG | ||
| 1073 | "conference is empty, so we remove it.\n"); | ||
| 1074 | err = dsp_cmx_del_conf(conf); | ||
| 1075 | if (err) | ||
| 1076 | return err; | ||
| 1077 | } else { | ||
| 1078 | /* update members left on conf */ | ||
| 1079 | dsp_cmx_hardware(conf, NULL); | ||
| 1080 | } | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | /* if split */ | ||
| 1084 | if (!conf_id) | ||
| 1085 | return 0; | ||
| 1086 | |||
| 1087 | /* now add us to conf */ | ||
| 1088 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 1089 | printk(KERN_DEBUG "searching conference %d\n", | ||
| 1090 | conf_id); | ||
| 1091 | conf = dsp_cmx_search_conf(conf_id); | ||
| 1092 | if (!conf) { | ||
| 1093 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 1094 | printk(KERN_DEBUG | ||
| 1095 | "conference doesn't exist yet, creating.\n"); | ||
| 1096 | /* the conference doesn't exist, so we create */ | ||
| 1097 | conf = dsp_cmx_new_conf(conf_id); | ||
| 1098 | if (!conf) | ||
| 1099 | return -EINVAL; | ||
| 1100 | } else if (!list_empty(&conf->mlist)) { | ||
| 1101 | member = list_entry(conf->mlist.next, struct dsp_conf_member, | ||
| 1102 | list); | ||
| 1103 | if (dsp->hdlc && !member->dsp->hdlc) { | ||
| 1104 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 1105 | printk(KERN_DEBUG | ||
| 1106 | "cannot join transparent conference.\n"); | ||
| 1107 | return -EINVAL; | ||
| 1108 | } | ||
| 1109 | if (!dsp->hdlc && member->dsp->hdlc) { | ||
| 1110 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 1111 | printk(KERN_DEBUG | ||
| 1112 | "cannot join hdlc conference.\n"); | ||
| 1113 | return -EINVAL; | ||
| 1114 | } | ||
| 1115 | } | ||
| 1116 | /* add conference member */ | ||
| 1117 | err = dsp_cmx_add_conf_member(dsp, conf); | ||
| 1118 | if (err) | ||
| 1119 | return err; | ||
| 1120 | dsp->conf_id = conf_id; | ||
| 1121 | |||
| 1122 | /* if we are alone, we do nothing! */ | ||
| 1123 | if (list_empty(&conf->mlist)) { | ||
| 1124 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 1125 | printk(KERN_DEBUG | ||
| 1126 | "we are alone in this conference, so exit.\n"); | ||
| 1127 | /* update hardware */ | ||
| 1128 | dsp_cmx_hardware(NULL, dsp); | ||
| 1129 | return 0; | ||
| 1130 | } | ||
| 1131 | |||
| 1132 | /* update members on conf */ | ||
| 1133 | dsp_cmx_hardware(conf, NULL); | ||
| 1134 | |||
| 1135 | return 0; | ||
| 1136 | } | ||
| 1137 | |||
| 1138 | |||
| 1139 | /* | ||
| 1140 | * audio data is received from card | ||
| 1141 | */ | ||
| 1142 | void | ||
| 1143 | dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb) | ||
| 1144 | { | ||
| 1145 | u8 *d, *p; | ||
| 1146 | int len = skb->len; | ||
| 1147 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
| 1148 | int w, i, ii; | ||
| 1149 | |||
| 1150 | /* check if we have sompen */ | ||
| 1151 | if (len < 1) | ||
| 1152 | return; | ||
| 1153 | |||
| 1154 | /* half of the buffer should be larger than maximum packet size */ | ||
| 1155 | if (len >= CMX_BUFF_HALF) { | ||
| 1156 | printk(KERN_ERR | ||
| 1157 | "%s line %d: packet from card is too large (%d bytes). " | ||
| 1158 | "please make card send smaller packets OR increase " | ||
| 1159 | "CMX_BUFF_SIZE\n", __FILE__, __LINE__, len); | ||
| 1160 | return; | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | /* | ||
| 1164 | * initialize pointers if not already - | ||
| 1165 | * also add delay if requested by PH_SIGNAL | ||
| 1166 | */ | ||
| 1167 | if (dsp->rx_init) { | ||
| 1168 | dsp->rx_init = 0; | ||
| 1169 | if (dsp->features.unordered) { | ||
| 1170 | dsp->rx_R = (hh->id & CMX_BUFF_MASK); | ||
| 1171 | dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) | ||
| 1172 | & CMX_BUFF_MASK; | ||
| 1173 | } else { | ||
| 1174 | dsp->rx_R = 0; | ||
| 1175 | dsp->rx_W = dsp->cmx_delay; | ||
| 1176 | } | ||
| 1177 | } | ||
| 1178 | /* if frame contains time code, write directly */ | ||
| 1179 | if (dsp->features.unordered) { | ||
| 1180 | dsp->rx_W = (hh->id & CMX_BUFF_MASK); | ||
| 1181 | /* printk(KERN_DEBUG "%s %08x\n", dsp->name, hh->id); */ | ||
| 1182 | } | ||
| 1183 | /* | ||
| 1184 | * if we underrun (or maybe overrun), | ||
| 1185 | * we set our new read pointer, and write silence to buffer | ||
| 1186 | */ | ||
| 1187 | if (((dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK) >= CMX_BUFF_HALF) { | ||
| 1188 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 1189 | printk(KERN_DEBUG | ||
| 1190 | "cmx_receive(dsp=%lx): UNDERRUN (or overrun the " | ||
| 1191 | "maximum delay), adjusting read pointer! " | ||
| 1192 | "(inst %s)\n", (u_long)dsp, dsp->name); | ||
| 1193 | /* flush buffer */ | ||
| 1194 | if (dsp->features.unordered) { | ||
| 1195 | dsp->rx_R = (hh->id & CMX_BUFF_MASK); | ||
| 1196 | dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) | ||
| 1197 | & CMX_BUFF_MASK; | ||
| 1198 | } else { | ||
| 1199 | dsp->rx_R = 0; | ||
| 1200 | dsp->rx_W = dsp->cmx_delay; | ||
| 1201 | } | ||
| 1202 | memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff)); | ||
| 1203 | } | ||
| 1204 | /* if we have reached double delay, jump back to middle */ | ||
| 1205 | if (dsp->cmx_delay) | ||
| 1206 | if (((dsp->rx_W - dsp->rx_R) & CMX_BUFF_MASK) >= | ||
| 1207 | (dsp->cmx_delay << 1)) { | ||
| 1208 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 1209 | printk(KERN_DEBUG | ||
| 1210 | "cmx_receive(dsp=%lx): OVERRUN (because " | ||
| 1211 | "twice the delay is reached), adjusting " | ||
| 1212 | "read pointer! (inst %s)\n", | ||
| 1213 | (u_long)dsp, dsp->name); | ||
| 1214 | /* flush buffer */ | ||
| 1215 | if (dsp->features.unordered) { | ||
| 1216 | dsp->rx_R = (hh->id & CMX_BUFF_MASK); | ||
| 1217 | dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) | ||
| 1218 | & CMX_BUFF_MASK; | ||
| 1219 | } else { | ||
| 1220 | dsp->rx_R = 0; | ||
| 1221 | dsp->rx_W = dsp->cmx_delay; | ||
| 1222 | } | ||
| 1223 | memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff)); | ||
| 1224 | } | ||
| 1225 | |||
| 1226 | /* show where to write */ | ||
| 1227 | #ifdef CMX_DEBUG | ||
| 1228 | printk(KERN_DEBUG | ||
| 1229 | "cmx_receive(dsp=%lx): rx_R(dsp)=%05x rx_W(dsp)=%05x len=%d %s\n", | ||
| 1230 | (u_long)dsp, dsp->rx_R, dsp->rx_W, len, dsp->name); | ||
| 1231 | #endif | ||
| 1232 | |||
| 1233 | /* write data into rx_buffer */ | ||
| 1234 | p = skb->data; | ||
| 1235 | d = dsp->rx_buff; | ||
| 1236 | w = dsp->rx_W; | ||
| 1237 | i = 0; | ||
| 1238 | ii = len; | ||
| 1239 | while (i < ii) { | ||
| 1240 | d[w++ & CMX_BUFF_MASK] = *p++; | ||
| 1241 | i++; | ||
| 1242 | } | ||
| 1243 | |||
| 1244 | /* increase write-pointer */ | ||
| 1245 | dsp->rx_W = ((dsp->rx_W+len) & CMX_BUFF_MASK); | ||
| 1246 | } | ||
| 1247 | |||
| 1248 | |||
| 1249 | /* | ||
| 1250 | * send (mixed) audio data to card and control jitter | ||
| 1251 | */ | ||
| 1252 | static void | ||
| 1253 | dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) | ||
| 1254 | { | ||
| 1255 | struct dsp_conf *conf = dsp->conf; | ||
| 1256 | struct dsp *member, *other; | ||
| 1257 | register s32 sample; | ||
| 1258 | u8 *d, *p, *q, *o_q; | ||
| 1259 | struct sk_buff *nskb, *txskb; | ||
| 1260 | int r, rr, t, tt, o_r, o_rr; | ||
| 1261 | int preload = 0; | ||
| 1262 | struct mISDNhead *hh, *thh; | ||
| 1263 | |||
| 1264 | /* don't process if: */ | ||
| 1265 | if (!dsp->b_active) { /* if not active */ | ||
| 1266 | dsp->last_tx = 0; | ||
| 1267 | return; | ||
| 1268 | } | ||
| 1269 | if (dsp->pcm_slot_tx >= 0 && /* connected to pcm slot */ | ||
| 1270 | dsp->tx_R == dsp->tx_W && /* AND no tx-data */ | ||
| 1271 | !(dsp->tone.tone && dsp->tone.software)) { /* AND not soft tones */ | ||
| 1272 | dsp->last_tx = 0; | ||
| 1273 | return; | ||
| 1274 | } | ||
| 1275 | |||
| 1276 | #ifdef CMX_DEBUG | ||
| 1277 | printk(KERN_DEBUG | ||
| 1278 | "SEND members=%d dsp=%s, conf=%p, rx_R=%05x rx_W=%05x\n", | ||
| 1279 | members, dsp->name, conf, dsp->rx_R, dsp->rx_W); | ||
| 1280 | #endif | ||
| 1281 | |||
| 1282 | /* preload if we have delay set */ | ||
| 1283 | if (dsp->cmx_delay && !dsp->last_tx) { | ||
| 1284 | preload = len; | ||
| 1285 | if (preload < 128) | ||
| 1286 | preload = 128; | ||
| 1287 | } | ||
| 1288 | |||
| 1289 | /* PREPARE RESULT */ | ||
| 1290 | nskb = mI_alloc_skb(len + preload, GFP_ATOMIC); | ||
| 1291 | if (!nskb) { | ||
| 1292 | printk(KERN_ERR | ||
| 1293 | "FATAL ERROR in mISDN_dsp.o: cannot alloc %d bytes\n", | ||
| 1294 | len + preload); | ||
| 1295 | return; | ||
| 1296 | } | ||
| 1297 | hh = mISDN_HEAD_P(nskb); | ||
| 1298 | hh->prim = PH_DATA_REQ; | ||
| 1299 | hh->id = 0; | ||
| 1300 | dsp->last_tx = 1; | ||
| 1301 | |||
| 1302 | /* set pointers, indexes and stuff */ | ||
| 1303 | member = dsp; | ||
| 1304 | p = dsp->tx_buff; /* transmit data */ | ||
| 1305 | q = dsp->rx_buff; /* received data */ | ||
| 1306 | d = skb_put(nskb, preload + len); /* result */ | ||
| 1307 | t = dsp->tx_R; /* tx-pointers */ | ||
| 1308 | tt = dsp->tx_W; | ||
| 1309 | r = dsp->rx_R; /* rx-pointers */ | ||
| 1310 | rr = (r + len) & CMX_BUFF_MASK; | ||
| 1311 | |||
| 1312 | /* preload with silence, if required */ | ||
| 1313 | if (preload) { | ||
| 1314 | memset(d, dsp_silence, preload); | ||
| 1315 | d += preload; | ||
| 1316 | } | ||
| 1317 | |||
| 1318 | /* PROCESS TONES/TX-DATA ONLY */ | ||
| 1319 | if (dsp->tone.tone && dsp->tone.software) { | ||
| 1320 | /* -> copy tone */ | ||
| 1321 | dsp_tone_copy(dsp, d, len); | ||
| 1322 | dsp->tx_R = 0; /* clear tx buffer */ | ||
| 1323 | dsp->tx_W = 0; | ||
| 1324 | goto send_packet; | ||
| 1325 | } | ||
| 1326 | /* if we have tx-data but do not use mixing */ | ||
| 1327 | if (!dsp->tx_mix && t != tt) { | ||
| 1328 | /* -> send tx-data and continue when not enough */ | ||
| 1329 | #ifdef CMX_TX_DEBUG | ||
| 1330 | sprintf(debugbuf, "TX sending (%04x-%04x)%p: ", t, tt, p); | ||
| 1331 | #endif | ||
| 1332 | while (r != rr && t != tt) { | ||
| 1333 | #ifdef CMX_TX_DEBUG | ||
| 1334 | if (strlen(debugbuf) < 48) | ||
| 1335 | sprintf(debugbuf+strlen(debugbuf), " %02x", p[t]); | ||
| 1336 | #endif | ||
| 1337 | *d++ = p[t]; /* write tx_buff */ | ||
| 1338 | t = (t+1) & CMX_BUFF_MASK; | ||
| 1339 | r = (r+1) & CMX_BUFF_MASK; | ||
| 1340 | } | ||
| 1341 | if (r == rr) { | ||
| 1342 | dsp->tx_R = t; | ||
| 1343 | #ifdef CMX_TX_DEBUG | ||
| 1344 | printk(KERN_DEBUG "%s\n", debugbuf); | ||
| 1345 | #endif | ||
| 1346 | goto send_packet; | ||
| 1347 | } | ||
| 1348 | } | ||
| 1349 | #ifdef CMX_TX_DEBUG | ||
| 1350 | printk(KERN_DEBUG "%s\n", debugbuf); | ||
| 1351 | #endif | ||
| 1352 | |||
| 1353 | /* PROCESS DATA (one member / no conf) */ | ||
| 1354 | if (!conf || members <= 1) { | ||
| 1355 | /* -> if echo is NOT enabled */ | ||
| 1356 | if (!dsp->echo) { | ||
| 1357 | /* -> send tx-data if available or use 0-volume */ | ||
| 1358 | while (r != rr && t != tt) { | ||
| 1359 | *d++ = p[t]; /* write tx_buff */ | ||
| 1360 | t = (t+1) & CMX_BUFF_MASK; | ||
| 1361 | r = (r+1) & CMX_BUFF_MASK; | ||
| 1362 | } | ||
| 1363 | if (r != rr) | ||
| 1364 | memset(d, dsp_silence, (rr-r)&CMX_BUFF_MASK); | ||
| 1365 | /* -> if echo is enabled */ | ||
| 1366 | } else { | ||
| 1367 | /* | ||
| 1368 | * -> mix tx-data with echo if available, | ||
| 1369 | * or use echo only | ||
| 1370 | */ | ||
| 1371 | while (r != rr && t != tt) { | ||
| 1372 | *d++ = dsp_audio_mix_law[(p[t]<<8)|q[r]]; | ||
| 1373 | t = (t+1) & CMX_BUFF_MASK; | ||
| 1374 | r = (r+1) & CMX_BUFF_MASK; | ||
| 1375 | } | ||
| 1376 | while (r != rr) { | ||
| 1377 | *d++ = q[r]; /* echo */ | ||
| 1378 | r = (r+1) & CMX_BUFF_MASK; | ||
| 1379 | } | ||
| 1380 | } | ||
| 1381 | dsp->tx_R = t; | ||
| 1382 | goto send_packet; | ||
| 1383 | } | ||
| 1384 | /* PROCESS DATA (two members) */ | ||
| 1385 | #ifdef CMX_CONF_DEBUG | ||
| 1386 | if (0) { | ||
| 1387 | #else | ||
| 1388 | if (members == 2) { | ||
| 1389 | #endif | ||
| 1390 | /* "other" becomes other party */ | ||
| 1391 | other = (list_entry(conf->mlist.next, | ||
| 1392 | struct dsp_conf_member, list))->dsp; | ||
| 1393 | if (other == member) | ||
| 1394 | other = (list_entry(conf->mlist.prev, | ||
| 1395 | struct dsp_conf_member, list))->dsp; | ||
| 1396 | o_q = other->rx_buff; /* received data */ | ||
| 1397 | o_rr = (other->rx_R + len) & CMX_BUFF_MASK; | ||
| 1398 | /* end of rx-pointer */ | ||
| 1399 | o_r = (o_rr - rr + r) & CMX_BUFF_MASK; | ||
| 1400 | /* start rx-pointer at current read position*/ | ||
| 1401 | /* -> if echo is NOT enabled */ | ||
| 1402 | if (!dsp->echo) { | ||
| 1403 | /* | ||
| 1404 | * -> copy other member's rx-data, | ||
| 1405 | * if tx-data is available, mix | ||
| 1406 | */ | ||
| 1407 | while (o_r != o_rr && t != tt) { | ||
| 1408 | *d++ = dsp_audio_mix_law[(p[t]<<8)|o_q[o_r]]; | ||
| 1409 | t = (t+1) & CMX_BUFF_MASK; | ||
| 1410 | o_r = (o_r+1) & CMX_BUFF_MASK; | ||
| 1411 | } | ||
| 1412 | while (o_r != o_rr) { | ||
| 1413 | *d++ = o_q[o_r]; | ||
| 1414 | o_r = (o_r+1) & CMX_BUFF_MASK; | ||
| 1415 | } | ||
| 1416 | /* -> if echo is enabled */ | ||
| 1417 | } else { | ||
| 1418 | /* | ||
| 1419 | * -> mix other member's rx-data with echo, | ||
| 1420 | * if tx-data is available, mix | ||
| 1421 | */ | ||
| 1422 | while (r != rr && t != tt) { | ||
| 1423 | sample = dsp_audio_law_to_s32[p[t]] + | ||
| 1424 | dsp_audio_law_to_s32[q[r]] + | ||
| 1425 | dsp_audio_law_to_s32[o_q[o_r]]; | ||
| 1426 | if (sample < -32768) | ||
| 1427 | sample = -32768; | ||
| 1428 | else if (sample > 32767) | ||
| 1429 | sample = 32767; | ||
| 1430 | *d++ = dsp_audio_s16_to_law[sample & 0xffff]; | ||
| 1431 | /* tx-data + rx_data + echo */ | ||
| 1432 | t = (t+1) & CMX_BUFF_MASK; | ||
| 1433 | r = (r+1) & CMX_BUFF_MASK; | ||
| 1434 | o_r = (o_r+1) & CMX_BUFF_MASK; | ||
| 1435 | } | ||
| 1436 | while (r != rr) { | ||
| 1437 | *d++ = dsp_audio_mix_law[(q[r]<<8)|o_q[o_r]]; | ||
| 1438 | r = (r+1) & CMX_BUFF_MASK; | ||
| 1439 | o_r = (o_r+1) & CMX_BUFF_MASK; | ||
| 1440 | } | ||
| 1441 | } | ||
| 1442 | dsp->tx_R = t; | ||
| 1443 | goto send_packet; | ||
| 1444 | } | ||
| 1445 | #ifdef DSP_NEVER_DEFINED | ||
| 1446 | } | ||
| 1447 | #endif | ||
| 1448 | /* PROCESS DATA (three or more members) */ | ||
| 1449 | /* -> if echo is NOT enabled */ | ||
| 1450 | if (!dsp->echo) { | ||
| 1451 | /* | ||
| 1452 | * -> substract rx-data from conf-data, | ||
| 1453 | * if tx-data is available, mix | ||
| 1454 | */ | ||
| 1455 | while (r != rr && t != tt) { | ||
| 1456 | sample = dsp_audio_law_to_s32[p[t]] + *c++ - | ||
| 1457 | dsp_audio_law_to_s32[q[r]]; | ||
| 1458 | if (sample < -32768) | ||
| 1459 | sample = -32768; | ||
| 1460 | else if (sample > 32767) | ||
| 1461 | sample = 32767; | ||
| 1462 | *d++ = dsp_audio_s16_to_law[sample & 0xffff]; | ||
| 1463 | /* conf-rx+tx */ | ||
| 1464 | r = (r+1) & CMX_BUFF_MASK; | ||
| 1465 | t = (t+1) & CMX_BUFF_MASK; | ||
| 1466 | } | ||
| 1467 | while (r != rr) { | ||
| 1468 | sample = *c++ - dsp_audio_law_to_s32[q[r]]; | ||
| 1469 | if (sample < -32768) | ||
| 1470 | sample = -32768; | ||
| 1471 | else if (sample > 32767) | ||
| 1472 | sample = 32767; | ||
| 1473 | *d++ = dsp_audio_s16_to_law[sample & 0xffff]; | ||
| 1474 | /* conf-rx */ | ||
| 1475 | r = (r+1) & CMX_BUFF_MASK; | ||
| 1476 | } | ||
| 1477 | /* -> if echo is enabled */ | ||
| 1478 | } else { | ||
| 1479 | /* | ||
| 1480 | * -> encode conf-data, if tx-data | ||
| 1481 | * is available, mix | ||
| 1482 | */ | ||
| 1483 | while (r != rr && t != tt) { | ||
| 1484 | sample = dsp_audio_law_to_s32[p[t]] + *c++; | ||
| 1485 | if (sample < -32768) | ||
| 1486 | sample = -32768; | ||
| 1487 | else if (sample > 32767) | ||
| 1488 | sample = 32767; | ||
| 1489 | *d++ = dsp_audio_s16_to_law[sample & 0xffff]; | ||
| 1490 | /* conf(echo)+tx */ | ||
| 1491 | t = (t+1) & CMX_BUFF_MASK; | ||
| 1492 | r = (r+1) & CMX_BUFF_MASK; | ||
| 1493 | } | ||
| 1494 | while (r != rr) { | ||
| 1495 | sample = *c++; | ||
| 1496 | if (sample < -32768) | ||
| 1497 | sample = -32768; | ||
| 1498 | else if (sample > 32767) | ||
| 1499 | sample = 32767; | ||
| 1500 | *d++ = dsp_audio_s16_to_law[sample & 0xffff]; | ||
| 1501 | /* conf(echo) */ | ||
| 1502 | r = (r+1) & CMX_BUFF_MASK; | ||
| 1503 | } | ||
| 1504 | } | ||
| 1505 | dsp->tx_R = t; | ||
| 1506 | goto send_packet; | ||
| 1507 | |||
| 1508 | send_packet: | ||
| 1509 | /* | ||
| 1510 | * send tx-data if enabled - don't filter, | ||
| 1511 | * becuase we want what we send, not what we filtered | ||
| 1512 | */ | ||
| 1513 | if (dsp->tx_data) { | ||
| 1514 | /* PREPARE RESULT */ | ||
| 1515 | txskb = mI_alloc_skb(len, GFP_ATOMIC); | ||
| 1516 | if (!txskb) { | ||
| 1517 | printk(KERN_ERR | ||
| 1518 | "FATAL ERROR in mISDN_dsp.o: " | ||
| 1519 | "cannot alloc %d bytes\n", len); | ||
| 1520 | } else { | ||
| 1521 | thh = mISDN_HEAD_P(txskb); | ||
| 1522 | thh->prim = DL_DATA_REQ; | ||
| 1523 | thh->id = 0; | ||
| 1524 | memcpy(skb_put(txskb, len), nskb->data+preload, len); | ||
| 1525 | /* queue (trigger later) */ | ||
| 1526 | skb_queue_tail(&dsp->sendq, txskb); | ||
| 1527 | } | ||
| 1528 | } | ||
| 1529 | /* adjust volume */ | ||
| 1530 | if (dsp->tx_volume) | ||
| 1531 | dsp_change_volume(nskb, dsp->tx_volume); | ||
| 1532 | /* pipeline */ | ||
| 1533 | if (dsp->pipeline.inuse) | ||
| 1534 | dsp_pipeline_process_tx(&dsp->pipeline, nskb->data, nskb->len); | ||
| 1535 | /* crypt */ | ||
| 1536 | if (dsp->bf_enable) | ||
| 1537 | dsp_bf_encrypt(dsp, nskb->data, nskb->len); | ||
| 1538 | /* queue and trigger */ | ||
| 1539 | skb_queue_tail(&dsp->sendq, nskb); | ||
| 1540 | schedule_work(&dsp->workq); | ||
| 1541 | } | ||
| 1542 | |||
| 1543 | u32 samplecount; | ||
| 1544 | struct timer_list dsp_spl_tl; | ||
| 1545 | u32 dsp_spl_jiffies; /* calculate the next time to fire */ | ||
| 1546 | u32 dsp_start_jiffies; /* jiffies at the time, the calculation begins */ | ||
| 1547 | struct timeval dsp_start_tv; /* time at start of calculation */ | ||
| 1548 | |||
| 1549 | void | ||
| 1550 | dsp_cmx_send(void *arg) | ||
| 1551 | { | ||
| 1552 | struct dsp_conf *conf; | ||
| 1553 | struct dsp_conf_member *member; | ||
| 1554 | struct dsp *dsp; | ||
| 1555 | int mustmix, members; | ||
| 1556 | s32 mixbuffer[MAX_POLL+100], *c; | ||
| 1557 | u8 *p, *q; | ||
| 1558 | int r, rr; | ||
| 1559 | int jittercheck = 0, delay, i; | ||
| 1560 | u_long flags; | ||
| 1561 | struct timeval tv; | ||
| 1562 | u32 elapsed; | ||
| 1563 | s16 length; | ||
| 1564 | |||
| 1565 | /* lock */ | ||
| 1566 | spin_lock_irqsave(&dsp_lock, flags); | ||
| 1567 | |||
| 1568 | if (!dsp_start_tv.tv_sec) { | ||
| 1569 | do_gettimeofday(&dsp_start_tv); | ||
| 1570 | length = dsp_poll; | ||
| 1571 | } else { | ||
| 1572 | do_gettimeofday(&tv); | ||
| 1573 | elapsed = ((tv.tv_sec - dsp_start_tv.tv_sec) * 8000) | ||
| 1574 | + ((s32)(tv.tv_usec / 125) - (dsp_start_tv.tv_usec / 125)); | ||
| 1575 | dsp_start_tv.tv_sec = tv.tv_sec; | ||
| 1576 | dsp_start_tv.tv_usec = tv.tv_usec; | ||
| 1577 | length = elapsed; | ||
| 1578 | } | ||
| 1579 | if (length > MAX_POLL + 100) | ||
| 1580 | length = MAX_POLL + 100; | ||
| 1581 | /* printk(KERN_DEBUG "len=%d dsp_count=0x%x.%04x dsp_poll_diff=0x%x.%04x\n", | ||
| 1582 | length, dsp_count >> 16, dsp_count & 0xffff, dsp_poll_diff >> 16, | ||
| 1583 | dsp_poll_diff & 0xffff); | ||
| 1584 | */ | ||
| 1585 | |||
| 1586 | /* | ||
| 1587 | * check if jitter needs to be checked | ||
| 1588 | * (this is about every second = 8192 samples) | ||
| 1589 | */ | ||
| 1590 | samplecount += length; | ||
| 1591 | if ((samplecount & 8191) < length) | ||
| 1592 | jittercheck = 1; | ||
| 1593 | |||
| 1594 | /* loop all members that do not require conference mixing */ | ||
| 1595 | list_for_each_entry(dsp, &dsp_ilist, list) { | ||
| 1596 | if (dsp->hdlc) | ||
| 1597 | continue; | ||
| 1598 | conf = dsp->conf; | ||
| 1599 | mustmix = 0; | ||
| 1600 | members = 0; | ||
| 1601 | if (conf) { | ||
| 1602 | members = count_list_member(&conf->mlist); | ||
| 1603 | #ifdef CMX_CONF_DEBUG | ||
| 1604 | if (conf->software && members > 1) | ||
| 1605 | #else | ||
| 1606 | if (conf->software && members > 2) | ||
| 1607 | #endif | ||
| 1608 | mustmix = 1; | ||
| 1609 | } | ||
| 1610 | |||
| 1611 | /* transmission required */ | ||
| 1612 | if (!mustmix) { | ||
| 1613 | dsp_cmx_send_member(dsp, length, mixbuffer, members); | ||
| 1614 | |||
| 1615 | /* | ||
| 1616 | * unused mixbuffer is given to prevent a | ||
| 1617 | * potential null-pointer-bug | ||
| 1618 | */ | ||
| 1619 | } | ||
| 1620 | } | ||
| 1621 | |||
| 1622 | /* loop all members that require conference mixing */ | ||
| 1623 | list_for_each_entry(conf, &conf_ilist, list) { | ||
| 1624 | /* count members and check hardware */ | ||
| 1625 | members = count_list_member(&conf->mlist); | ||
| 1626 | #ifdef CMX_CONF_DEBUG | ||
| 1627 | if (conf->software && members > 1) { | ||
| 1628 | #else | ||
| 1629 | if (conf->software && members > 2) { | ||
| 1630 | #endif | ||
| 1631 | /* check for hdlc conf */ | ||
| 1632 | member = list_entry(conf->mlist.next, | ||
| 1633 | struct dsp_conf_member, list); | ||
| 1634 | if (member->dsp->hdlc) | ||
| 1635 | continue; | ||
| 1636 | /* mix all data */ | ||
| 1637 | memset(mixbuffer, 0, length*sizeof(s32)); | ||
| 1638 | list_for_each_entry(member, &conf->mlist, list) { | ||
| 1639 | dsp = member->dsp; | ||
| 1640 | /* get range of data to mix */ | ||
| 1641 | c = mixbuffer; | ||
| 1642 | q = dsp->rx_buff; | ||
| 1643 | r = dsp->rx_R; | ||
| 1644 | rr = (r + length) & CMX_BUFF_MASK; | ||
| 1645 | /* add member's data */ | ||
| 1646 | while (r != rr) { | ||
| 1647 | *c++ += dsp_audio_law_to_s32[q[r]]; | ||
| 1648 | r = (r+1) & CMX_BUFF_MASK; | ||
| 1649 | } | ||
| 1650 | } | ||
| 1651 | |||
| 1652 | /* process each member */ | ||
| 1653 | list_for_each_entry(member, &conf->mlist, list) { | ||
| 1654 | /* transmission */ | ||
| 1655 | dsp_cmx_send_member(member->dsp, length, | ||
| 1656 | mixbuffer, members); | ||
| 1657 | } | ||
| 1658 | } | ||
| 1659 | } | ||
| 1660 | |||
| 1661 | /* delete rx-data, increment buffers, change pointers */ | ||
| 1662 | list_for_each_entry(dsp, &dsp_ilist, list) { | ||
| 1663 | if (dsp->hdlc) | ||
| 1664 | continue; | ||
| 1665 | p = dsp->rx_buff; | ||
| 1666 | q = dsp->tx_buff; | ||
| 1667 | r = dsp->rx_R; | ||
| 1668 | /* move receive pointer when receiving */ | ||
| 1669 | if (!dsp->rx_is_off) { | ||
| 1670 | rr = (r + length) & CMX_BUFF_MASK; | ||
| 1671 | /* delete rx-data */ | ||
| 1672 | while (r != rr) { | ||
| 1673 | p[r] = dsp_silence; | ||
| 1674 | r = (r+1) & CMX_BUFF_MASK; | ||
| 1675 | } | ||
| 1676 | /* increment rx-buffer pointer */ | ||
| 1677 | dsp->rx_R = r; /* write incremented read pointer */ | ||
| 1678 | } | ||
| 1679 | |||
| 1680 | /* check current rx_delay */ | ||
| 1681 | delay = (dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK; | ||
| 1682 | if (delay >= CMX_BUFF_HALF) | ||
| 1683 | delay = 0; /* will be the delay before next write */ | ||
| 1684 | /* check for lower delay */ | ||
| 1685 | if (delay < dsp->rx_delay[0]) | ||
| 1686 | dsp->rx_delay[0] = delay; | ||
| 1687 | /* check current tx_delay */ | ||
| 1688 | delay = (dsp->tx_W-dsp->tx_R) & CMX_BUFF_MASK; | ||
| 1689 | if (delay >= CMX_BUFF_HALF) | ||
| 1690 | delay = 0; /* will be the delay before next write */ | ||
| 1691 | /* check for lower delay */ | ||
| 1692 | if (delay < dsp->tx_delay[0]) | ||
| 1693 | dsp->tx_delay[0] = delay; | ||
| 1694 | if (jittercheck) { | ||
| 1695 | /* find the lowest of all rx_delays */ | ||
| 1696 | delay = dsp->rx_delay[0]; | ||
| 1697 | i = 1; | ||
| 1698 | while (i < MAX_SECONDS_JITTER_CHECK) { | ||
| 1699 | if (delay > dsp->rx_delay[i]) | ||
| 1700 | delay = dsp->rx_delay[i]; | ||
| 1701 | i++; | ||
| 1702 | } | ||
| 1703 | /* | ||
| 1704 | * remove rx_delay only if we have delay AND we | ||
| 1705 | * have not preset cmx_delay | ||
| 1706 | */ | ||
| 1707 | if (delay && !dsp->cmx_delay) { | ||
| 1708 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 1709 | printk(KERN_DEBUG | ||
| 1710 | "%s lowest rx_delay of %d bytes for" | ||
| 1711 | " dsp %s are now removed.\n", | ||
| 1712 | __func__, delay, | ||
| 1713 | dsp->name); | ||
| 1714 | r = dsp->rx_R; | ||
| 1715 | rr = (r + delay) & CMX_BUFF_MASK; | ||
| 1716 | /* delete rx-data */ | ||
| 1717 | while (r != rr) { | ||
| 1718 | p[r] = dsp_silence; | ||
| 1719 | r = (r+1) & CMX_BUFF_MASK; | ||
| 1720 | } | ||
| 1721 | /* increment rx-buffer pointer */ | ||
| 1722 | dsp->rx_R = r; | ||
| 1723 | /* write incremented read pointer */ | ||
| 1724 | } | ||
| 1725 | /* find the lowest of all tx_delays */ | ||
| 1726 | delay = dsp->tx_delay[0]; | ||
| 1727 | i = 1; | ||
| 1728 | while (i < MAX_SECONDS_JITTER_CHECK) { | ||
| 1729 | if (delay > dsp->tx_delay[i]) | ||
| 1730 | delay = dsp->tx_delay[i]; | ||
| 1731 | i++; | ||
| 1732 | } | ||
| 1733 | /* | ||
| 1734 | * remove delay only if we have delay AND we | ||
| 1735 | * have enabled tx_dejitter | ||
| 1736 | */ | ||
| 1737 | if (delay && dsp->tx_dejitter) { | ||
| 1738 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 1739 | printk(KERN_DEBUG | ||
| 1740 | "%s lowest tx_delay of %d bytes for" | ||
| 1741 | " dsp %s are now removed.\n", | ||
| 1742 | __func__, delay, | ||
| 1743 | dsp->name); | ||
| 1744 | r = dsp->tx_R; | ||
| 1745 | rr = (r + delay) & CMX_BUFF_MASK; | ||
| 1746 | /* delete tx-data */ | ||
| 1747 | while (r != rr) { | ||
| 1748 | q[r] = dsp_silence; | ||
| 1749 | r = (r+1) & CMX_BUFF_MASK; | ||
| 1750 | } | ||
| 1751 | /* increment rx-buffer pointer */ | ||
| 1752 | dsp->tx_R = r; | ||
| 1753 | /* write incremented read pointer */ | ||
| 1754 | } | ||
| 1755 | /* scroll up delays */ | ||
| 1756 | i = MAX_SECONDS_JITTER_CHECK - 1; | ||
| 1757 | while (i) { | ||
| 1758 | dsp->rx_delay[i] = dsp->rx_delay[i-1]; | ||
| 1759 | dsp->tx_delay[i] = dsp->tx_delay[i-1]; | ||
| 1760 | i--; | ||
| 1761 | } | ||
| 1762 | dsp->tx_delay[0] = CMX_BUFF_HALF; /* (infinite) delay */ | ||
| 1763 | dsp->rx_delay[0] = CMX_BUFF_HALF; /* (infinite) delay */ | ||
| 1764 | } | ||
| 1765 | } | ||
| 1766 | |||
| 1767 | /* if next event would be in the past ... */ | ||
| 1768 | if ((s32)(dsp_spl_jiffies+dsp_tics-jiffies) <= 0) | ||
| 1769 | dsp_spl_jiffies = jiffies + 1; | ||
| 1770 | else | ||
| 1771 | dsp_spl_jiffies += dsp_tics; | ||
| 1772 | |||
| 1773 | dsp_spl_tl.expires = dsp_spl_jiffies; | ||
| 1774 | add_timer(&dsp_spl_tl); | ||
| 1775 | |||
| 1776 | /* unlock */ | ||
| 1777 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
| 1778 | } | ||
| 1779 | |||
| 1780 | /* | ||
| 1781 | * audio data is transmitted from upper layer to the dsp | ||
| 1782 | */ | ||
| 1783 | void | ||
| 1784 | dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb) | ||
| 1785 | { | ||
| 1786 | u_int w, ww; | ||
| 1787 | u8 *d, *p; | ||
| 1788 | int space; /* todo: , l = skb->len; */ | ||
| 1789 | #ifdef CMX_TX_DEBUG | ||
| 1790 | char debugbuf[256] = ""; | ||
| 1791 | #endif | ||
| 1792 | |||
| 1793 | /* check if there is enough space, and then copy */ | ||
| 1794 | w = dsp->tx_W; | ||
| 1795 | ww = dsp->tx_R; | ||
| 1796 | p = dsp->tx_buff; | ||
| 1797 | d = skb->data; | ||
| 1798 | space = ww-w; | ||
| 1799 | if (space <= 0) | ||
| 1800 | space += CMX_BUFF_SIZE; | ||
| 1801 | /* write-pointer should not overrun nor reach read pointer */ | ||
| 1802 | if (space-1 < skb->len) | ||
| 1803 | /* write to the space we have left */ | ||
| 1804 | ww = (ww - 1) & CMX_BUFF_MASK; | ||
| 1805 | else | ||
| 1806 | /* write until all byte are copied */ | ||
| 1807 | ww = (w + skb->len) & CMX_BUFF_MASK; | ||
| 1808 | dsp->tx_W = ww; | ||
| 1809 | |||
| 1810 | /* show current buffer */ | ||
| 1811 | #ifdef CMX_DEBUG | ||
| 1812 | printk(KERN_DEBUG | ||
| 1813 | "cmx_transmit(dsp=%lx) %d bytes to 0x%x-0x%x. %s\n", | ||
| 1814 | (u_long)dsp, (ww-w)&CMX_BUFF_MASK, w, ww, dsp->name); | ||
| 1815 | #endif | ||
| 1816 | |||
| 1817 | /* copy transmit data to tx-buffer */ | ||
| 1818 | #ifdef CMX_TX_DEBUG | ||
| 1819 | sprintf(debugbuf, "TX getting (%04x-%04x)%p: ", w, ww, p); | ||
| 1820 | #endif | ||
| 1821 | while (w != ww) { | ||
| 1822 | #ifdef CMX_TX_DEBUG | ||
| 1823 | if (strlen(debugbuf) < 48) | ||
| 1824 | sprintf(debugbuf+strlen(debugbuf), " %02x", *d); | ||
| 1825 | #endif | ||
| 1826 | p[w] = *d++; | ||
| 1827 | w = (w+1) & CMX_BUFF_MASK; | ||
| 1828 | } | ||
| 1829 | #ifdef CMX_TX_DEBUG | ||
| 1830 | printk(KERN_DEBUG "%s\n", debugbuf); | ||
| 1831 | #endif | ||
| 1832 | |||
| 1833 | } | ||
| 1834 | |||
| 1835 | /* | ||
| 1836 | * hdlc data is received from card and sent to all members. | ||
| 1837 | */ | ||
| 1838 | void | ||
| 1839 | dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb) | ||
| 1840 | { | ||
| 1841 | struct sk_buff *nskb = NULL; | ||
| 1842 | struct dsp_conf_member *member; | ||
| 1843 | struct mISDNhead *hh; | ||
| 1844 | |||
| 1845 | /* not if not active */ | ||
| 1846 | if (!dsp->b_active) | ||
| 1847 | return; | ||
| 1848 | |||
| 1849 | /* check if we have sompen */ | ||
| 1850 | if (skb->len < 1) | ||
| 1851 | return; | ||
| 1852 | |||
| 1853 | /* no conf */ | ||
| 1854 | if (!dsp->conf) { | ||
| 1855 | /* in case of hardware (echo) */ | ||
| 1856 | if (dsp->pcm_slot_tx >= 0) | ||
| 1857 | return; | ||
| 1858 | if (dsp->echo) | ||
| 1859 | nskb = skb_clone(skb, GFP_ATOMIC); | ||
| 1860 | if (nskb) { | ||
| 1861 | hh = mISDN_HEAD_P(nskb); | ||
| 1862 | hh->prim = PH_DATA_REQ; | ||
| 1863 | hh->id = 0; | ||
| 1864 | skb_queue_tail(&dsp->sendq, nskb); | ||
| 1865 | schedule_work(&dsp->workq); | ||
| 1866 | } | ||
| 1867 | return; | ||
| 1868 | } | ||
| 1869 | /* in case of hardware conference */ | ||
| 1870 | if (dsp->conf->hardware) | ||
| 1871 | return; | ||
| 1872 | list_for_each_entry(member, &dsp->conf->mlist, list) { | ||
| 1873 | if (dsp->echo || member->dsp != dsp) { | ||
| 1874 | nskb = skb_clone(skb, GFP_ATOMIC); | ||
| 1875 | if (nskb) { | ||
| 1876 | hh = mISDN_HEAD_P(nskb); | ||
| 1877 | hh->prim = PH_DATA_REQ; | ||
| 1878 | hh->id = 0; | ||
| 1879 | skb_queue_tail(&member->dsp->sendq, nskb); | ||
| 1880 | schedule_work(&member->dsp->workq); | ||
| 1881 | } | ||
| 1882 | } | ||
| 1883 | } | ||
| 1884 | } | ||
| 1885 | |||
| 1886 | |||
diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c new file mode 100644 index 000000000000..2f10ed82c0db --- /dev/null +++ b/drivers/isdn/mISDN/dsp_core.c | |||
| @@ -0,0 +1,1191 @@ | |||
| 1 | /* | ||
| 2 | * Author Andreas Eversberg (jolly@eversberg.eu) | ||
| 3 | * Based on source code structure by | ||
| 4 | * Karsten Keil (keil@isdn4linux.de) | ||
| 5 | * | ||
| 6 | * This file is (c) under GNU PUBLIC LICENSE | ||
| 7 | * For changes and modifications please read | ||
| 8 | * ../../../Documentation/isdn/mISDN.cert | ||
| 9 | * | ||
| 10 | * Thanks to Karsten Keil (great drivers) | ||
| 11 | * Cologne Chip (great chips) | ||
| 12 | * | ||
| 13 | * This module does: | ||
| 14 | * Real-time tone generation | ||
| 15 | * DTMF detection | ||
| 16 | * Real-time cross-connection and conferrence | ||
| 17 | * Compensate jitter due to system load and hardware fault. | ||
| 18 | * All features are done in kernel space and will be realized | ||
| 19 | * using hardware, if available and supported by chip set. | ||
| 20 | * Blowfish encryption/decryption | ||
| 21 | */ | ||
| 22 | |||
| 23 | /* STRUCTURE: | ||
| 24 | * | ||
| 25 | * The dsp module provides layer 2 for b-channels (64kbit). It provides | ||
| 26 | * transparent audio forwarding with special digital signal processing: | ||
| 27 | * | ||
| 28 | * - (1) generation of tones | ||
| 29 | * - (2) detection of dtmf tones | ||
| 30 | * - (3) crossconnecting and conferences (clocking) | ||
| 31 | * - (4) echo generation for delay test | ||
| 32 | * - (5) volume control | ||
| 33 | * - (6) disable receive data | ||
| 34 | * - (7) pipeline | ||
| 35 | * - (8) encryption/decryption | ||
| 36 | * | ||
| 37 | * Look: | ||
| 38 | * TX RX | ||
| 39 | * ------upper layer------ | ||
| 40 | * | ^ | ||
| 41 | * | |(6) | ||
| 42 | * v | | ||
| 43 | * +-----+-------------+-----+ | ||
| 44 | * |(3)(4) | | ||
| 45 | * | CMX | | ||
| 46 | * | | | ||
| 47 | * | +-------------+ | ||
| 48 | * | | ^ | ||
| 49 | * | | | | ||
| 50 | * |+---------+| +----+----+ | ||
| 51 | * ||(1) || |(2) | | ||
| 52 | * || || | | | ||
| 53 | * || Tones || | DTMF | | ||
| 54 | * || || | | | ||
| 55 | * || || | | | ||
| 56 | * |+----+----+| +----+----+ | ||
| 57 | * +-----+-----+ ^ | ||
| 58 | * | | | ||
| 59 | * v | | ||
| 60 | * +----+----+ +----+----+ | ||
| 61 | * |(5) | |(5) | | ||
| 62 | * | | | | | ||
| 63 | * |TX Volume| |RX Volume| | ||
| 64 | * | | | | | ||
| 65 | * | | | | | ||
| 66 | * +----+----+ +----+----+ | ||
| 67 | * | ^ | ||
| 68 | * | | | ||
| 69 | * v | | ||
| 70 | * +----+-------------+----+ | ||
| 71 | * |(7) | | ||
| 72 | * | | | ||
| 73 | * | Pipeline Processing | | ||
| 74 | * | | | ||
| 75 | * | | | ||
| 76 | * +----+-------------+----+ | ||
| 77 | * | ^ | ||
| 78 | * | | | ||
| 79 | * v | | ||
| 80 | * +----+----+ +----+----+ | ||
| 81 | * |(8) | |(8) | | ||
| 82 | * | | | | | ||
| 83 | * | Encrypt | | Decrypt | | ||
| 84 | * | | | | | ||
| 85 | * | | | | | ||
| 86 | * +----+----+ +----+----+ | ||
| 87 | * | ^ | ||
| 88 | * | | | ||
| 89 | * v | | ||
| 90 | * ------card layer------ | ||
| 91 | * TX RX | ||
| 92 | * | ||
| 93 | * Above you can see the logical data flow. If software is used to do the | ||
| 94 | * process, it is actually the real data flow. If hardware is used, data | ||
| 95 | * may not flow, but hardware commands to the card, to provide the data flow | ||
| 96 | * as shown. | ||
| 97 | * | ||
| 98 | * NOTE: The channel must be activated in order to make dsp work, even if | ||
| 99 | * no data flow to the upper layer is intended. Activation can be done | ||
| 100 | * after and before controlling the setting using PH_CONTROL requests. | ||
| 101 | * | ||
| 102 | * DTMF: Will be detected by hardware if possible. It is done before CMX | ||
| 103 | * processing. | ||
| 104 | * | ||
| 105 | * Tones: Will be generated via software if endless looped audio fifos are | ||
| 106 | * not supported by hardware. Tones will override all data from CMX. | ||
| 107 | * It is not required to join a conference to use tones at any time. | ||
| 108 | * | ||
| 109 | * CMX: Is transparent when not used. When it is used, it will do | ||
| 110 | * crossconnections and conferences via software if not possible through | ||
| 111 | * hardware. If hardware capability is available, hardware is used. | ||
| 112 | * | ||
| 113 | * Echo: Is generated by CMX and is used to check performane of hard and | ||
| 114 | * software CMX. | ||
| 115 | * | ||
| 116 | * The CMX has special functions for conferences with one, two and more | ||
| 117 | * members. It will allow different types of data flow. Receive and transmit | ||
| 118 | * data to/form upper layer may be swithed on/off individually without loosing | ||
| 119 | * features of CMX, Tones and DTMF. | ||
| 120 | * | ||
| 121 | * Echo Cancellation: Sometimes we like to cancel echo from the interface. | ||
| 122 | * Note that a VoIP call may not have echo caused by the IP phone. The echo | ||
| 123 | * is generated by the telephone line connected to it. Because the delay | ||
| 124 | * is high, it becomes an echo. RESULT: Echo Cachelation is required if | ||
| 125 | * both echo AND delay is applied to an interface. | ||
| 126 | * Remember that software CMX always generates a more or less delay. | ||
| 127 | * | ||
| 128 | * If all used features can be realized in hardware, and if transmit and/or | ||
| 129 | * receive data ist disabled, the card may not send/receive any data at all. | ||
| 130 | * Not receiving is usefull if only announcements are played. Not sending is | ||
| 131 | * usefull if an answering machine records audio. Not sending and receiving is | ||
| 132 | * usefull during most states of the call. If supported by hardware, tones | ||
| 133 | * will be played without cpu load. Small PBXs and NT-Mode applications will | ||
| 134 | * not need expensive hardware when processing calls. | ||
| 135 | * | ||
| 136 | * | ||
| 137 | * LOCKING: | ||
| 138 | * | ||
| 139 | * When data is received from upper or lower layer (card), the complete dsp | ||
| 140 | * module is locked by a global lock. This lock MUST lock irq, because it | ||
| 141 | * must lock timer events by DSP poll timer. | ||
| 142 | * When data is ready to be transmitted down, the data is queued and sent | ||
| 143 | * outside lock and timer event. | ||
| 144 | * PH_CONTROL must not change any settings, join or split conference members | ||
| 145 | * during process of data. | ||
| 146 | * | ||
| 147 | * HDLC: | ||
| 148 | * | ||
| 149 | * It works quite the same as transparent, except that HDLC data is forwarded | ||
| 150 | * to all other conference members if no hardware bridging is possible. | ||
| 151 | * Send data will be writte to sendq. Sendq will be sent if confirm is received. | ||
| 152 | * Conference cannot join, if one member is not hdlc. | ||
| 153 | * | ||
| 154 | */ | ||
| 155 | |||
| 156 | #include <linux/delay.h> | ||
| 157 | #include <linux/mISDNif.h> | ||
| 158 | #include <linux/mISDNdsp.h> | ||
| 159 | #include <linux/module.h> | ||
| 160 | #include <linux/vmalloc.h> | ||
| 161 | #include "core.h" | ||
| 162 | #include "dsp.h" | ||
| 163 | |||
| 164 | const char *mISDN_dsp_revision = "2.0"; | ||
| 165 | |||
| 166 | static int debug; | ||
| 167 | static int options; | ||
| 168 | static int poll; | ||
| 169 | static int dtmfthreshold = 100; | ||
| 170 | |||
| 171 | MODULE_AUTHOR("Andreas Eversberg"); | ||
| 172 | module_param(debug, uint, S_IRUGO | S_IWUSR); | ||
| 173 | module_param(options, uint, S_IRUGO | S_IWUSR); | ||
| 174 | module_param(poll, uint, S_IRUGO | S_IWUSR); | ||
| 175 | module_param(dtmfthreshold, uint, S_IRUGO | S_IWUSR); | ||
| 176 | MODULE_LICENSE("GPL"); | ||
| 177 | |||
| 178 | /*int spinnest = 0;*/ | ||
| 179 | |||
| 180 | spinlock_t dsp_lock; /* global dsp lock */ | ||
| 181 | struct list_head dsp_ilist; | ||
| 182 | struct list_head conf_ilist; | ||
| 183 | int dsp_debug; | ||
| 184 | int dsp_options; | ||
| 185 | int dsp_poll, dsp_tics; | ||
| 186 | |||
| 187 | /* check if rx may be turned off or must be turned on */ | ||
| 188 | static void | ||
| 189 | dsp_rx_off_member(struct dsp *dsp) | ||
| 190 | { | ||
| 191 | struct mISDN_ctrl_req cq; | ||
| 192 | int rx_off = 1; | ||
| 193 | |||
| 194 | if (!dsp->features_rx_off) | ||
| 195 | return; | ||
| 196 | |||
| 197 | /* not disabled */ | ||
| 198 | if (!dsp->rx_disabled) | ||
| 199 | rx_off = 0; | ||
| 200 | /* software dtmf */ | ||
| 201 | else if (dsp->dtmf.software) | ||
| 202 | rx_off = 0; | ||
| 203 | /* echo in software */ | ||
| 204 | else if (dsp->echo && dsp->pcm_slot_tx < 0) | ||
| 205 | rx_off = 0; | ||
| 206 | /* bridge in software */ | ||
| 207 | else if (dsp->conf) { | ||
| 208 | if (dsp->conf->software) | ||
| 209 | rx_off = 0; | ||
| 210 | } | ||
| 211 | |||
| 212 | if (rx_off == dsp->rx_is_off) | ||
| 213 | return; | ||
| 214 | |||
| 215 | if (!dsp->ch.peer) { | ||
| 216 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 217 | printk(KERN_DEBUG "%s: no peer, no rx_off\n", | ||
| 218 | __func__); | ||
| 219 | return; | ||
| 220 | } | ||
| 221 | cq.op = MISDN_CTRL_RX_OFF; | ||
| 222 | cq.p1 = rx_off; | ||
| 223 | if (dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq)) { | ||
| 224 | printk(KERN_DEBUG "%s: 2nd CONTROL_CHANNEL failed\n", | ||
| 225 | __func__); | ||
| 226 | return; | ||
| 227 | } | ||
| 228 | dsp->rx_is_off = rx_off; | ||
| 229 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 230 | printk(KERN_DEBUG "%s: %s set rx_off = %d\n", | ||
| 231 | __func__, dsp->name, rx_off); | ||
| 232 | } | ||
| 233 | static void | ||
| 234 | dsp_rx_off(struct dsp *dsp) | ||
| 235 | { | ||
| 236 | struct dsp_conf_member *member; | ||
| 237 | |||
| 238 | if (dsp_options & DSP_OPT_NOHARDWARE) | ||
| 239 | return; | ||
| 240 | |||
| 241 | /* no conf */ | ||
| 242 | if (!dsp->conf) { | ||
| 243 | dsp_rx_off_member(dsp); | ||
| 244 | return; | ||
| 245 | } | ||
| 246 | /* check all members in conf */ | ||
| 247 | list_for_each_entry(member, &dsp->conf->mlist, list) { | ||
| 248 | dsp_rx_off_member(member->dsp); | ||
| 249 | } | ||
| 250 | } | ||
| 251 | |||
| 252 | static int | ||
| 253 | dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb) | ||
| 254 | { | ||
| 255 | struct sk_buff *nskb; | ||
| 256 | int ret = 0; | ||
| 257 | int cont; | ||
| 258 | u8 *data; | ||
| 259 | int len; | ||
| 260 | |||
| 261 | if (skb->len < sizeof(int)) | ||
| 262 | printk(KERN_ERR "%s: PH_CONTROL message too short\n", __func__); | ||
| 263 | cont = *((int *)skb->data); | ||
| 264 | len = skb->len - sizeof(int); | ||
| 265 | data = skb->data + sizeof(int); | ||
| 266 | |||
| 267 | switch (cont) { | ||
| 268 | case DTMF_TONE_START: /* turn on DTMF */ | ||
| 269 | if (dsp->hdlc) { | ||
| 270 | ret = -EINVAL; | ||
| 271 | break; | ||
| 272 | } | ||
| 273 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 274 | printk(KERN_DEBUG "%s: start dtmf\n", __func__); | ||
| 275 | if (len == sizeof(int)) { | ||
| 276 | printk(KERN_NOTICE "changing DTMF Threshold " | ||
| 277 | "to %d\n", *((int *)data)); | ||
| 278 | dsp->dtmf.treshold = (*(int *)data) * 10000; | ||
| 279 | } | ||
| 280 | /* init goertzel */ | ||
| 281 | dsp_dtmf_goertzel_init(dsp); | ||
| 282 | |||
| 283 | /* check dtmf hardware */ | ||
| 284 | dsp_dtmf_hardware(dsp); | ||
| 285 | break; | ||
| 286 | case DTMF_TONE_STOP: /* turn off DTMF */ | ||
| 287 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 288 | printk(KERN_DEBUG "%s: stop dtmf\n", __func__); | ||
| 289 | dsp->dtmf.hardware = 0; | ||
| 290 | dsp->dtmf.software = 0; | ||
| 291 | break; | ||
| 292 | case DSP_CONF_JOIN: /* join / update conference */ | ||
| 293 | if (len < sizeof(int)) { | ||
| 294 | ret = -EINVAL; | ||
| 295 | break; | ||
| 296 | } | ||
| 297 | if (*((u32 *)data) == 0) | ||
| 298 | goto conf_split; | ||
| 299 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 300 | printk(KERN_DEBUG "%s: join conference %d\n", | ||
| 301 | __func__, *((u32 *)data)); | ||
| 302 | ret = dsp_cmx_conf(dsp, *((u32 *)data)); | ||
| 303 | /* dsp_cmx_hardware will also be called here */ | ||
| 304 | dsp_rx_off(dsp); | ||
| 305 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 306 | dsp_cmx_debug(dsp); | ||
| 307 | break; | ||
| 308 | case DSP_CONF_SPLIT: /* remove from conference */ | ||
| 309 | conf_split: | ||
| 310 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 311 | printk(KERN_DEBUG "%s: release conference\n", __func__); | ||
| 312 | ret = dsp_cmx_conf(dsp, 0); | ||
| 313 | /* dsp_cmx_hardware will also be called here */ | ||
| 314 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 315 | dsp_cmx_debug(dsp); | ||
| 316 | dsp_rx_off(dsp); | ||
| 317 | break; | ||
| 318 | case DSP_TONE_PATT_ON: /* play tone */ | ||
| 319 | if (dsp->hdlc) { | ||
| 320 | ret = -EINVAL; | ||
| 321 | break; | ||
| 322 | } | ||
| 323 | if (len < sizeof(int)) { | ||
| 324 | ret = -EINVAL; | ||
| 325 | break; | ||
| 326 | } | ||
| 327 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 328 | printk(KERN_DEBUG "%s: turn tone 0x%x on\n", | ||
| 329 | __func__, *((int *)skb->data)); | ||
| 330 | ret = dsp_tone(dsp, *((int *)data)); | ||
| 331 | if (!ret) { | ||
| 332 | dsp_cmx_hardware(dsp->conf, dsp); | ||
| 333 | dsp_rx_off(dsp); | ||
| 334 | } | ||
| 335 | if (!dsp->tone.tone) | ||
| 336 | goto tone_off; | ||
| 337 | break; | ||
| 338 | case DSP_TONE_PATT_OFF: /* stop tone */ | ||
| 339 | if (dsp->hdlc) { | ||
| 340 | ret = -EINVAL; | ||
| 341 | break; | ||
| 342 | } | ||
| 343 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 344 | printk(KERN_DEBUG "%s: turn tone off\n", __func__); | ||
| 345 | dsp_tone(dsp, 0); | ||
| 346 | dsp_cmx_hardware(dsp->conf, dsp); | ||
| 347 | dsp_rx_off(dsp); | ||
| 348 | /* reset tx buffers (user space data) */ | ||
| 349 | tone_off: | ||
| 350 | dsp->rx_W = 0; | ||
| 351 | dsp->rx_R = 0; | ||
| 352 | break; | ||
| 353 | case DSP_VOL_CHANGE_TX: /* change volume */ | ||
| 354 | if (dsp->hdlc) { | ||
| 355 | ret = -EINVAL; | ||
| 356 | break; | ||
| 357 | } | ||
| 358 | if (len < sizeof(int)) { | ||
| 359 | ret = -EINVAL; | ||
| 360 | break; | ||
| 361 | } | ||
| 362 | dsp->tx_volume = *((int *)data); | ||
| 363 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 364 | printk(KERN_DEBUG "%s: change tx vol to %d\n", | ||
| 365 | __func__, dsp->tx_volume); | ||
| 366 | dsp_cmx_hardware(dsp->conf, dsp); | ||
| 367 | dsp_dtmf_hardware(dsp); | ||
| 368 | dsp_rx_off(dsp); | ||
| 369 | break; | ||
| 370 | case DSP_VOL_CHANGE_RX: /* change volume */ | ||
| 371 | if (dsp->hdlc) { | ||
| 372 | ret = -EINVAL; | ||
| 373 | break; | ||
| 374 | } | ||
| 375 | if (len < sizeof(int)) { | ||
| 376 | ret = -EINVAL; | ||
| 377 | break; | ||
| 378 | } | ||
| 379 | dsp->rx_volume = *((int *)data); | ||
| 380 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 381 | printk(KERN_DEBUG "%s: change rx vol to %d\n", | ||
| 382 | __func__, dsp->tx_volume); | ||
| 383 | dsp_cmx_hardware(dsp->conf, dsp); | ||
| 384 | dsp_dtmf_hardware(dsp); | ||
| 385 | dsp_rx_off(dsp); | ||
| 386 | break; | ||
| 387 | case DSP_ECHO_ON: /* enable echo */ | ||
| 388 | dsp->echo = 1; /* soft echo */ | ||
| 389 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 390 | printk(KERN_DEBUG "%s: enable cmx-echo\n", __func__); | ||
| 391 | dsp_cmx_hardware(dsp->conf, dsp); | ||
| 392 | dsp_rx_off(dsp); | ||
| 393 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 394 | dsp_cmx_debug(dsp); | ||
| 395 | break; | ||
| 396 | case DSP_ECHO_OFF: /* disable echo */ | ||
| 397 | dsp->echo = 0; | ||
| 398 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 399 | printk(KERN_DEBUG "%s: disable cmx-echo\n", __func__); | ||
| 400 | dsp_cmx_hardware(dsp->conf, dsp); | ||
| 401 | dsp_rx_off(dsp); | ||
| 402 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 403 | dsp_cmx_debug(dsp); | ||
| 404 | break; | ||
| 405 | case DSP_RECEIVE_ON: /* enable receive to user space */ | ||
| 406 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 407 | printk(KERN_DEBUG "%s: enable receive to user " | ||
| 408 | "space\n", __func__); | ||
| 409 | dsp->rx_disabled = 0; | ||
| 410 | dsp_rx_off(dsp); | ||
| 411 | break; | ||
| 412 | case DSP_RECEIVE_OFF: /* disable receive to user space */ | ||
| 413 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 414 | printk(KERN_DEBUG "%s: disable receive to " | ||
| 415 | "user space\n", __func__); | ||
| 416 | dsp->rx_disabled = 1; | ||
| 417 | dsp_rx_off(dsp); | ||
| 418 | break; | ||
| 419 | case DSP_MIX_ON: /* enable mixing of tx data */ | ||
| 420 | if (dsp->hdlc) { | ||
| 421 | ret = -EINVAL; | ||
| 422 | break; | ||
| 423 | } | ||
| 424 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 425 | printk(KERN_DEBUG "%s: enable mixing of " | ||
| 426 | "tx-data with conf mebers\n", __func__); | ||
| 427 | dsp->tx_mix = 1; | ||
| 428 | dsp_cmx_hardware(dsp->conf, dsp); | ||
| 429 | dsp_rx_off(dsp); | ||
| 430 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 431 | dsp_cmx_debug(dsp); | ||
| 432 | break; | ||
| 433 | case DSP_MIX_OFF: /* disable mixing of tx data */ | ||
| 434 | if (dsp->hdlc) { | ||
| 435 | ret = -EINVAL; | ||
| 436 | break; | ||
| 437 | } | ||
| 438 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 439 | printk(KERN_DEBUG "%s: disable mixing of " | ||
| 440 | "tx-data with conf mebers\n", __func__); | ||
| 441 | dsp->tx_mix = 0; | ||
| 442 | dsp_cmx_hardware(dsp->conf, dsp); | ||
| 443 | dsp_rx_off(dsp); | ||
| 444 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 445 | dsp_cmx_debug(dsp); | ||
| 446 | break; | ||
| 447 | case DSP_TXDATA_ON: /* enable txdata */ | ||
| 448 | dsp->tx_data = 1; | ||
| 449 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 450 | printk(KERN_DEBUG "%s: enable tx-data\n", __func__); | ||
| 451 | dsp_cmx_hardware(dsp->conf, dsp); | ||
| 452 | dsp_rx_off(dsp); | ||
| 453 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 454 | dsp_cmx_debug(dsp); | ||
| 455 | break; | ||
| 456 | case DSP_TXDATA_OFF: /* disable txdata */ | ||
| 457 | dsp->tx_data = 0; | ||
| 458 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 459 | printk(KERN_DEBUG "%s: disable tx-data\n", __func__); | ||
| 460 | dsp_cmx_hardware(dsp->conf, dsp); | ||
| 461 | dsp_rx_off(dsp); | ||
| 462 | if (dsp_debug & DEBUG_DSP_CMX) | ||
| 463 | dsp_cmx_debug(dsp); | ||
| 464 | break; | ||
| 465 | case DSP_DELAY: /* use delay algorithm instead of dynamic | ||
| 466 | jitter algorithm */ | ||
| 467 | if (dsp->hdlc) { | ||
| 468 | ret = -EINVAL; | ||
| 469 | break; | ||
| 470 | } | ||
| 471 | if (len < sizeof(int)) { | ||
| 472 | ret = -EINVAL; | ||
| 473 | break; | ||
| 474 | } | ||
| 475 | dsp->cmx_delay = (*((int *)data)) << 3; | ||
| 476 | /* miliseconds to samples */ | ||
| 477 | if (dsp->cmx_delay >= (CMX_BUFF_HALF>>1)) | ||
| 478 | /* clip to half of maximum usable buffer | ||
| 479 | (half of half buffer) */ | ||
| 480 | dsp->cmx_delay = (CMX_BUFF_HALF>>1) - 1; | ||
| 481 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 482 | printk(KERN_DEBUG "%s: use delay algorithm to " | ||
| 483 | "compensate jitter (%d samples)\n", | ||
| 484 | __func__, dsp->cmx_delay); | ||
| 485 | break; | ||
| 486 | case DSP_JITTER: /* use dynamic jitter algorithm instead of | ||
| 487 | delay algorithm */ | ||
| 488 | if (dsp->hdlc) { | ||
| 489 | ret = -EINVAL; | ||
| 490 | break; | ||
| 491 | } | ||
| 492 | dsp->cmx_delay = 0; | ||
| 493 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 494 | printk(KERN_DEBUG "%s: use jitter algorithm to " | ||
| 495 | "compensate jitter\n", __func__); | ||
| 496 | break; | ||
| 497 | case DSP_TX_DEJITTER: /* use dynamic jitter algorithm for tx-buffer */ | ||
| 498 | if (dsp->hdlc) { | ||
| 499 | ret = -EINVAL; | ||
| 500 | break; | ||
| 501 | } | ||
| 502 | dsp->tx_dejitter = 1; | ||
| 503 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 504 | printk(KERN_DEBUG "%s: use dejitter on TX " | ||
| 505 | "buffer\n", __func__); | ||
| 506 | break; | ||
| 507 | case DSP_TX_DEJ_OFF: /* use tx-buffer without dejittering*/ | ||
| 508 | if (dsp->hdlc) { | ||
| 509 | ret = -EINVAL; | ||
| 510 | break; | ||
| 511 | } | ||
| 512 | dsp->tx_dejitter = 0; | ||
| 513 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 514 | printk(KERN_DEBUG "%s: use TX buffer without " | ||
| 515 | "dejittering\n", __func__); | ||
| 516 | break; | ||
| 517 | case DSP_PIPELINE_CFG: | ||
| 518 | if (dsp->hdlc) { | ||
| 519 | ret = -EINVAL; | ||
| 520 | break; | ||
| 521 | } | ||
| 522 | if (len > 0 && ((char *)data)[len - 1]) { | ||
| 523 | printk(KERN_DEBUG "%s: pipeline config string " | ||
| 524 | "is not NULL terminated!\n", __func__); | ||
| 525 | ret = -EINVAL; | ||
| 526 | } else { | ||
| 527 | dsp->pipeline.inuse = 1; | ||
| 528 | dsp_cmx_hardware(dsp->conf, dsp); | ||
| 529 | ret = dsp_pipeline_build(&dsp->pipeline, | ||
| 530 | len > 0 ? (char *)data : NULL); | ||
| 531 | dsp_cmx_hardware(dsp->conf, dsp); | ||
| 532 | dsp_rx_off(dsp); | ||
| 533 | } | ||
| 534 | break; | ||
| 535 | case DSP_BF_ENABLE_KEY: /* turn blowfish on */ | ||
| 536 | if (dsp->hdlc) { | ||
| 537 | ret = -EINVAL; | ||
| 538 | break; | ||
| 539 | } | ||
| 540 | if (len < 4 || len > 56) { | ||
| 541 | ret = -EINVAL; | ||
| 542 | break; | ||
| 543 | } | ||
| 544 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 545 | printk(KERN_DEBUG "%s: turn blowfish on (key " | ||
| 546 | "not shown)\n", __func__); | ||
| 547 | ret = dsp_bf_init(dsp, (u8 *)data, len); | ||
| 548 | /* set new cont */ | ||
| 549 | if (!ret) | ||
| 550 | cont = DSP_BF_ACCEPT; | ||
| 551 | else | ||
| 552 | cont = DSP_BF_REJECT; | ||
| 553 | /* send indication if it worked to set it */ | ||
| 554 | nskb = _alloc_mISDN_skb(PH_CONTROL_IND, MISDN_ID_ANY, | ||
| 555 | sizeof(int), &cont, GFP_ATOMIC); | ||
| 556 | if (nskb) { | ||
| 557 | if (dsp->up) { | ||
| 558 | if (dsp->up->send(dsp->up, nskb)) | ||
| 559 | dev_kfree_skb(nskb); | ||
| 560 | } else | ||
| 561 | dev_kfree_skb(nskb); | ||
| 562 | } | ||
| 563 | if (!ret) { | ||
| 564 | dsp_cmx_hardware(dsp->conf, dsp); | ||
| 565 | dsp_dtmf_hardware(dsp); | ||
| 566 | dsp_rx_off(dsp); | ||
| 567 | } | ||
| 568 | break; | ||
| 569 | case DSP_BF_DISABLE: /* turn blowfish off */ | ||
| 570 | if (dsp->hdlc) { | ||
| 571 | ret = -EINVAL; | ||
| 572 | break; | ||
| 573 | } | ||
| 574 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 575 | printk(KERN_DEBUG "%s: turn blowfish off\n", __func__); | ||
| 576 | dsp_bf_cleanup(dsp); | ||
| 577 | dsp_cmx_hardware(dsp->conf, dsp); | ||
| 578 | dsp_dtmf_hardware(dsp); | ||
| 579 | dsp_rx_off(dsp); | ||
| 580 | break; | ||
| 581 | default: | ||
| 582 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 583 | printk(KERN_DEBUG "%s: ctrl req %x unhandled\n", | ||
| 584 | __func__, cont); | ||
| 585 | ret = -EINVAL; | ||
| 586 | } | ||
| 587 | return ret; | ||
| 588 | } | ||
| 589 | |||
| 590 | static void | ||
| 591 | get_features(struct mISDNchannel *ch) | ||
| 592 | { | ||
| 593 | struct dsp *dsp = container_of(ch, struct dsp, ch); | ||
| 594 | struct mISDN_ctrl_req cq; | ||
| 595 | |||
| 596 | if (dsp_options & DSP_OPT_NOHARDWARE) | ||
| 597 | return; | ||
| 598 | if (!ch->peer) { | ||
| 599 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 600 | printk(KERN_DEBUG "%s: no peer, no features\n", | ||
| 601 | __func__); | ||
| 602 | return; | ||
| 603 | } | ||
| 604 | memset(&cq, 0, sizeof(cq)); | ||
| 605 | cq.op = MISDN_CTRL_GETOP; | ||
| 606 | if (ch->peer->ctrl(ch->peer, CONTROL_CHANNEL, &cq) < 0) { | ||
| 607 | printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", | ||
| 608 | __func__); | ||
| 609 | return; | ||
| 610 | } | ||
| 611 | if (cq.op & MISDN_CTRL_RX_OFF) | ||
| 612 | dsp->features_rx_off = 1; | ||
| 613 | if ((cq.op & MISDN_CTRL_HW_FEATURES_OP)) { | ||
| 614 | cq.op = MISDN_CTRL_HW_FEATURES; | ||
| 615 | *((u_long *)&cq.p1) = (u_long)&dsp->features; | ||
| 616 | if (ch->peer->ctrl(ch->peer, CONTROL_CHANNEL, &cq)) { | ||
| 617 | printk(KERN_DEBUG "%s: 2nd CONTROL_CHANNEL failed\n", | ||
| 618 | __func__); | ||
| 619 | } | ||
| 620 | } else | ||
| 621 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 622 | printk(KERN_DEBUG "%s: features not supported for %s\n", | ||
| 623 | __func__, dsp->name); | ||
| 624 | } | ||
| 625 | |||
| 626 | static int | ||
| 627 | dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) | ||
| 628 | { | ||
| 629 | struct dsp *dsp = container_of(ch, struct dsp, ch); | ||
| 630 | struct mISDNhead *hh; | ||
| 631 | int ret = 0; | ||
| 632 | u8 *digits; | ||
| 633 | int cont; | ||
| 634 | struct sk_buff *nskb; | ||
| 635 | u_long flags; | ||
| 636 | |||
| 637 | hh = mISDN_HEAD_P(skb); | ||
| 638 | switch (hh->prim) { | ||
| 639 | /* FROM DOWN */ | ||
| 640 | case (PH_DATA_CNF): | ||
| 641 | dsp->data_pending = 0; | ||
| 642 | /* trigger next hdlc frame, if any */ | ||
| 643 | if (dsp->hdlc) { | ||
| 644 | spin_lock_irqsave(&dsp_lock, flags); | ||
| 645 | if (dsp->b_active) | ||
| 646 | schedule_work(&dsp->workq); | ||
| 647 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
| 648 | } | ||
| 649 | break; | ||
| 650 | case (PH_DATA_IND): | ||
| 651 | case (DL_DATA_IND): | ||
| 652 | if (skb->len < 1) { | ||
| 653 | ret = -EINVAL; | ||
| 654 | break; | ||
| 655 | } | ||
| 656 | if (dsp->rx_is_off) { | ||
| 657 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 658 | printk(KERN_DEBUG "%s: rx-data during rx_off" | ||
| 659 | " for %s\n", | ||
| 660 | __func__, dsp->name); | ||
| 661 | } | ||
| 662 | if (dsp->hdlc) { | ||
| 663 | /* hdlc */ | ||
| 664 | spin_lock_irqsave(&dsp_lock, flags); | ||
| 665 | dsp_cmx_hdlc(dsp, skb); | ||
| 666 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
| 667 | if (dsp->rx_disabled) { | ||
| 668 | /* if receive is not allowed */ | ||
| 669 | break; | ||
| 670 | } | ||
| 671 | hh->prim = DL_DATA_IND; | ||
| 672 | if (dsp->up) | ||
| 673 | return dsp->up->send(dsp->up, skb); | ||
| 674 | break; | ||
| 675 | } | ||
| 676 | |||
| 677 | /* decrypt if enabled */ | ||
| 678 | if (dsp->bf_enable) | ||
| 679 | dsp_bf_decrypt(dsp, skb->data, skb->len); | ||
| 680 | /* pipeline */ | ||
| 681 | if (dsp->pipeline.inuse) | ||
| 682 | dsp_pipeline_process_rx(&dsp->pipeline, skb->data, | ||
| 683 | skb->len); | ||
| 684 | /* change volume if requested */ | ||
| 685 | if (dsp->rx_volume) | ||
| 686 | dsp_change_volume(skb, dsp->rx_volume); | ||
| 687 | |||
| 688 | /* check if dtmf soft decoding is turned on */ | ||
| 689 | if (dsp->dtmf.software) { | ||
| 690 | digits = dsp_dtmf_goertzel_decode(dsp, skb->data, | ||
| 691 | skb->len, (dsp_options&DSP_OPT_ULAW)?1:0); | ||
| 692 | while (*digits) { | ||
| 693 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
| 694 | printk(KERN_DEBUG "%s: digit" | ||
| 695 | "(%c) to layer %s\n", | ||
| 696 | __func__, *digits, dsp->name); | ||
| 697 | cont = DTMF_TONE_VAL | *digits; | ||
| 698 | nskb = _alloc_mISDN_skb(PH_CONTROL_IND, | ||
| 699 | MISDN_ID_ANY, sizeof(int), &cont, | ||
| 700 | GFP_ATOMIC); | ||
| 701 | if (nskb) { | ||
| 702 | if (dsp->up) { | ||
| 703 | if (dsp->up->send( | ||
| 704 | dsp->up, nskb)) | ||
| 705 | dev_kfree_skb(nskb); | ||
| 706 | } else | ||
| 707 | dev_kfree_skb(nskb); | ||
| 708 | } | ||
| 709 | digits++; | ||
| 710 | } | ||
| 711 | } | ||
| 712 | /* we need to process receive data if software */ | ||
| 713 | spin_lock_irqsave(&dsp_lock, flags); | ||
| 714 | if (dsp->pcm_slot_tx < 0 && dsp->pcm_slot_rx < 0) { | ||
| 715 | /* process data from card at cmx */ | ||
| 716 | dsp_cmx_receive(dsp, skb); | ||
| 717 | } | ||
| 718 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
| 719 | |||
| 720 | if (dsp->rx_disabled) { | ||
| 721 | /* if receive is not allowed */ | ||
| 722 | break; | ||
| 723 | } | ||
| 724 | hh->prim = DL_DATA_IND; | ||
| 725 | if (dsp->up) | ||
| 726 | return dsp->up->send(dsp->up, skb); | ||
| 727 | break; | ||
| 728 | case (PH_CONTROL_IND): | ||
| 729 | if (dsp_debug & DEBUG_DSP_DTMFCOEFF) | ||
| 730 | printk(KERN_DEBUG "%s: PH_CONTROL INDICATION " | ||
| 731 | "received: %x (len %d) %s\n", __func__, | ||
| 732 | hh->id, skb->len, dsp->name); | ||
| 733 | switch (hh->id) { | ||
| 734 | case (DTMF_HFC_COEF): /* getting coefficients */ | ||
| 735 | if (!dsp->dtmf.hardware) { | ||
| 736 | if (dsp_debug & DEBUG_DSP_DTMFCOEFF) | ||
| 737 | printk(KERN_DEBUG "%s: ignoring DTMF " | ||
| 738 | "coefficients from HFC\n", | ||
| 739 | __func__); | ||
| 740 | break; | ||
| 741 | } | ||
| 742 | digits = dsp_dtmf_goertzel_decode(dsp, skb->data, | ||
| 743 | skb->len, 2); | ||
| 744 | while (*digits) { | ||
| 745 | int k; | ||
| 746 | struct sk_buff *nskb; | ||
| 747 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
| 748 | printk(KERN_DEBUG "%s: digit" | ||
| 749 | "(%c) to layer %s\n", | ||
| 750 | __func__, *digits, dsp->name); | ||
| 751 | k = *digits | DTMF_TONE_VAL; | ||
| 752 | nskb = _alloc_mISDN_skb(PH_CONTROL_IND, | ||
| 753 | MISDN_ID_ANY, sizeof(int), &k, | ||
| 754 | GFP_ATOMIC); | ||
| 755 | if (nskb) { | ||
| 756 | if (dsp->up) { | ||
| 757 | if (dsp->up->send( | ||
| 758 | dsp->up, nskb)) | ||
| 759 | dev_kfree_skb(nskb); | ||
| 760 | } else | ||
| 761 | dev_kfree_skb(nskb); | ||
| 762 | } | ||
| 763 | digits++; | ||
| 764 | } | ||
| 765 | break; | ||
| 766 | case (HFC_VOL_CHANGE_TX): /* change volume */ | ||
| 767 | if (skb->len != sizeof(int)) { | ||
| 768 | ret = -EINVAL; | ||
| 769 | break; | ||
| 770 | } | ||
| 771 | spin_lock_irqsave(&dsp_lock, flags); | ||
| 772 | dsp->tx_volume = *((int *)skb->data); | ||
| 773 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 774 | printk(KERN_DEBUG "%s: change tx volume to " | ||
| 775 | "%d\n", __func__, dsp->tx_volume); | ||
| 776 | dsp_cmx_hardware(dsp->conf, dsp); | ||
| 777 | dsp_dtmf_hardware(dsp); | ||
| 778 | dsp_rx_off(dsp); | ||
| 779 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
| 780 | break; | ||
| 781 | default: | ||
| 782 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 783 | printk(KERN_DEBUG "%s: ctrl ind %x unhandled " | ||
| 784 | "%s\n", __func__, hh->id, dsp->name); | ||
| 785 | ret = -EINVAL; | ||
| 786 | } | ||
| 787 | break; | ||
| 788 | case (PH_ACTIVATE_IND): | ||
| 789 | case (PH_ACTIVATE_CNF): | ||
| 790 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 791 | printk(KERN_DEBUG "%s: b_channel is now active %s\n", | ||
| 792 | __func__, dsp->name); | ||
| 793 | /* bchannel now active */ | ||
| 794 | spin_lock_irqsave(&dsp_lock, flags); | ||
| 795 | dsp->b_active = 1; | ||
| 796 | dsp->data_pending = 0; | ||
| 797 | dsp->rx_init = 1; | ||
| 798 | /* rx_W and rx_R will be adjusted on first frame */ | ||
| 799 | dsp->rx_W = 0; | ||
| 800 | dsp->rx_R = 0; | ||
| 801 | memset(dsp->rx_buff, 0, sizeof(dsp->rx_buff)); | ||
| 802 | dsp_cmx_hardware(dsp->conf, dsp); | ||
| 803 | dsp_dtmf_hardware(dsp); | ||
| 804 | dsp_rx_off(dsp); | ||
| 805 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
| 806 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 807 | printk(KERN_DEBUG "%s: done with activation, sending " | ||
| 808 | "confirm to user space. %s\n", __func__, | ||
| 809 | dsp->name); | ||
| 810 | /* send activation to upper layer */ | ||
| 811 | hh->prim = DL_ESTABLISH_CNF; | ||
| 812 | if (dsp->up) | ||
| 813 | return dsp->up->send(dsp->up, skb); | ||
| 814 | break; | ||
| 815 | case (PH_DEACTIVATE_IND): | ||
| 816 | case (PH_DEACTIVATE_CNF): | ||
| 817 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 818 | printk(KERN_DEBUG "%s: b_channel is now inactive %s\n", | ||
| 819 | __func__, dsp->name); | ||
| 820 | /* bchannel now inactive */ | ||
| 821 | spin_lock_irqsave(&dsp_lock, flags); | ||
| 822 | dsp->b_active = 0; | ||
| 823 | dsp->data_pending = 0; | ||
| 824 | dsp_cmx_hardware(dsp->conf, dsp); | ||
| 825 | dsp_rx_off(dsp); | ||
| 826 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
| 827 | hh->prim = DL_RELEASE_CNF; | ||
| 828 | if (dsp->up) | ||
| 829 | return dsp->up->send(dsp->up, skb); | ||
| 830 | break; | ||
| 831 | /* FROM UP */ | ||
| 832 | case (DL_DATA_REQ): | ||
| 833 | case (PH_DATA_REQ): | ||
| 834 | if (skb->len < 1) { | ||
| 835 | ret = -EINVAL; | ||
| 836 | break; | ||
| 837 | } | ||
| 838 | if (dsp->hdlc) { | ||
| 839 | /* hdlc */ | ||
| 840 | spin_lock_irqsave(&dsp_lock, flags); | ||
| 841 | if (dsp->b_active) { | ||
| 842 | skb_queue_tail(&dsp->sendq, skb); | ||
| 843 | schedule_work(&dsp->workq); | ||
| 844 | } | ||
| 845 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
| 846 | return 0; | ||
| 847 | } | ||
| 848 | /* send data to tx-buffer (if no tone is played) */ | ||
| 849 | if (!dsp->tone.tone) { | ||
| 850 | spin_lock_irqsave(&dsp_lock, flags); | ||
| 851 | dsp_cmx_transmit(dsp, skb); | ||
| 852 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
| 853 | } | ||
| 854 | break; | ||
| 855 | case (PH_CONTROL_REQ): | ||
| 856 | spin_lock_irqsave(&dsp_lock, flags); | ||
| 857 | ret = dsp_control_req(dsp, hh, skb); | ||
| 858 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
| 859 | break; | ||
| 860 | case (DL_ESTABLISH_REQ): | ||
| 861 | case (PH_ACTIVATE_REQ): | ||
| 862 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 863 | printk(KERN_DEBUG "%s: activating b_channel %s\n", | ||
| 864 | __func__, dsp->name); | ||
| 865 | if (dsp->dtmf.hardware || dsp->dtmf.software) | ||
| 866 | dsp_dtmf_goertzel_init(dsp); | ||
| 867 | get_features(ch); | ||
| 868 | /* send ph_activate */ | ||
| 869 | hh->prim = PH_ACTIVATE_REQ; | ||
| 870 | if (ch->peer) | ||
| 871 | return ch->recv(ch->peer, skb); | ||
| 872 | break; | ||
| 873 | case (DL_RELEASE_REQ): | ||
| 874 | case (PH_DEACTIVATE_REQ): | ||
| 875 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 876 | printk(KERN_DEBUG "%s: releasing b_channel %s\n", | ||
| 877 | __func__, dsp->name); | ||
| 878 | spin_lock_irqsave(&dsp_lock, flags); | ||
| 879 | dsp->tone.tone = 0; | ||
| 880 | dsp->tone.hardware = 0; | ||
| 881 | dsp->tone.software = 0; | ||
| 882 | if (timer_pending(&dsp->tone.tl)) | ||
| 883 | del_timer(&dsp->tone.tl); | ||
| 884 | if (dsp->conf) | ||
| 885 | dsp_cmx_conf(dsp, 0); /* dsp_cmx_hardware will also be | ||
| 886 | called here */ | ||
| 887 | skb_queue_purge(&dsp->sendq); | ||
| 888 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
| 889 | hh->prim = PH_DEACTIVATE_REQ; | ||
| 890 | if (ch->peer) | ||
| 891 | return ch->recv(ch->peer, skb); | ||
| 892 | break; | ||
| 893 | default: | ||
| 894 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 895 | printk(KERN_DEBUG "%s: msg %x unhandled %s\n", | ||
| 896 | __func__, hh->prim, dsp->name); | ||
| 897 | ret = -EINVAL; | ||
| 898 | } | ||
| 899 | if (!ret) | ||
| 900 | dev_kfree_skb(skb); | ||
| 901 | return ret; | ||
| 902 | } | ||
| 903 | |||
| 904 | static int | ||
| 905 | dsp_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
| 906 | { | ||
| 907 | struct dsp *dsp = container_of(ch, struct dsp, ch); | ||
| 908 | u_long flags; | ||
| 909 | int err = 0; | ||
| 910 | |||
| 911 | if (debug & DEBUG_DSP_CTRL) | ||
| 912 | printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd); | ||
| 913 | |||
| 914 | switch (cmd) { | ||
| 915 | case OPEN_CHANNEL: | ||
| 916 | break; | ||
| 917 | case CLOSE_CHANNEL: | ||
| 918 | if (dsp->ch.peer) | ||
| 919 | dsp->ch.peer->ctrl(dsp->ch.peer, CLOSE_CHANNEL, NULL); | ||
| 920 | |||
| 921 | /* wait until workqueue has finished, | ||
| 922 | * must lock here, or we may hit send-process currently | ||
| 923 | * queueing. */ | ||
| 924 | spin_lock_irqsave(&dsp_lock, flags); | ||
| 925 | dsp->b_active = 0; | ||
| 926 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
| 927 | /* MUST not be locked, because it waits until queue is done. */ | ||
| 928 | cancel_work_sync(&dsp->workq); | ||
| 929 | spin_lock_irqsave(&dsp_lock, flags); | ||
| 930 | if (timer_pending(&dsp->tone.tl)) | ||
| 931 | del_timer(&dsp->tone.tl); | ||
| 932 | skb_queue_purge(&dsp->sendq); | ||
| 933 | if (dsp_debug & DEBUG_DSP_CTRL) | ||
| 934 | printk(KERN_DEBUG "%s: releasing member %s\n", | ||
| 935 | __func__, dsp->name); | ||
| 936 | dsp->b_active = 0; | ||
| 937 | dsp_cmx_conf(dsp, 0); /* dsp_cmx_hardware will also be called | ||
| 938 | here */ | ||
| 939 | dsp_pipeline_destroy(&dsp->pipeline); | ||
| 940 | |||
| 941 | if (dsp_debug & DEBUG_DSP_CTRL) | ||
| 942 | printk(KERN_DEBUG "%s: remove & destroy object %s\n", | ||
| 943 | __func__, dsp->name); | ||
| 944 | list_del(&dsp->list); | ||
| 945 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
| 946 | |||
| 947 | if (dsp_debug & DEBUG_DSP_CTRL) | ||
| 948 | printk(KERN_DEBUG "%s: dsp instance released\n", | ||
| 949 | __func__); | ||
| 950 | vfree(dsp); | ||
| 951 | module_put(THIS_MODULE); | ||
| 952 | break; | ||
| 953 | } | ||
| 954 | return err; | ||
| 955 | } | ||
| 956 | |||
| 957 | static void | ||
| 958 | dsp_send_bh(struct work_struct *work) | ||
| 959 | { | ||
| 960 | struct dsp *dsp = container_of(work, struct dsp, workq); | ||
| 961 | struct sk_buff *skb; | ||
| 962 | struct mISDNhead *hh; | ||
| 963 | |||
| 964 | if (dsp->hdlc && dsp->data_pending) | ||
| 965 | return; /* wait until data has been acknowledged */ | ||
| 966 | |||
| 967 | /* send queued data */ | ||
| 968 | while ((skb = skb_dequeue(&dsp->sendq))) { | ||
| 969 | /* in locked date, we must have still data in queue */ | ||
| 970 | if (dsp->data_pending) { | ||
| 971 | if (dsp_debug & DEBUG_DSP_CORE) | ||
| 972 | printk(KERN_DEBUG "%s: fifo full %s, this is " | ||
| 973 | "no bug!\n", __func__, dsp->name); | ||
| 974 | /* flush transparent data, if not acked */ | ||
| 975 | dev_kfree_skb(skb); | ||
| 976 | continue; | ||
| 977 | } | ||
| 978 | hh = mISDN_HEAD_P(skb); | ||
| 979 | if (hh->prim == DL_DATA_REQ) { | ||
| 980 | /* send packet up */ | ||
| 981 | if (dsp->up) { | ||
| 982 | if (dsp->up->send(dsp->up, skb)) | ||
| 983 | dev_kfree_skb(skb); | ||
| 984 | } else | ||
| 985 | dev_kfree_skb(skb); | ||
| 986 | } else { | ||
| 987 | /* send packet down */ | ||
| 988 | if (dsp->ch.peer) { | ||
| 989 | dsp->data_pending = 1; | ||
| 990 | if (dsp->ch.recv(dsp->ch.peer, skb)) { | ||
| 991 | dev_kfree_skb(skb); | ||
| 992 | dsp->data_pending = 0; | ||
| 993 | } | ||
| 994 | } else | ||
| 995 | dev_kfree_skb(skb); | ||
| 996 | } | ||
| 997 | } | ||
| 998 | } | ||
| 999 | |||
| 1000 | static int | ||
| 1001 | dspcreate(struct channel_req *crq) | ||
| 1002 | { | ||
| 1003 | struct dsp *ndsp; | ||
| 1004 | u_long flags; | ||
| 1005 | |||
| 1006 | if (crq->protocol != ISDN_P_B_L2DSP | ||
| 1007 | && crq->protocol != ISDN_P_B_L2DSPHDLC) | ||
| 1008 | return -EPROTONOSUPPORT; | ||
| 1009 | ndsp = vmalloc(sizeof(struct dsp)); | ||
| 1010 | if (!ndsp) { | ||
| 1011 | printk(KERN_ERR "%s: vmalloc struct dsp failed\n", __func__); | ||
| 1012 | return -ENOMEM; | ||
| 1013 | } | ||
| 1014 | memset(ndsp, 0, sizeof(struct dsp)); | ||
| 1015 | if (dsp_debug & DEBUG_DSP_CTRL) | ||
| 1016 | printk(KERN_DEBUG "%s: creating new dsp instance\n", __func__); | ||
| 1017 | |||
| 1018 | /* default enabled */ | ||
| 1019 | INIT_WORK(&ndsp->workq, (void *)dsp_send_bh); | ||
| 1020 | skb_queue_head_init(&ndsp->sendq); | ||
| 1021 | ndsp->ch.send = dsp_function; | ||
| 1022 | ndsp->ch.ctrl = dsp_ctrl; | ||
| 1023 | ndsp->up = crq->ch; | ||
| 1024 | crq->ch = &ndsp->ch; | ||
| 1025 | if (crq->protocol == ISDN_P_B_L2DSP) { | ||
| 1026 | crq->protocol = ISDN_P_B_RAW; | ||
| 1027 | ndsp->hdlc = 0; | ||
| 1028 | } else { | ||
| 1029 | crq->protocol = ISDN_P_B_HDLC; | ||
| 1030 | ndsp->hdlc = 1; | ||
| 1031 | } | ||
| 1032 | if (!try_module_get(THIS_MODULE)) | ||
| 1033 | printk(KERN_WARNING "%s:cannot get module\n", | ||
| 1034 | __func__); | ||
| 1035 | |||
| 1036 | sprintf(ndsp->name, "DSP_C%x(0x%p)", | ||
| 1037 | ndsp->up->st->dev->id + 1, ndsp); | ||
| 1038 | /* set frame size to start */ | ||
| 1039 | ndsp->features.hfc_id = -1; /* current PCM id */ | ||
| 1040 | ndsp->features.pcm_id = -1; /* current PCM id */ | ||
| 1041 | ndsp->pcm_slot_rx = -1; /* current CPM slot */ | ||
| 1042 | ndsp->pcm_slot_tx = -1; | ||
| 1043 | ndsp->pcm_bank_rx = -1; | ||
| 1044 | ndsp->pcm_bank_tx = -1; | ||
| 1045 | ndsp->hfc_conf = -1; /* current conference number */ | ||
| 1046 | /* set tone timer */ | ||
| 1047 | ndsp->tone.tl.function = (void *)dsp_tone_timeout; | ||
| 1048 | ndsp->tone.tl.data = (long) ndsp; | ||
| 1049 | init_timer(&ndsp->tone.tl); | ||
| 1050 | |||
| 1051 | if (dtmfthreshold < 20 || dtmfthreshold > 500) | ||
| 1052 | dtmfthreshold = 200; | ||
| 1053 | ndsp->dtmf.treshold = dtmfthreshold*10000; | ||
| 1054 | |||
| 1055 | /* init pipeline append to list */ | ||
| 1056 | spin_lock_irqsave(&dsp_lock, flags); | ||
| 1057 | dsp_pipeline_init(&ndsp->pipeline); | ||
| 1058 | list_add_tail(&ndsp->list, &dsp_ilist); | ||
| 1059 | spin_unlock_irqrestore(&dsp_lock, flags); | ||
| 1060 | |||
| 1061 | return 0; | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | |||
| 1065 | static struct Bprotocol DSP = { | ||
| 1066 | .Bprotocols = (1 << (ISDN_P_B_L2DSP & ISDN_P_B_MASK)) | ||
| 1067 | | (1 << (ISDN_P_B_L2DSPHDLC & ISDN_P_B_MASK)), | ||
| 1068 | .name = "dsp", | ||
| 1069 | .create = dspcreate | ||
| 1070 | }; | ||
| 1071 | |||
| 1072 | static int dsp_init(void) | ||
| 1073 | { | ||
| 1074 | int err; | ||
| 1075 | int tics; | ||
| 1076 | |||
| 1077 | printk(KERN_INFO "DSP modul %s\n", mISDN_dsp_revision); | ||
| 1078 | |||
| 1079 | dsp_options = options; | ||
| 1080 | dsp_debug = debug; | ||
| 1081 | |||
| 1082 | /* set packet size */ | ||
| 1083 | dsp_poll = poll; | ||
| 1084 | if (dsp_poll) { | ||
| 1085 | if (dsp_poll > MAX_POLL) { | ||
| 1086 | printk(KERN_ERR "%s: Wrong poll value (%d), use %d " | ||
| 1087 | "maximum.\n", __func__, poll, MAX_POLL); | ||
| 1088 | err = -EINVAL; | ||
| 1089 | return err; | ||
| 1090 | } | ||
| 1091 | if (dsp_poll < 8) { | ||
| 1092 | printk(KERN_ERR "%s: Wrong poll value (%d), use 8 " | ||
| 1093 | "minimum.\n", __func__, dsp_poll); | ||
| 1094 | err = -EINVAL; | ||
| 1095 | return err; | ||
| 1096 | } | ||
| 1097 | dsp_tics = poll * HZ / 8000; | ||
| 1098 | if (dsp_tics * 8000 != poll * HZ) { | ||
| 1099 | printk(KERN_INFO "mISDN_dsp: Cannot clock every %d " | ||
| 1100 | "samples (0,125 ms). It is not a multiple of " | ||
| 1101 | "%d HZ.\n", poll, HZ); | ||
| 1102 | err = -EINVAL; | ||
| 1103 | return err; | ||
| 1104 | } | ||
| 1105 | } else { | ||
| 1106 | poll = 8; | ||
| 1107 | while (poll <= MAX_POLL) { | ||
| 1108 | tics = poll * HZ / 8000; | ||
| 1109 | if (tics * 8000 == poll * HZ) { | ||
| 1110 | dsp_tics = tics; | ||
| 1111 | dsp_poll = poll; | ||
| 1112 | if (poll >= 64) | ||
| 1113 | break; | ||
| 1114 | } | ||
| 1115 | poll++; | ||
| 1116 | } | ||
| 1117 | } | ||
| 1118 | if (dsp_poll == 0) { | ||
| 1119 | printk(KERN_INFO "mISDN_dsp: There is no multiple of kernel " | ||
| 1120 | "clock that equals exactly the duration of 8-256 " | ||
| 1121 | "samples. (Choose kernel clock speed like 100, 250, " | ||
| 1122 | "300, 1000)\n"); | ||
| 1123 | err = -EINVAL; | ||
| 1124 | return err; | ||
| 1125 | } | ||
| 1126 | printk(KERN_INFO "mISDN_dsp: DSP clocks every %d samples. This equals " | ||
| 1127 | "%d jiffies.\n", dsp_poll, dsp_tics); | ||
| 1128 | |||
| 1129 | spin_lock_init(&dsp_lock); | ||
| 1130 | INIT_LIST_HEAD(&dsp_ilist); | ||
| 1131 | INIT_LIST_HEAD(&conf_ilist); | ||
| 1132 | |||
| 1133 | /* init conversion tables */ | ||
| 1134 | dsp_audio_generate_law_tables(); | ||
| 1135 | dsp_silence = (dsp_options&DSP_OPT_ULAW)?0xff:0x2a; | ||
| 1136 | dsp_audio_law_to_s32 = (dsp_options&DSP_OPT_ULAW)?dsp_audio_ulaw_to_s32: | ||
| 1137 | dsp_audio_alaw_to_s32; | ||
| 1138 | dsp_audio_generate_s2law_table(); | ||
| 1139 | dsp_audio_generate_seven(); | ||
| 1140 | dsp_audio_generate_mix_table(); | ||
| 1141 | if (dsp_options & DSP_OPT_ULAW) | ||
| 1142 | dsp_audio_generate_ulaw_samples(); | ||
| 1143 | dsp_audio_generate_volume_changes(); | ||
| 1144 | |||
| 1145 | err = dsp_pipeline_module_init(); | ||
| 1146 | if (err) { | ||
| 1147 | printk(KERN_ERR "mISDN_dsp: Can't initialize pipeline, " | ||
| 1148 | "error(%d)\n", err); | ||
| 1149 | return err; | ||
| 1150 | } | ||
| 1151 | |||
| 1152 | err = mISDN_register_Bprotocol(&DSP); | ||
| 1153 | if (err) { | ||
| 1154 | printk(KERN_ERR "Can't register %s error(%d)\n", DSP.name, err); | ||
| 1155 | return err; | ||
| 1156 | } | ||
| 1157 | |||
| 1158 | /* set sample timer */ | ||
| 1159 | dsp_spl_tl.function = (void *)dsp_cmx_send; | ||
| 1160 | dsp_spl_tl.data = 0; | ||
| 1161 | init_timer(&dsp_spl_tl); | ||
| 1162 | dsp_spl_tl.expires = jiffies + dsp_tics; | ||
| 1163 | dsp_spl_jiffies = dsp_spl_tl.expires; | ||
| 1164 | add_timer(&dsp_spl_tl); | ||
| 1165 | |||
| 1166 | return 0; | ||
| 1167 | } | ||
| 1168 | |||
| 1169 | |||
| 1170 | static void dsp_cleanup(void) | ||
| 1171 | { | ||
| 1172 | mISDN_unregister_Bprotocol(&DSP); | ||
| 1173 | |||
| 1174 | if (timer_pending(&dsp_spl_tl)) | ||
| 1175 | del_timer(&dsp_spl_tl); | ||
| 1176 | |||
| 1177 | if (!list_empty(&dsp_ilist)) { | ||
| 1178 | printk(KERN_ERR "mISDN_dsp: Audio DSP object inst list not " | ||
| 1179 | "empty.\n"); | ||
| 1180 | } | ||
| 1181 | if (!list_empty(&conf_ilist)) { | ||
| 1182 | printk(KERN_ERR "mISDN_dsp: Conference list not empty. Not " | ||
| 1183 | "all memory freed.\n"); | ||
| 1184 | } | ||
| 1185 | |||
| 1186 | dsp_pipeline_module_exit(); | ||
| 1187 | } | ||
| 1188 | |||
| 1189 | module_init(dsp_init); | ||
| 1190 | module_exit(dsp_cleanup); | ||
| 1191 | |||
diff --git a/drivers/isdn/mISDN/dsp_dtmf.c b/drivers/isdn/mISDN/dsp_dtmf.c new file mode 100644 index 000000000000..efc371c1f0dc --- /dev/null +++ b/drivers/isdn/mISDN/dsp_dtmf.c | |||
| @@ -0,0 +1,303 @@ | |||
| 1 | /* | ||
| 2 | * DTMF decoder. | ||
| 3 | * | ||
| 4 | * Copyright by Andreas Eversberg (jolly@eversberg.eu) | ||
| 5 | * based on different decoders such as ISDN4Linux | ||
| 6 | * | ||
| 7 | * This software may be used and distributed according to the terms | ||
| 8 | * of the GNU General Public License, incorporated herein by reference. | ||
| 9 | * | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/mISDNif.h> | ||
| 13 | #include <linux/mISDNdsp.h> | ||
| 14 | #include "core.h" | ||
| 15 | #include "dsp.h" | ||
| 16 | |||
| 17 | #define NCOEFF 8 /* number of frequencies to be analyzed */ | ||
| 18 | |||
| 19 | /* For DTMF recognition: | ||
| 20 | * 2 * cos(2 * PI * k / N) precalculated for all k | ||
| 21 | */ | ||
| 22 | static u64 cos2pik[NCOEFF] = | ||
| 23 | { | ||
| 24 | /* k << 15 (source: hfc-4s/8s documentation (www.colognechip.de)) */ | ||
| 25 | 55960, 53912, 51402, 48438, 38146, 32650, 26170, 18630 | ||
| 26 | }; | ||
| 27 | |||
| 28 | /* digit matrix */ | ||
| 29 | static char dtmf_matrix[4][4] = | ||
| 30 | { | ||
| 31 | {'1', '2', '3', 'A'}, | ||
| 32 | {'4', '5', '6', 'B'}, | ||
| 33 | {'7', '8', '9', 'C'}, | ||
| 34 | {'*', '0', '#', 'D'} | ||
| 35 | }; | ||
| 36 | |||
| 37 | /* dtmf detection using goertzel algorithm | ||
| 38 | * init function | ||
| 39 | */ | ||
| 40 | void dsp_dtmf_goertzel_init(struct dsp *dsp) | ||
| 41 | { | ||
| 42 | dsp->dtmf.size = 0; | ||
| 43 | dsp->dtmf.lastwhat = '\0'; | ||
| 44 | dsp->dtmf.lastdigit = '\0'; | ||
| 45 | dsp->dtmf.count = 0; | ||
| 46 | } | ||
| 47 | |||
| 48 | /* check for hardware or software features | ||
| 49 | */ | ||
| 50 | void dsp_dtmf_hardware(struct dsp *dsp) | ||
| 51 | { | ||
| 52 | int hardware = 1; | ||
| 53 | |||
| 54 | if (!dsp->features.hfc_dtmf) | ||
| 55 | hardware = 0; | ||
| 56 | |||
| 57 | /* check for volume change */ | ||
| 58 | if (dsp->tx_volume) { | ||
| 59 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
| 60 | printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " | ||
| 61 | "because tx_volume is changed\n", | ||
| 62 | __func__, dsp->name); | ||
| 63 | hardware = 0; | ||
| 64 | } | ||
| 65 | if (dsp->rx_volume) { | ||
| 66 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
| 67 | printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " | ||
| 68 | "because rx_volume is changed\n", | ||
| 69 | __func__, dsp->name); | ||
| 70 | hardware = 0; | ||
| 71 | } | ||
| 72 | /* check if encryption is enabled */ | ||
| 73 | if (dsp->bf_enable) { | ||
| 74 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
| 75 | printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " | ||
| 76 | "because encryption is enabled\n", | ||
| 77 | __func__, dsp->name); | ||
| 78 | hardware = 0; | ||
| 79 | } | ||
| 80 | /* check if pipeline exists */ | ||
| 81 | if (dsp->pipeline.inuse) { | ||
| 82 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
| 83 | printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " | ||
| 84 | "because pipeline exists.\n", | ||
| 85 | __func__, dsp->name); | ||
| 86 | hardware = 0; | ||
| 87 | } | ||
| 88 | |||
| 89 | dsp->dtmf.hardware = hardware; | ||
| 90 | dsp->dtmf.software = !hardware; | ||
| 91 | } | ||
| 92 | |||
| 93 | |||
| 94 | /************************************************************* | ||
| 95 | * calculate the coefficients of the given sample and decode * | ||
| 96 | *************************************************************/ | ||
| 97 | |||
| 98 | /* the given sample is decoded. if the sample is not long enough for a | ||
| 99 | * complete frame, the decoding is finished and continued with the next | ||
| 100 | * call of this function. | ||
| 101 | * | ||
| 102 | * the algorithm is very good for detection with a minimum of errors. i | ||
| 103 | * tested it allot. it even works with very short tones (40ms). the only | ||
| 104 | * disadvantage is, that it doesn't work good with different volumes of both | ||
| 105 | * tones. this will happen, if accoustically coupled dialers are used. | ||
| 106 | * it sometimes detects tones during speach, which is normal for decoders. | ||
| 107 | * use sequences to given commands during calls. | ||
| 108 | * | ||
| 109 | * dtmf - points to a structure of the current dtmf state | ||
| 110 | * spl and len - the sample | ||
| 111 | * fmt - 0 = alaw, 1 = ulaw, 2 = coefficients from HFC DTMF hw-decoder | ||
| 112 | */ | ||
| 113 | |||
| 114 | u8 | ||
| 115 | *dsp_dtmf_goertzel_decode(struct dsp *dsp, u8 *data, int len, int fmt) | ||
| 116 | { | ||
| 117 | u8 what; | ||
| 118 | int size; | ||
| 119 | signed short *buf; | ||
| 120 | s32 sk, sk1, sk2; | ||
| 121 | int k, n, i; | ||
| 122 | s32 *hfccoeff; | ||
| 123 | s32 result[NCOEFF], tresh, treshl; | ||
| 124 | int lowgroup, highgroup; | ||
| 125 | s64 cos2pik_; | ||
| 126 | |||
| 127 | dsp->dtmf.digits[0] = '\0'; | ||
| 128 | |||
| 129 | /* Note: The function will loop until the buffer has not enough samples | ||
| 130 | * left to decode a full frame. | ||
| 131 | */ | ||
| 132 | again: | ||
| 133 | /* convert samples */ | ||
| 134 | size = dsp->dtmf.size; | ||
| 135 | buf = dsp->dtmf.buffer; | ||
| 136 | switch (fmt) { | ||
| 137 | case 0: /* alaw */ | ||
| 138 | case 1: /* ulaw */ | ||
| 139 | while (size < DSP_DTMF_NPOINTS && len) { | ||
| 140 | buf[size++] = dsp_audio_law_to_s32[*data++]; | ||
| 141 | len--; | ||
| 142 | } | ||
| 143 | break; | ||
| 144 | |||
| 145 | case 2: /* HFC coefficients */ | ||
| 146 | default: | ||
| 147 | if (len < 64) { | ||
| 148 | if (len > 0) | ||
| 149 | printk(KERN_ERR "%s: coefficients have invalid " | ||
| 150 | "size. (is=%d < must=%d)\n", | ||
| 151 | __func__, len, 64); | ||
| 152 | return dsp->dtmf.digits; | ||
| 153 | } | ||
| 154 | hfccoeff = (s32 *)data; | ||
| 155 | for (k = 0; k < NCOEFF; k++) { | ||
| 156 | sk2 = (*hfccoeff++)>>4; | ||
| 157 | sk = (*hfccoeff++)>>4; | ||
| 158 | if (sk > 32767 || sk < -32767 || sk2 > 32767 | ||
| 159 | || sk2 < -32767) | ||
| 160 | printk(KERN_WARNING | ||
| 161 | "DTMF-Detection overflow\n"); | ||
| 162 | /* compute |X(k)|**2 */ | ||
| 163 | result[k] = | ||
| 164 | (sk * sk) - | ||
| 165 | (((cos2pik[k] * sk) >> 15) * sk2) + | ||
| 166 | (sk2 * sk2); | ||
| 167 | } | ||
| 168 | data += 64; | ||
| 169 | len -= 64; | ||
| 170 | goto coefficients; | ||
| 171 | break; | ||
| 172 | } | ||
| 173 | dsp->dtmf.size = size; | ||
| 174 | |||
| 175 | if (size < DSP_DTMF_NPOINTS) | ||
| 176 | return dsp->dtmf.digits; | ||
| 177 | |||
| 178 | dsp->dtmf.size = 0; | ||
| 179 | |||
| 180 | /* now we have a full buffer of signed long samples - we do goertzel */ | ||
| 181 | for (k = 0; k < NCOEFF; k++) { | ||
| 182 | sk = 0; | ||
| 183 | sk1 = 0; | ||
| 184 | sk2 = 0; | ||
| 185 | buf = dsp->dtmf.buffer; | ||
| 186 | cos2pik_ = cos2pik[k]; | ||
| 187 | for (n = 0; n < DSP_DTMF_NPOINTS; n++) { | ||
| 188 | sk = ((cos2pik_*sk1)>>15) - sk2 + (*buf++); | ||
| 189 | sk2 = sk1; | ||
| 190 | sk1 = sk; | ||
| 191 | } | ||
| 192 | sk >>= 8; | ||
| 193 | sk2 >>= 8; | ||
| 194 | if (sk > 32767 || sk < -32767 || sk2 > 32767 || sk2 < -32767) | ||
| 195 | printk(KERN_WARNING "DTMF-Detection overflow\n"); | ||
| 196 | /* compute |X(k)|**2 */ | ||
| 197 | result[k] = | ||
| 198 | (sk * sk) - | ||
| 199 | (((cos2pik[k] * sk) >> 15) * sk2) + | ||
| 200 | (sk2 * sk2); | ||
| 201 | } | ||
| 202 | |||
| 203 | /* our (squared) coefficients have been calculated, we need to process | ||
| 204 | * them. | ||
| 205 | */ | ||
| 206 | coefficients: | ||
| 207 | tresh = 0; | ||
| 208 | for (i = 0; i < NCOEFF; i++) { | ||
| 209 | if (result[i] < 0) | ||
| 210 | result[i] = 0; | ||
| 211 | if (result[i] > dsp->dtmf.treshold) { | ||
| 212 | if (result[i] > tresh) | ||
| 213 | tresh = result[i]; | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | if (tresh == 0) { | ||
| 218 | what = 0; | ||
| 219 | goto storedigit; | ||
| 220 | } | ||
| 221 | |||
| 222 | if (dsp_debug & DEBUG_DSP_DTMFCOEFF) | ||
| 223 | printk(KERN_DEBUG "a %3d %3d %3d %3d %3d %3d %3d %3d" | ||
| 224 | " tr:%3d r %3d %3d %3d %3d %3d %3d %3d %3d\n", | ||
| 225 | result[0]/10000, result[1]/10000, result[2]/10000, | ||
| 226 | result[3]/10000, result[4]/10000, result[5]/10000, | ||
| 227 | result[6]/10000, result[7]/10000, tresh/10000, | ||
| 228 | result[0]/(tresh/100), result[1]/(tresh/100), | ||
| 229 | result[2]/(tresh/100), result[3]/(tresh/100), | ||
| 230 | result[4]/(tresh/100), result[5]/(tresh/100), | ||
| 231 | result[6]/(tresh/100), result[7]/(tresh/100)); | ||
| 232 | |||
| 233 | /* calc digit (lowgroup/highgroup) */ | ||
| 234 | lowgroup = -1; | ||
| 235 | highgroup = -1; | ||
| 236 | treshl = tresh >> 3; /* tones which are not on, must be below 9 dB */ | ||
| 237 | tresh = tresh >> 2; /* touchtones must match within 6 dB */ | ||
| 238 | for (i = 0; i < NCOEFF; i++) { | ||
| 239 | if (result[i] < treshl) | ||
| 240 | continue; /* ignore */ | ||
| 241 | if (result[i] < tresh) { | ||
| 242 | lowgroup = -1; | ||
| 243 | highgroup = -1; | ||
| 244 | break; /* noise inbetween */ | ||
| 245 | } | ||
| 246 | /* good level found. This is allowed only one time per group */ | ||
| 247 | if (i < NCOEFF/2) { | ||
| 248 | /* lowgroup */ | ||
| 249 | if (lowgroup >= 0) { | ||
| 250 | /* Bad. Another tone found. */ | ||
| 251 | lowgroup = -1; | ||
| 252 | break; | ||
| 253 | } else | ||
| 254 | lowgroup = i; | ||
| 255 | } else { | ||
| 256 | /* higroup */ | ||
| 257 | if (highgroup >= 0) { | ||
| 258 | /* Bad. Another tone found. */ | ||
| 259 | highgroup = -1; | ||
| 260 | break; | ||
| 261 | } else | ||
| 262 | highgroup = i-(NCOEFF/2); | ||
| 263 | } | ||
| 264 | } | ||
| 265 | |||
| 266 | /* get digit or null */ | ||
| 267 | what = 0; | ||
| 268 | if (lowgroup >= 0 && highgroup >= 0) | ||
| 269 | what = dtmf_matrix[lowgroup][highgroup]; | ||
| 270 | |||
| 271 | storedigit: | ||
| 272 | if (what && (dsp_debug & DEBUG_DSP_DTMF)) | ||
| 273 | printk(KERN_DEBUG "DTMF what: %c\n", what); | ||
| 274 | |||
| 275 | if (dsp->dtmf.lastwhat != what) | ||
| 276 | dsp->dtmf.count = 0; | ||
| 277 | |||
| 278 | /* the tone (or no tone) must remain 3 times without change */ | ||
| 279 | if (dsp->dtmf.count == 2) { | ||
| 280 | if (dsp->dtmf.lastdigit != what) { | ||
| 281 | dsp->dtmf.lastdigit = what; | ||
| 282 | if (what) { | ||
| 283 | if (dsp_debug & DEBUG_DSP_DTMF) | ||
| 284 | printk(KERN_DEBUG "DTMF digit: %c\n", | ||
| 285 | what); | ||
| 286 | if ((strlen(dsp->dtmf.digits)+1) | ||
| 287 | < sizeof(dsp->dtmf.digits)) { | ||
| 288 | dsp->dtmf.digits[strlen( | ||
| 289 | dsp->dtmf.digits)+1] = '\0'; | ||
| 290 | dsp->dtmf.digits[strlen( | ||
| 291 | dsp->dtmf.digits)] = what; | ||
| 292 | } | ||
| 293 | } | ||
| 294 | } | ||
| 295 | } else | ||
| 296 | dsp->dtmf.count++; | ||
| 297 | |||
| 298 | dsp->dtmf.lastwhat = what; | ||
| 299 | |||
| 300 | goto again; | ||
| 301 | } | ||
| 302 | |||
| 303 | |||
diff --git a/drivers/isdn/mISDN/dsp_ecdis.h b/drivers/isdn/mISDN/dsp_ecdis.h new file mode 100644 index 000000000000..8a20af43308b --- /dev/null +++ b/drivers/isdn/mISDN/dsp_ecdis.h | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | /* | ||
| 2 | * SpanDSP - a series of DSP components for telephony | ||
| 3 | * | ||
| 4 | * ec_disable_detector.h - A detector which should eventually meet the | ||
| 5 | * G.164/G.165 requirements for detecting the | ||
| 6 | * 2100Hz echo cancellor disable tone. | ||
| 7 | * | ||
| 8 | * Written by Steve Underwood <steveu@coppice.org> | ||
| 9 | * | ||
| 10 | * Copyright (C) 2001 Steve Underwood | ||
| 11 | * | ||
| 12 | * All rights reserved. | ||
| 13 | * | ||
| 14 | * This program is free software; you can redistribute it and/or modify | ||
| 15 | * it under the terms of the GNU General Public License as published by | ||
| 16 | * the Free Software Foundation; either version 2 of the License, or | ||
| 17 | * (at your option) any later version. | ||
| 18 | * | ||
| 19 | * This program is distributed in the hope that it will be useful, | ||
| 20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 22 | * GNU General Public License for more details. | ||
| 23 | * | ||
| 24 | * You should have received a copy of the GNU General Public License | ||
| 25 | * along with this program; if not, write to the Free Software | ||
| 26 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 27 | * | ||
| 28 | */ | ||
| 29 | |||
| 30 | #include "dsp_biquad.h" | ||
| 31 | |||
| 32 | struct ec_disable_detector_state { | ||
| 33 | struct biquad2_state notch; | ||
| 34 | int notch_level; | ||
| 35 | int channel_level; | ||
| 36 | int tone_present; | ||
| 37 | int tone_cycle_duration; | ||
| 38 | int good_cycles; | ||
| 39 | int hit; | ||
| 40 | }; | ||
| 41 | |||
| 42 | |||
| 43 | #define FALSE 0 | ||
| 44 | #define TRUE (!FALSE) | ||
| 45 | |||
| 46 | static inline void | ||
| 47 | echo_can_disable_detector_init(struct ec_disable_detector_state *det) | ||
| 48 | { | ||
| 49 | /* Elliptic notch */ | ||
| 50 | /* This is actually centred at 2095Hz, but gets the balance we want, due | ||
| 51 | to the asymmetric walls of the notch */ | ||
| 52 | biquad2_init(&det->notch, | ||
| 53 | (int32_t) (-0.7600000*32768.0), | ||
| 54 | (int32_t) (-0.1183852*32768.0), | ||
| 55 | (int32_t) (-0.5104039*32768.0), | ||
| 56 | (int32_t) (0.1567596*32768.0), | ||
| 57 | (int32_t) (1.0000000*32768.0)); | ||
| 58 | |||
| 59 | det->channel_level = 0; | ||
| 60 | det->notch_level = 0; | ||
| 61 | det->tone_present = FALSE; | ||
| 62 | det->tone_cycle_duration = 0; | ||
| 63 | det->good_cycles = 0; | ||
| 64 | det->hit = 0; | ||
| 65 | } | ||
| 66 | /*- End of function --------------------------------------------------------*/ | ||
| 67 | |||
| 68 | static inline int | ||
| 69 | echo_can_disable_detector_update(struct ec_disable_detector_state *det, | ||
| 70 | int16_t amp) | ||
| 71 | { | ||
| 72 | int16_t notched; | ||
| 73 | |||
| 74 | notched = biquad2(&det->notch, amp); | ||
| 75 | /* Estimate the overall energy in the channel, and the energy in | ||
| 76 | the notch (i.e. overall channel energy - tone energy => noise). | ||
| 77 | Use abs instead of multiply for speed (is it really faster?). | ||
| 78 | Damp the overall energy a little more for a stable result. | ||
| 79 | Damp the notch energy a little less, so we don't damp out the | ||
| 80 | blip every time the phase reverses */ | ||
| 81 | det->channel_level += ((abs(amp) - det->channel_level) >> 5); | ||
| 82 | det->notch_level += ((abs(notched) - det->notch_level) >> 4); | ||
| 83 | if (det->channel_level > 280) { | ||
| 84 | /* There is adequate energy in the channel. | ||
| 85 | Is it mostly at 2100Hz? */ | ||
| 86 | if (det->notch_level*6 < det->channel_level) { | ||
| 87 | /* The notch says yes, so we have the tone. */ | ||
| 88 | if (!det->tone_present) { | ||
| 89 | /* Do we get a kick every 450+-25ms? */ | ||
| 90 | if (det->tone_cycle_duration >= 425*8 | ||
| 91 | && det->tone_cycle_duration <= 475*8) { | ||
| 92 | det->good_cycles++; | ||
| 93 | if (det->good_cycles > 2) | ||
| 94 | det->hit = TRUE; | ||
| 95 | } | ||
| 96 | det->tone_cycle_duration = 0; | ||
| 97 | } | ||
| 98 | det->tone_present = TRUE; | ||
| 99 | } else | ||
| 100 | det->tone_present = FALSE; | ||
| 101 | det->tone_cycle_duration++; | ||
| 102 | } else { | ||
| 103 | det->tone_present = FALSE; | ||
| 104 | det->tone_cycle_duration = 0; | ||
| 105 | det->good_cycles = 0; | ||
| 106 | } | ||
| 107 | return det->hit; | ||
| 108 | } | ||
| 109 | /*- End of function --------------------------------------------------------*/ | ||
| 110 | /*- End of file ------------------------------------------------------------*/ | ||
diff --git a/drivers/isdn/mISDN/dsp_hwec.c b/drivers/isdn/mISDN/dsp_hwec.c new file mode 100644 index 000000000000..eb892d9dd5c6 --- /dev/null +++ b/drivers/isdn/mISDN/dsp_hwec.c | |||
| @@ -0,0 +1,138 @@ | |||
| 1 | /* | ||
| 2 | * dsp_hwec.c: | ||
| 3 | * builtin mISDN dsp pipeline element for enabling the hw echocanceller | ||
| 4 | * | ||
| 5 | * Copyright (C) 2007, Nadi Sarrar | ||
| 6 | * | ||
| 7 | * Nadi Sarrar <nadi@beronet.com> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify it | ||
| 10 | * under the terms of the GNU General Public License as published by the Free | ||
| 11 | * Software Foundation; either version 2 of the License, or (at your option) | ||
| 12 | * any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
| 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 17 | * more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License along with | ||
| 20 | * this program; if not, write to the Free Software Foundation, Inc., 59 | ||
| 21 | * Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 22 | * | ||
| 23 | * The full GNU General Public License is included in this distribution in the | ||
| 24 | * file called LICENSE. | ||
| 25 | * | ||
| 26 | */ | ||
| 27 | |||
| 28 | #include <linux/kernel.h> | ||
| 29 | #include <linux/string.h> | ||
| 30 | #include <linux/mISDNdsp.h> | ||
| 31 | #include <linux/mISDNif.h> | ||
| 32 | #include "core.h" | ||
| 33 | #include "dsp.h" | ||
| 34 | #include "dsp_hwec.h" | ||
| 35 | |||
| 36 | static struct mISDN_dsp_element_arg args[] = { | ||
| 37 | { "deftaps", "128", "Set the number of taps of cancellation." }, | ||
| 38 | }; | ||
| 39 | |||
| 40 | static struct mISDN_dsp_element dsp_hwec_p = { | ||
| 41 | .name = "hwec", | ||
| 42 | .new = NULL, | ||
| 43 | .free = NULL, | ||
| 44 | .process_tx = NULL, | ||
| 45 | .process_rx = NULL, | ||
| 46 | .num_args = sizeof(args) / sizeof(struct mISDN_dsp_element_arg), | ||
| 47 | .args = args, | ||
| 48 | }; | ||
| 49 | struct mISDN_dsp_element *dsp_hwec = &dsp_hwec_p; | ||
| 50 | |||
| 51 | void dsp_hwec_enable(struct dsp *dsp, const char *arg) | ||
| 52 | { | ||
| 53 | int deftaps = 128, | ||
| 54 | len; | ||
| 55 | struct mISDN_ctrl_req cq; | ||
| 56 | |||
| 57 | if (!dsp) { | ||
| 58 | printk(KERN_ERR "%s: failed to enable hwec: dsp is NULL\n", | ||
| 59 | __func__); | ||
| 60 | return; | ||
| 61 | } | ||
| 62 | |||
| 63 | if (!arg) | ||
| 64 | goto _do; | ||
| 65 | |||
| 66 | len = strlen(arg); | ||
| 67 | if (!len) | ||
| 68 | goto _do; | ||
| 69 | |||
| 70 | { | ||
| 71 | char _dup[len + 1]; | ||
| 72 | char *dup, *tok, *name, *val; | ||
| 73 | int tmp; | ||
| 74 | |||
| 75 | strcpy(_dup, arg); | ||
| 76 | dup = _dup; | ||
| 77 | |||
| 78 | while ((tok = strsep(&dup, ","))) { | ||
| 79 | if (!strlen(tok)) | ||
| 80 | continue; | ||
| 81 | name = strsep(&tok, "="); | ||
| 82 | val = tok; | ||
| 83 | |||
| 84 | if (!val) | ||
| 85 | continue; | ||
| 86 | |||
| 87 | if (!strcmp(name, "deftaps")) { | ||
| 88 | if (sscanf(val, "%d", &tmp) == 1) | ||
| 89 | deftaps = tmp; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | _do: | ||
| 95 | printk(KERN_DEBUG "%s: enabling hwec with deftaps=%d\n", | ||
| 96 | __func__, deftaps); | ||
| 97 | memset(&cq, 0, sizeof(cq)); | ||
| 98 | cq.op = MISDN_CTRL_HFC_ECHOCAN_ON; | ||
| 99 | cq.p1 = deftaps; | ||
| 100 | if (!dsp->ch.peer->ctrl(&dsp->ch, CONTROL_CHANNEL, &cq)) { | ||
| 101 | printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", | ||
| 102 | __func__); | ||
| 103 | return; | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | void dsp_hwec_disable(struct dsp *dsp) | ||
| 108 | { | ||
| 109 | struct mISDN_ctrl_req cq; | ||
| 110 | |||
| 111 | if (!dsp) { | ||
| 112 | printk(KERN_ERR "%s: failed to disable hwec: dsp is NULL\n", | ||
| 113 | __func__); | ||
| 114 | return; | ||
| 115 | } | ||
| 116 | |||
| 117 | printk(KERN_DEBUG "%s: disabling hwec\n", __func__); | ||
| 118 | memset(&cq, 0, sizeof(cq)); | ||
| 119 | cq.op = MISDN_CTRL_HFC_ECHOCAN_OFF; | ||
| 120 | if (!dsp->ch.peer->ctrl(&dsp->ch, CONTROL_CHANNEL, &cq)) { | ||
| 121 | printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", | ||
| 122 | __func__); | ||
| 123 | return; | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | int dsp_hwec_init(void) | ||
| 128 | { | ||
| 129 | mISDN_dsp_element_register(dsp_hwec); | ||
| 130 | |||
| 131 | return 0; | ||
| 132 | } | ||
| 133 | |||
| 134 | void dsp_hwec_exit(void) | ||
| 135 | { | ||
| 136 | mISDN_dsp_element_unregister(dsp_hwec); | ||
| 137 | } | ||
| 138 | |||
diff --git a/drivers/isdn/mISDN/dsp_hwec.h b/drivers/isdn/mISDN/dsp_hwec.h new file mode 100644 index 000000000000..eebe80c3f713 --- /dev/null +++ b/drivers/isdn/mISDN/dsp_hwec.h | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | /* | ||
| 2 | * dsp_hwec.h | ||
| 3 | */ | ||
| 4 | |||
| 5 | extern struct mISDN_dsp_element *dsp_hwec; | ||
| 6 | extern void dsp_hwec_enable(struct dsp *dsp, const char *arg); | ||
| 7 | extern void dsp_hwec_disable(struct dsp *dsp); | ||
| 8 | extern int dsp_hwec_init(void); | ||
| 9 | extern void dsp_hwec_exit(void); | ||
| 10 | |||
diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c new file mode 100644 index 000000000000..850260ab57d0 --- /dev/null +++ b/drivers/isdn/mISDN/dsp_pipeline.c | |||
| @@ -0,0 +1,348 @@ | |||
| 1 | /* | ||
| 2 | * dsp_pipeline.c: pipelined audio processing | ||
| 3 | * | ||
| 4 | * Copyright (C) 2007, Nadi Sarrar | ||
| 5 | * | ||
| 6 | * Nadi Sarrar <nadi@beronet.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify it | ||
| 9 | * under the terms of the GNU General Public License as published by the Free | ||
| 10 | * Software Foundation; either version 2 of the License, or (at your option) | ||
| 11 | * any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
| 14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 16 | * more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License along with | ||
| 19 | * this program; if not, write to the Free Software Foundation, Inc., 59 | ||
| 20 | * Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 21 | * | ||
| 22 | * The full GNU General Public License is included in this distribution in the | ||
| 23 | * file called LICENSE. | ||
| 24 | * | ||
| 25 | */ | ||
| 26 | |||
| 27 | #include <linux/kernel.h> | ||
| 28 | #include <linux/list.h> | ||
| 29 | #include <linux/string.h> | ||
| 30 | #include <linux/mISDNif.h> | ||
| 31 | #include <linux/mISDNdsp.h> | ||
| 32 | #include "dsp.h" | ||
| 33 | #include "dsp_hwec.h" | ||
| 34 | |||
| 35 | /* uncomment for debugging */ | ||
| 36 | /*#define PIPELINE_DEBUG*/ | ||
| 37 | |||
| 38 | struct dsp_pipeline_entry { | ||
| 39 | struct mISDN_dsp_element *elem; | ||
| 40 | void *p; | ||
| 41 | struct list_head list; | ||
| 42 | }; | ||
| 43 | struct dsp_element_entry { | ||
| 44 | struct mISDN_dsp_element *elem; | ||
| 45 | struct device dev; | ||
| 46 | struct list_head list; | ||
| 47 | }; | ||
| 48 | |||
| 49 | static LIST_HEAD(dsp_elements); | ||
| 50 | |||
| 51 | /* sysfs */ | ||
| 52 | static struct class *elements_class; | ||
| 53 | |||
| 54 | static ssize_t | ||
| 55 | attr_show_args(struct device *dev, struct device_attribute *attr, char *buf) | ||
| 56 | { | ||
| 57 | struct mISDN_dsp_element *elem = dev_get_drvdata(dev); | ||
| 58 | ssize_t len = 0; | ||
| 59 | int i = 0; | ||
| 60 | |||
| 61 | *buf = 0; | ||
| 62 | for (; i < elem->num_args; ++i) | ||
| 63 | len = sprintf(buf, "%sName: %s\n%s%s%sDescription: %s\n" | ||
| 64 | "\n", buf, | ||
| 65 | elem->args[i].name, | ||
| 66 | elem->args[i].def ? "Default: " : "", | ||
| 67 | elem->args[i].def ? elem->args[i].def : "", | ||
| 68 | elem->args[i].def ? "\n" : "", | ||
| 69 | elem->args[i].desc); | ||
| 70 | |||
| 71 | return len; | ||
| 72 | } | ||
| 73 | |||
| 74 | static struct device_attribute element_attributes[] = { | ||
| 75 | __ATTR(args, 0444, attr_show_args, NULL), | ||
| 76 | }; | ||
| 77 | |||
| 78 | int mISDN_dsp_element_register(struct mISDN_dsp_element *elem) | ||
| 79 | { | ||
| 80 | struct dsp_element_entry *entry; | ||
| 81 | int ret, i; | ||
| 82 | |||
| 83 | if (!elem) | ||
| 84 | return -EINVAL; | ||
| 85 | |||
| 86 | entry = kzalloc(sizeof(struct dsp_element_entry), GFP_KERNEL); | ||
| 87 | if (!entry) | ||
| 88 | return -ENOMEM; | ||
| 89 | |||
| 90 | entry->elem = elem; | ||
| 91 | |||
| 92 | entry->dev.class = elements_class; | ||
| 93 | dev_set_drvdata(&entry->dev, elem); | ||
| 94 | snprintf(entry->dev.bus_id, BUS_ID_SIZE, elem->name); | ||
| 95 | ret = device_register(&entry->dev); | ||
| 96 | if (ret) { | ||
| 97 | printk(KERN_ERR "%s: failed to register %s\n", | ||
| 98 | __func__, elem->name); | ||
| 99 | goto err1; | ||
| 100 | } | ||
| 101 | |||
| 102 | for (i = 0; i < (sizeof(element_attributes) | ||
| 103 | / sizeof(struct device_attribute)); ++i) | ||
| 104 | ret = device_create_file(&entry->dev, | ||
| 105 | &element_attributes[i]); | ||
| 106 | if (ret) { | ||
| 107 | printk(KERN_ERR "%s: failed to create device file\n", | ||
| 108 | __func__); | ||
| 109 | goto err2; | ||
| 110 | } | ||
| 111 | |||
| 112 | list_add_tail(&entry->list, &dsp_elements); | ||
| 113 | |||
| 114 | printk(KERN_DEBUG "%s: %s registered\n", __func__, elem->name); | ||
| 115 | |||
| 116 | return 0; | ||
| 117 | |||
| 118 | err2: | ||
| 119 | device_unregister(&entry->dev); | ||
| 120 | err1: | ||
| 121 | kfree(entry); | ||
| 122 | return ret; | ||
| 123 | } | ||
| 124 | EXPORT_SYMBOL(mISDN_dsp_element_register); | ||
| 125 | |||
| 126 | void mISDN_dsp_element_unregister(struct mISDN_dsp_element *elem) | ||
| 127 | { | ||
| 128 | struct dsp_element_entry *entry, *n; | ||
| 129 | |||
| 130 | if (!elem) | ||
| 131 | return; | ||
| 132 | |||
| 133 | list_for_each_entry_safe(entry, n, &dsp_elements, list) | ||
| 134 | if (entry->elem == elem) { | ||
| 135 | list_del(&entry->list); | ||
| 136 | device_unregister(&entry->dev); | ||
| 137 | kfree(entry); | ||
| 138 | printk(KERN_DEBUG "%s: %s unregistered\n", | ||
| 139 | __func__, elem->name); | ||
| 140 | return; | ||
| 141 | } | ||
| 142 | printk(KERN_ERR "%s: element %s not in list.\n", __func__, elem->name); | ||
| 143 | } | ||
| 144 | EXPORT_SYMBOL(mISDN_dsp_element_unregister); | ||
| 145 | |||
| 146 | int dsp_pipeline_module_init(void) | ||
| 147 | { | ||
| 148 | elements_class = class_create(THIS_MODULE, "dsp_pipeline"); | ||
| 149 | if (IS_ERR(elements_class)) | ||
| 150 | return PTR_ERR(elements_class); | ||
| 151 | |||
| 152 | #ifdef PIPELINE_DEBUG | ||
| 153 | printk(KERN_DEBUG "%s: dsp pipeline module initialized\n", __func__); | ||
| 154 | #endif | ||
| 155 | |||
| 156 | dsp_hwec_init(); | ||
| 157 | |||
| 158 | return 0; | ||
| 159 | } | ||
| 160 | |||
| 161 | void dsp_pipeline_module_exit(void) | ||
| 162 | { | ||
| 163 | struct dsp_element_entry *entry, *n; | ||
| 164 | |||
| 165 | dsp_hwec_exit(); | ||
| 166 | |||
| 167 | class_destroy(elements_class); | ||
| 168 | |||
| 169 | list_for_each_entry_safe(entry, n, &dsp_elements, list) { | ||
| 170 | list_del(&entry->list); | ||
| 171 | printk(KERN_WARNING "%s: element was still registered: %s\n", | ||
| 172 | __func__, entry->elem->name); | ||
| 173 | kfree(entry); | ||
| 174 | } | ||
| 175 | |||
| 176 | printk(KERN_DEBUG "%s: dsp pipeline module exited\n", __func__); | ||
| 177 | } | ||
| 178 | |||
| 179 | int dsp_pipeline_init(struct dsp_pipeline *pipeline) | ||
| 180 | { | ||
| 181 | if (!pipeline) | ||
| 182 | return -EINVAL; | ||
| 183 | |||
| 184 | INIT_LIST_HEAD(&pipeline->list); | ||
| 185 | |||
| 186 | #ifdef PIPELINE_DEBUG | ||
| 187 | printk(KERN_DEBUG "%s: dsp pipeline ready\n", __func__); | ||
| 188 | #endif | ||
| 189 | |||
| 190 | return 0; | ||
| 191 | } | ||
| 192 | |||
| 193 | static inline void _dsp_pipeline_destroy(struct dsp_pipeline *pipeline) | ||
| 194 | { | ||
| 195 | struct dsp_pipeline_entry *entry, *n; | ||
| 196 | |||
| 197 | list_for_each_entry_safe(entry, n, &pipeline->list, list) { | ||
| 198 | list_del(&entry->list); | ||
| 199 | if (entry->elem == dsp_hwec) | ||
| 200 | dsp_hwec_disable(container_of(pipeline, struct dsp, | ||
| 201 | pipeline)); | ||
| 202 | else | ||
| 203 | entry->elem->free(entry->p); | ||
| 204 | kfree(entry); | ||
| 205 | } | ||
| 206 | } | ||
| 207 | |||
| 208 | void dsp_pipeline_destroy(struct dsp_pipeline *pipeline) | ||
| 209 | { | ||
| 210 | |||
| 211 | if (!pipeline) | ||
| 212 | return; | ||
| 213 | |||
| 214 | _dsp_pipeline_destroy(pipeline); | ||
| 215 | |||
| 216 | #ifdef PIPELINE_DEBUG | ||
| 217 | printk(KERN_DEBUG "%s: dsp pipeline destroyed\n", __func__); | ||
| 218 | #endif | ||
| 219 | } | ||
| 220 | |||
| 221 | int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg) | ||
| 222 | { | ||
| 223 | int len, incomplete = 0, found = 0; | ||
| 224 | char *dup, *tok, *name, *args; | ||
| 225 | struct dsp_element_entry *entry, *n; | ||
| 226 | struct dsp_pipeline_entry *pipeline_entry; | ||
| 227 | struct mISDN_dsp_element *elem; | ||
| 228 | |||
| 229 | if (!pipeline) | ||
| 230 | return -EINVAL; | ||
| 231 | |||
| 232 | if (!list_empty(&pipeline->list)) | ||
| 233 | _dsp_pipeline_destroy(pipeline); | ||
| 234 | |||
| 235 | if (!cfg) | ||
| 236 | return 0; | ||
| 237 | |||
| 238 | len = strlen(cfg); | ||
| 239 | if (!len) | ||
| 240 | return 0; | ||
| 241 | |||
| 242 | dup = kmalloc(len + 1, GFP_KERNEL); | ||
| 243 | if (!dup) | ||
| 244 | return 0; | ||
| 245 | strcpy(dup, cfg); | ||
| 246 | while ((tok = strsep(&dup, "|"))) { | ||
| 247 | if (!strlen(tok)) | ||
| 248 | continue; | ||
| 249 | name = strsep(&tok, "("); | ||
| 250 | args = strsep(&tok, ")"); | ||
| 251 | if (args && !*args) | ||
| 252 | args = 0; | ||
| 253 | |||
| 254 | list_for_each_entry_safe(entry, n, &dsp_elements, list) | ||
| 255 | if (!strcmp(entry->elem->name, name)) { | ||
| 256 | elem = entry->elem; | ||
| 257 | |||
| 258 | pipeline_entry = kmalloc(sizeof(struct | ||
| 259 | dsp_pipeline_entry), GFP_KERNEL); | ||
| 260 | if (!pipeline_entry) { | ||
| 261 | printk(KERN_DEBUG "%s: failed to add " | ||
| 262 | "entry to pipeline: %s (out of " | ||
| 263 | "memory)\n", __func__, elem->name); | ||
| 264 | incomplete = 1; | ||
| 265 | goto _out; | ||
| 266 | } | ||
| 267 | pipeline_entry->elem = elem; | ||
| 268 | |||
| 269 | if (elem == dsp_hwec) { | ||
| 270 | /* This is a hack to make the hwec | ||
| 271 | available as a pipeline module */ | ||
| 272 | dsp_hwec_enable(container_of(pipeline, | ||
| 273 | struct dsp, pipeline), args); | ||
| 274 | list_add_tail(&pipeline_entry->list, | ||
| 275 | &pipeline->list); | ||
| 276 | } else { | ||
| 277 | pipeline_entry->p = elem->new(args); | ||
| 278 | if (pipeline_entry->p) { | ||
| 279 | list_add_tail(&pipeline_entry-> | ||
| 280 | list, &pipeline->list); | ||
| 281 | #ifdef PIPELINE_DEBUG | ||
| 282 | printk(KERN_DEBUG "%s: created " | ||
| 283 | "instance of %s%s%s\n", | ||
| 284 | __func__, name, args ? | ||
| 285 | " with args " : "", args ? | ||
| 286 | args : ""); | ||
| 287 | #endif | ||
| 288 | } else { | ||
| 289 | printk(KERN_DEBUG "%s: failed " | ||
| 290 | "to add entry to pipeline: " | ||
| 291 | "%s (new() returned NULL)\n", | ||
| 292 | __func__, elem->name); | ||
| 293 | kfree(pipeline_entry); | ||
| 294 | incomplete = 1; | ||
| 295 | } | ||
| 296 | } | ||
| 297 | found = 1; | ||
| 298 | break; | ||
| 299 | } | ||
| 300 | |||
| 301 | if (found) | ||
| 302 | found = 0; | ||
| 303 | else { | ||
| 304 | printk(KERN_DEBUG "%s: element not found, skipping: " | ||
| 305 | "%s\n", __func__, name); | ||
| 306 | incomplete = 1; | ||
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 310 | _out: | ||
| 311 | if (!list_empty(&pipeline->list)) | ||
| 312 | pipeline->inuse = 1; | ||
| 313 | else | ||
| 314 | pipeline->inuse = 0; | ||
| 315 | |||
| 316 | #ifdef PIPELINE_DEBUG | ||
| 317 | printk(KERN_DEBUG "%s: dsp pipeline built%s: %s\n", | ||
| 318 | __func__, incomplete ? " incomplete" : "", cfg); | ||
| 319 | #endif | ||
| 320 | kfree(dup); | ||
| 321 | return 0; | ||
| 322 | } | ||
| 323 | |||
| 324 | void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, int len) | ||
| 325 | { | ||
| 326 | struct dsp_pipeline_entry *entry; | ||
| 327 | |||
| 328 | if (!pipeline) | ||
| 329 | return; | ||
| 330 | |||
| 331 | list_for_each_entry(entry, &pipeline->list, list) | ||
| 332 | if (entry->elem->process_tx) | ||
| 333 | entry->elem->process_tx(entry->p, data, len); | ||
| 334 | } | ||
| 335 | |||
| 336 | void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len) | ||
| 337 | { | ||
| 338 | struct dsp_pipeline_entry *entry; | ||
| 339 | |||
| 340 | if (!pipeline) | ||
| 341 | return; | ||
| 342 | |||
| 343 | list_for_each_entry_reverse(entry, &pipeline->list, list) | ||
| 344 | if (entry->elem->process_rx) | ||
| 345 | entry->elem->process_rx(entry->p, data, len); | ||
| 346 | } | ||
| 347 | |||
| 348 | |||
diff --git a/drivers/isdn/mISDN/dsp_tones.c b/drivers/isdn/mISDN/dsp_tones.c new file mode 100644 index 000000000000..23dd0dd21524 --- /dev/null +++ b/drivers/isdn/mISDN/dsp_tones.c | |||
| @@ -0,0 +1,551 @@ | |||
| 1 | /* | ||
| 2 | * Audio support data for ISDN4Linux. | ||
| 3 | * | ||
| 4 | * Copyright Andreas Eversberg (jolly@eversberg.eu) | ||
| 5 | * | ||
| 6 | * This software may be used and distributed according to the terms | ||
| 7 | * of the GNU General Public License, incorporated herein by reference. | ||
| 8 | * | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/mISDNif.h> | ||
| 12 | #include <linux/mISDNdsp.h> | ||
| 13 | #include "core.h" | ||
| 14 | #include "dsp.h" | ||
| 15 | |||
| 16 | |||
| 17 | #define DATA_S sample_silence | ||
| 18 | #define SIZE_S (&sizeof_silence) | ||
| 19 | #define DATA_GA sample_german_all | ||
| 20 | #define SIZE_GA (&sizeof_german_all) | ||
| 21 | #define DATA_GO sample_german_old | ||
| 22 | #define SIZE_GO (&sizeof_german_old) | ||
| 23 | #define DATA_DT sample_american_dialtone | ||
| 24 | #define SIZE_DT (&sizeof_american_dialtone) | ||
| 25 | #define DATA_RI sample_american_ringing | ||
| 26 | #define SIZE_RI (&sizeof_american_ringing) | ||
| 27 | #define DATA_BU sample_american_busy | ||
| 28 | #define SIZE_BU (&sizeof_american_busy) | ||
| 29 | #define DATA_S1 sample_special1 | ||
| 30 | #define SIZE_S1 (&sizeof_special1) | ||
| 31 | #define DATA_S2 sample_special2 | ||
| 32 | #define SIZE_S2 (&sizeof_special2) | ||
| 33 | #define DATA_S3 sample_special3 | ||
| 34 | #define SIZE_S3 (&sizeof_special3) | ||
| 35 | |||
| 36 | /***************/ | ||
| 37 | /* tones loops */ | ||
| 38 | /***************/ | ||
| 39 | |||
| 40 | /* all tones are alaw encoded */ | ||
| 41 | /* the last sample+1 is in phase with the first sample. the error is low */ | ||
| 42 | |||
| 43 | static u8 sample_german_all[] = { | ||
| 44 | 0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d, | ||
| 45 | 0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c, | ||
| 46 | 0xdc, 0xfc, 0x6c, | ||
| 47 | 0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d, | ||
| 48 | 0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c, | ||
| 49 | 0xdc, 0xfc, 0x6c, | ||
| 50 | 0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d, | ||
| 51 | 0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c, | ||
| 52 | 0xdc, 0xfc, 0x6c, | ||
| 53 | 0x80, 0xab, 0x81, 0x6d, 0xfd, 0xdd, 0x5d, 0x9d, | ||
| 54 | 0x4d, 0xd1, 0x89, 0x88, 0xd0, 0x4c, 0x9c, 0x5c, | ||
| 55 | 0xdc, 0xfc, 0x6c, | ||
| 56 | }; | ||
| 57 | static u32 sizeof_german_all = sizeof(sample_german_all); | ||
| 58 | |||
| 59 | static u8 sample_german_old[] = { | ||
| 60 | 0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed, | ||
| 61 | 0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70, | ||
| 62 | 0x8c, | ||
| 63 | 0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed, | ||
| 64 | 0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70, | ||
| 65 | 0x8c, | ||
| 66 | 0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed, | ||
| 67 | 0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70, | ||
| 68 | 0x8c, | ||
| 69 | 0xec, 0x68, 0xe1, 0x6d, 0x6d, 0x91, 0x51, 0xed, | ||
| 70 | 0x6d, 0x01, 0x1e, 0x10, 0x0c, 0x90, 0x60, 0x70, | ||
| 71 | 0x8c, | ||
| 72 | }; | ||
| 73 | static u32 sizeof_german_old = sizeof(sample_german_old); | ||
| 74 | |||
| 75 | static u8 sample_american_dialtone[] = { | ||
| 76 | 0x2a, 0x18, 0x90, 0x6c, 0x4c, 0xbc, 0x4c, 0x6c, | ||
| 77 | 0x10, 0x58, 0x32, 0xb9, 0x31, 0x2d, 0x8d, 0x0d, | ||
| 78 | 0x8d, 0x2d, 0x31, 0x99, 0x0f, 0x28, 0x60, 0xf0, | ||
| 79 | 0xd0, 0x50, 0xd0, 0x30, 0x60, 0x08, 0x8e, 0x67, | ||
| 80 | 0x09, 0x19, 0x21, 0xe1, 0xd9, 0xb9, 0x29, 0x67, | ||
| 81 | 0x83, 0x02, 0xce, 0xbe, 0xee, 0x1a, 0x1b, 0xef, | ||
| 82 | 0xbf, 0xcf, 0x03, 0x82, 0x66, 0x28, 0xb8, 0xd8, | ||
| 83 | 0xe0, 0x20, 0x18, 0x08, 0x66, 0x8f, 0x09, 0x61, | ||
| 84 | 0x31, 0xd1, 0x51, 0xd1, 0xf1, 0x61, 0x29, 0x0e, | ||
| 85 | 0x98, 0x30, 0x2c, 0x8c, 0x0c, 0x8c, 0x2c, 0x30, | ||
| 86 | 0xb8, 0x33, 0x59, 0x11, 0x6d, 0x4d, 0xbd, 0x4d, | ||
| 87 | 0x6d, 0x91, 0x19, | ||
| 88 | }; | ||
| 89 | static u32 sizeof_american_dialtone = sizeof(sample_american_dialtone); | ||
| 90 | |||
| 91 | static u8 sample_american_ringing[] = { | ||
| 92 | 0x2a, 0xe0, 0xac, 0x0c, 0xbc, 0x4c, 0x8c, 0x90, | ||
| 93 | 0x48, 0xc7, 0xc1, 0xed, 0xcd, 0x4d, 0xcd, 0xed, | ||
| 94 | 0xc1, 0xb7, 0x08, 0x30, 0xec, 0xcc, 0xcc, 0x8c, | ||
| 95 | 0x10, 0x58, 0x1a, 0x99, 0x71, 0xed, 0x8d, 0x8d, | ||
| 96 | 0x2d, 0x41, 0x89, 0x9e, 0x20, 0x70, 0x2c, 0xec, | ||
| 97 | 0x2c, 0x70, 0x20, 0x86, 0x77, 0xe1, 0x31, 0x11, | ||
| 98 | 0xd1, 0xf1, 0x81, 0x09, 0xa3, 0x56, 0x58, 0x00, | ||
| 99 | 0x40, 0xc0, 0x60, 0x38, 0x46, 0x43, 0x57, 0x39, | ||
| 100 | 0xd9, 0x59, 0x99, 0xc9, 0x77, 0x2f, 0x2e, 0xc6, | ||
| 101 | 0xd6, 0x28, 0xd6, 0x36, 0x26, 0x2e, 0x8a, 0xa3, | ||
| 102 | 0x43, 0x63, 0x4b, 0x4a, 0x62, 0x42, 0xa2, 0x8b, | ||
| 103 | 0x2f, 0x27, 0x37, 0xd7, 0x29, 0xd7, 0xc7, 0x2f, | ||
| 104 | 0x2e, 0x76, 0xc8, 0x98, 0x58, 0xd8, 0x38, 0x56, | ||
| 105 | 0x42, 0x47, 0x39, 0x61, 0xc1, 0x41, 0x01, 0x59, | ||
| 106 | 0x57, 0xa2, 0x08, 0x80, 0xf0, 0xd0, 0x10, 0x30, | ||
| 107 | 0xe0, 0x76, 0x87, 0x21, 0x71, 0x2d, 0xed, 0x2d, | ||
| 108 | 0x71, 0x21, 0x9f, 0x88, 0x40, 0x2c, 0x8c, 0x8c, | ||
| 109 | 0xec, 0x70, 0x98, 0x1b, 0x59, 0x11, 0x8d, 0xcd, | ||
| 110 | 0xcd, 0xed, 0x31, 0x09, 0xb6, 0xc0, 0xec, 0xcc, | ||
| 111 | 0x4c, 0xcc, 0xec, 0xc0, 0xc6, 0x49, 0x91, 0x8d, | ||
| 112 | 0x4d, 0xbd, 0x0d, 0xad, 0xe1, | ||
| 113 | }; | ||
| 114 | static u32 sizeof_american_ringing = sizeof(sample_american_ringing); | ||
| 115 | |||
| 116 | static u8 sample_american_busy[] = { | ||
| 117 | 0x2a, 0x00, 0x6c, 0x4c, 0x4c, 0x6c, 0xb0, 0x66, | ||
| 118 | 0x99, 0x11, 0x6d, 0x8d, 0x2d, 0x41, 0xd7, 0x96, | ||
| 119 | 0x60, 0xf0, 0x70, 0x40, 0x58, 0xf6, 0x53, 0x57, | ||
| 120 | 0x09, 0x89, 0xd7, 0x5f, 0xe3, 0x2a, 0xe3, 0x5f, | ||
| 121 | 0xd7, 0x89, 0x09, 0x57, 0x53, 0xf6, 0x58, 0x40, | ||
| 122 | 0x70, 0xf0, 0x60, 0x96, 0xd7, 0x41, 0x2d, 0x8d, | ||
| 123 | 0x6d, 0x11, 0x99, 0x66, 0xb0, 0x6c, 0x4c, 0x4c, | ||
| 124 | 0x6c, 0x00, 0x2a, 0x01, 0x6d, 0x4d, 0x4d, 0x6d, | ||
| 125 | 0xb1, 0x67, 0x98, 0x10, 0x6c, 0x8c, 0x2c, 0x40, | ||
| 126 | 0xd6, 0x97, 0x61, 0xf1, 0x71, 0x41, 0x59, 0xf7, | ||
| 127 | 0x52, 0x56, 0x08, 0x88, 0xd6, 0x5e, 0xe2, 0x2a, | ||
| 128 | 0xe2, 0x5e, 0xd6, 0x88, 0x08, 0x56, 0x52, 0xf7, | ||
| 129 | 0x59, 0x41, 0x71, 0xf1, 0x61, 0x97, 0xd6, 0x40, | ||
| 130 | 0x2c, 0x8c, 0x6c, 0x10, 0x98, 0x67, 0xb1, 0x6d, | ||
| 131 | 0x4d, 0x4d, 0x6d, 0x01, | ||
| 132 | }; | ||
| 133 | static u32 sizeof_american_busy = sizeof(sample_american_busy); | ||
| 134 | |||
| 135 | static u8 sample_special1[] = { | ||
| 136 | 0x2a, 0x2c, 0xbc, 0x6c, 0xd6, 0x71, 0xbd, 0x0d, | ||
| 137 | 0xd9, 0x80, 0xcc, 0x4c, 0x40, 0x39, 0x0d, 0xbd, | ||
| 138 | 0x11, 0x86, 0xec, 0xbc, 0xec, 0x0e, 0x51, 0xbd, | ||
| 139 | 0x8d, 0x89, 0x30, 0x4c, 0xcc, 0xe0, 0xe1, 0xcd, | ||
| 140 | 0x4d, 0x31, 0x88, 0x8c, 0xbc, 0x50, 0x0f, 0xed, | ||
| 141 | 0xbd, 0xed, 0x87, 0x10, 0xbc, 0x0c, 0x38, 0x41, | ||
| 142 | 0x4d, 0xcd, 0x81, 0xd8, 0x0c, 0xbc, 0x70, 0xd7, | ||
| 143 | 0x6d, 0xbd, 0x2d, | ||
| 144 | }; | ||
| 145 | static u32 sizeof_special1 = sizeof(sample_special1); | ||
| 146 | |||
| 147 | static u8 sample_special2[] = { | ||
| 148 | 0x2a, 0xcc, 0x8c, 0xd7, 0x4d, 0x2d, 0x18, 0xbc, | ||
| 149 | 0x10, 0xc1, 0xbd, 0xc1, 0x10, 0xbc, 0x18, 0x2d, | ||
| 150 | 0x4d, 0xd7, 0x8c, 0xcc, 0x2a, 0xcd, 0x8d, 0xd6, | ||
| 151 | 0x4c, 0x2c, 0x19, 0xbd, 0x11, 0xc0, 0xbc, 0xc0, | ||
| 152 | 0x11, 0xbd, 0x19, 0x2c, 0x4c, 0xd6, 0x8d, 0xcd, | ||
| 153 | 0x2a, 0xcc, 0x8c, 0xd7, 0x4d, 0x2d, 0x18, 0xbc, | ||
| 154 | 0x10, 0xc1, 0xbd, 0xc1, 0x10, 0xbc, 0x18, 0x2d, | ||
| 155 | 0x4d, 0xd7, 0x8c, 0xcc, 0x2a, 0xcd, 0x8d, 0xd6, | ||
| 156 | 0x4c, 0x2c, 0x19, 0xbd, 0x11, 0xc0, 0xbc, 0xc0, | ||
| 157 | 0x11, 0xbd, 0x19, 0x2c, 0x4c, 0xd6, 0x8d, 0xcd, | ||
| 158 | }; | ||
| 159 | static u32 sizeof_special2 = sizeof(sample_special2); | ||
| 160 | |||
| 161 | static u8 sample_special3[] = { | ||
| 162 | 0x2a, 0xbc, 0x18, 0xcd, 0x11, 0x2c, 0x8c, 0xc1, | ||
| 163 | 0x4d, 0xd6, 0xbc, 0xd6, 0x4d, 0xc1, 0x8c, 0x2c, | ||
| 164 | 0x11, 0xcd, 0x18, 0xbc, 0x2a, 0xbd, 0x19, 0xcc, | ||
| 165 | 0x10, 0x2d, 0x8d, 0xc0, 0x4c, 0xd7, 0xbd, 0xd7, | ||
| 166 | 0x4c, 0xc0, 0x8d, 0x2d, 0x10, 0xcc, 0x19, 0xbd, | ||
| 167 | 0x2a, 0xbc, 0x18, 0xcd, 0x11, 0x2c, 0x8c, 0xc1, | ||
| 168 | 0x4d, 0xd6, 0xbc, 0xd6, 0x4d, 0xc1, 0x8c, 0x2c, | ||
| 169 | 0x11, 0xcd, 0x18, 0xbc, 0x2a, 0xbd, 0x19, 0xcc, | ||
| 170 | 0x10, 0x2d, 0x8d, 0xc0, 0x4c, 0xd7, 0xbd, 0xd7, | ||
| 171 | 0x4c, 0xc0, 0x8d, 0x2d, 0x10, 0xcc, 0x19, 0xbd, | ||
| 172 | }; | ||
| 173 | static u32 sizeof_special3 = sizeof(sample_special3); | ||
| 174 | |||
| 175 | static u8 sample_silence[] = { | ||
| 176 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
| 177 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
| 178 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
| 179 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
| 180 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
| 181 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
| 182 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
| 183 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
| 184 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
| 185 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
| 186 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
| 187 | 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, | ||
| 188 | }; | ||
| 189 | static u32 sizeof_silence = sizeof(sample_silence); | ||
| 190 | |||
| 191 | struct tones_samples { | ||
| 192 | u32 *len; | ||
| 193 | u8 *data; | ||
| 194 | }; | ||
| 195 | static struct | ||
| 196 | tones_samples samples[] = { | ||
| 197 | {&sizeof_german_all, sample_german_all}, | ||
| 198 | {&sizeof_german_old, sample_german_old}, | ||
| 199 | {&sizeof_american_dialtone, sample_american_dialtone}, | ||
| 200 | {&sizeof_american_ringing, sample_american_ringing}, | ||
| 201 | {&sizeof_american_busy, sample_american_busy}, | ||
| 202 | {&sizeof_special1, sample_special1}, | ||
| 203 | {&sizeof_special2, sample_special2}, | ||
| 204 | {&sizeof_special3, sample_special3}, | ||
| 205 | {NULL, NULL}, | ||
| 206 | }; | ||
| 207 | |||
| 208 | /*********************************** | ||
| 209 | * generate ulaw from alaw samples * | ||
| 210 | ***********************************/ | ||
| 211 | |||
| 212 | void | ||
| 213 | dsp_audio_generate_ulaw_samples(void) | ||
| 214 | { | ||
| 215 | int i, j; | ||
| 216 | |||
| 217 | i = 0; | ||
| 218 | while (samples[i].len) { | ||
| 219 | j = 0; | ||
| 220 | while (j < (*samples[i].len)) { | ||
| 221 | samples[i].data[j] = | ||
| 222 | dsp_audio_alaw_to_ulaw[samples[i].data[j]]; | ||
| 223 | j++; | ||
| 224 | } | ||
| 225 | i++; | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | |||
| 230 | /**************************** | ||
| 231 | * tone sequence definition * | ||
| 232 | ****************************/ | ||
| 233 | |||
| 234 | struct pattern { | ||
| 235 | int tone; | ||
| 236 | u8 *data[10]; | ||
| 237 | u32 *siz[10]; | ||
| 238 | u32 seq[10]; | ||
| 239 | } pattern[] = { | ||
| 240 | {TONE_GERMAN_DIALTONE, | ||
| 241 | {DATA_GA, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 242 | {SIZE_GA, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 243 | {1900, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
| 244 | |||
| 245 | {TONE_GERMAN_OLDDIALTONE, | ||
| 246 | {DATA_GO, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 247 | {SIZE_GO, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 248 | {1998, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
| 249 | |||
| 250 | {TONE_AMERICAN_DIALTONE, | ||
| 251 | {DATA_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 252 | {SIZE_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 253 | {8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
| 254 | |||
| 255 | {TONE_GERMAN_DIALPBX, | ||
| 256 | {DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, 0, 0, 0, 0}, | ||
| 257 | {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, 0, 0, 0, 0}, | ||
| 258 | {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, | ||
| 259 | |||
| 260 | {TONE_GERMAN_OLDDIALPBX, | ||
| 261 | {DATA_GO, DATA_S, DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0}, | ||
| 262 | {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0}, | ||
| 263 | {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, | ||
| 264 | |||
| 265 | {TONE_AMERICAN_DIALPBX, | ||
| 266 | {DATA_DT, DATA_S, DATA_DT, DATA_S, DATA_DT, DATA_S, 0, 0, 0, 0}, | ||
| 267 | {SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, 0, 0, 0, 0}, | ||
| 268 | {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, | ||
| 269 | |||
| 270 | {TONE_GERMAN_RINGING, | ||
| 271 | {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 272 | {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 273 | {8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
| 274 | |||
| 275 | {TONE_GERMAN_OLDRINGING, | ||
| 276 | {DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 277 | {SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 278 | {8000, 40000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
| 279 | |||
| 280 | {TONE_AMERICAN_RINGING, | ||
| 281 | {DATA_RI, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 282 | {SIZE_RI, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 283 | {8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
| 284 | |||
| 285 | {TONE_GERMAN_RINGPBX, | ||
| 286 | {DATA_GA, DATA_S, DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0}, | ||
| 287 | {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0}, | ||
| 288 | {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, | ||
| 289 | |||
| 290 | {TONE_GERMAN_OLDRINGPBX, | ||
| 291 | {DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0}, | ||
| 292 | {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0}, | ||
| 293 | {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, | ||
| 294 | |||
| 295 | {TONE_AMERICAN_RINGPBX, | ||
| 296 | {DATA_RI, DATA_S, DATA_RI, DATA_S, 0, 0, 0, 0, 0, 0}, | ||
| 297 | {SIZE_RI, SIZE_S, SIZE_RI, SIZE_S, 0, 0, 0, 0, 0, 0}, | ||
| 298 | {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, | ||
| 299 | |||
| 300 | {TONE_GERMAN_BUSY, | ||
| 301 | {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 302 | {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 303 | {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
| 304 | |||
| 305 | {TONE_GERMAN_OLDBUSY, | ||
| 306 | {DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 307 | {SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 308 | {1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
| 309 | |||
| 310 | {TONE_AMERICAN_BUSY, | ||
| 311 | {DATA_BU, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 312 | {SIZE_BU, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 313 | {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
| 314 | |||
| 315 | {TONE_GERMAN_HANGUP, | ||
| 316 | {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 317 | {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 318 | {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
| 319 | |||
| 320 | {TONE_GERMAN_OLDHANGUP, | ||
| 321 | {DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 322 | {SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 323 | {1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
| 324 | |||
| 325 | {TONE_AMERICAN_HANGUP, | ||
| 326 | {DATA_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 327 | {SIZE_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 328 | {8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
| 329 | |||
| 330 | {TONE_SPECIAL_INFO, | ||
| 331 | {DATA_S1, DATA_S2, DATA_S3, DATA_S, 0, 0, 0, 0, 0, 0}, | ||
| 332 | {SIZE_S1, SIZE_S2, SIZE_S3, SIZE_S, 0, 0, 0, 0, 0, 0}, | ||
| 333 | {2666, 2666, 2666, 8002, 0, 0, 0, 0, 0, 0} }, | ||
| 334 | |||
| 335 | {TONE_GERMAN_GASSENBESETZT, | ||
| 336 | {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 337 | {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 338 | {2000, 2000, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
| 339 | |||
| 340 | {TONE_GERMAN_AUFSCHALTTON, | ||
| 341 | {DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0}, | ||
| 342 | {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0}, | ||
| 343 | {1000, 5000, 1000, 17000, 0, 0, 0, 0, 0, 0} }, | ||
| 344 | |||
| 345 | {0, | ||
| 346 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 347 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, | ||
| 348 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, | ||
| 349 | }; | ||
| 350 | |||
| 351 | /****************** | ||
| 352 | * copy tone data * | ||
| 353 | ******************/ | ||
| 354 | |||
| 355 | /* an sk_buff is generated from the number of samples needed. | ||
| 356 | * the count will be changed and may begin from 0 each pattern period. | ||
| 357 | * the clue is to precalculate the pointers and legths to use only one | ||
| 358 | * memcpy per function call, or two memcpy if the tone sequence changes. | ||
| 359 | * | ||
| 360 | * pattern - the type of the pattern | ||
| 361 | * count - the sample from the beginning of the pattern (phase) | ||
| 362 | * len - the number of bytes | ||
| 363 | * | ||
| 364 | * return - the sk_buff with the sample | ||
| 365 | * | ||
| 366 | * if tones has finished (e.g. knocking tone), dsp->tones is turned off | ||
| 367 | */ | ||
| 368 | void dsp_tone_copy(struct dsp *dsp, u8 *data, int len) | ||
| 369 | { | ||
| 370 | int index, count, start, num; | ||
| 371 | struct pattern *pat; | ||
| 372 | struct dsp_tone *tone = &dsp->tone; | ||
| 373 | |||
| 374 | /* if we have no tone, we copy silence */ | ||
| 375 | if (!tone->tone) { | ||
| 376 | memset(data, dsp_silence, len); | ||
| 377 | return; | ||
| 378 | } | ||
| 379 | |||
| 380 | /* process pattern */ | ||
| 381 | pat = (struct pattern *)tone->pattern; | ||
| 382 | /* points to the current pattern */ | ||
| 383 | index = tone->index; /* gives current sequence index */ | ||
| 384 | count = tone->count; /* gives current sample */ | ||
| 385 | |||
| 386 | /* copy sample */ | ||
| 387 | while (len) { | ||
| 388 | /* find sample to start with */ | ||
| 389 | while (42) { | ||
| 390 | /* warp arround */ | ||
| 391 | if (!pat->seq[index]) { | ||
| 392 | count = 0; | ||
| 393 | index = 0; | ||
| 394 | } | ||
| 395 | /* check if we are currently playing this tone */ | ||
| 396 | if (count < pat->seq[index]) | ||
| 397 | break; | ||
| 398 | if (dsp_debug & DEBUG_DSP_TONE) | ||
| 399 | printk(KERN_DEBUG "%s: reaching next sequence " | ||
| 400 | "(index=%d)\n", __func__, index); | ||
| 401 | count -= pat->seq[index]; | ||
| 402 | index++; | ||
| 403 | } | ||
| 404 | /* calculate start and number of samples */ | ||
| 405 | start = count % (*(pat->siz[index])); | ||
| 406 | num = len; | ||
| 407 | if (num+count > pat->seq[index]) | ||
| 408 | num = pat->seq[index] - count; | ||
| 409 | if (num+start > (*(pat->siz[index]))) | ||
| 410 | num = (*(pat->siz[index])) - start; | ||
| 411 | /* copy memory */ | ||
| 412 | memcpy(data, pat->data[index]+start, num); | ||
| 413 | /* reduce length */ | ||
| 414 | data += num; | ||
| 415 | count += num; | ||
| 416 | len -= num; | ||
| 417 | } | ||
| 418 | tone->index = index; | ||
| 419 | tone->count = count; | ||
| 420 | |||
| 421 | /* return sk_buff */ | ||
| 422 | return; | ||
| 423 | } | ||
| 424 | |||
| 425 | |||
| 426 | /******************************* | ||
| 427 | * send HW message to hfc card * | ||
| 428 | *******************************/ | ||
| 429 | |||
| 430 | static void | ||
| 431 | dsp_tone_hw_message(struct dsp *dsp, u8 *sample, int len) | ||
| 432 | { | ||
| 433 | struct sk_buff *nskb; | ||
| 434 | |||
| 435 | /* unlocking is not required, because we don't expect a response */ | ||
| 436 | nskb = _alloc_mISDN_skb(PH_CONTROL_REQ, | ||
| 437 | (len)?HFC_SPL_LOOP_ON:HFC_SPL_LOOP_OFF, len, sample, | ||
| 438 | GFP_ATOMIC); | ||
| 439 | if (nskb) { | ||
| 440 | if (dsp->ch.peer) { | ||
| 441 | if (dsp->ch.recv(dsp->ch.peer, nskb)) | ||
| 442 | dev_kfree_skb(nskb); | ||
| 443 | } else | ||
| 444 | dev_kfree_skb(nskb); | ||
| 445 | } | ||
| 446 | } | ||
| 447 | |||
| 448 | |||
| 449 | /***************** | ||
| 450 | * timer expires * | ||
| 451 | *****************/ | ||
| 452 | void | ||
| 453 | dsp_tone_timeout(void *arg) | ||
| 454 | { | ||
| 455 | struct dsp *dsp = arg; | ||
| 456 | struct dsp_tone *tone = &dsp->tone; | ||
| 457 | struct pattern *pat = (struct pattern *)tone->pattern; | ||
| 458 | int index = tone->index; | ||
| 459 | |||
| 460 | if (!tone->tone) | ||
| 461 | return; | ||
| 462 | |||
| 463 | index++; | ||
| 464 | if (!pat->seq[index]) | ||
| 465 | index = 0; | ||
| 466 | tone->index = index; | ||
| 467 | |||
| 468 | /* set next tone */ | ||
| 469 | if (pat->data[index] == DATA_S) | ||
| 470 | dsp_tone_hw_message(dsp, 0, 0); | ||
| 471 | else | ||
| 472 | dsp_tone_hw_message(dsp, pat->data[index], *(pat->siz[index])); | ||
| 473 | /* set timer */ | ||
| 474 | init_timer(&tone->tl); | ||
| 475 | tone->tl.expires = jiffies + (pat->seq[index] * HZ) / 8000; | ||
| 476 | add_timer(&tone->tl); | ||
| 477 | } | ||
| 478 | |||
| 479 | |||
| 480 | /******************** | ||
| 481 | * set/release tone * | ||
| 482 | ********************/ | ||
| 483 | |||
| 484 | /* | ||
| 485 | * tones are relaized by streaming or by special loop commands if supported | ||
| 486 | * by hardware. when hardware is used, the patterns will be controlled by | ||
| 487 | * timers. | ||
| 488 | */ | ||
| 489 | int | ||
| 490 | dsp_tone(struct dsp *dsp, int tone) | ||
| 491 | { | ||
| 492 | struct pattern *pat; | ||
| 493 | int i; | ||
| 494 | struct dsp_tone *tonet = &dsp->tone; | ||
| 495 | |||
| 496 | tonet->software = 0; | ||
| 497 | tonet->hardware = 0; | ||
| 498 | |||
| 499 | /* we turn off the tone */ | ||
| 500 | if (!tone) { | ||
| 501 | if (dsp->features.hfc_loops) | ||
| 502 | if (timer_pending(&tonet->tl)) | ||
| 503 | del_timer(&tonet->tl); | ||
| 504 | if (dsp->features.hfc_loops) | ||
| 505 | dsp_tone_hw_message(dsp, NULL, 0); | ||
| 506 | tonet->tone = 0; | ||
| 507 | return 0; | ||
| 508 | } | ||
| 509 | |||
| 510 | pat = NULL; | ||
| 511 | i = 0; | ||
| 512 | while (pattern[i].tone) { | ||
| 513 | if (pattern[i].tone == tone) { | ||
| 514 | pat = &pattern[i]; | ||
| 515 | break; | ||
| 516 | } | ||
| 517 | i++; | ||
| 518 | } | ||
| 519 | if (!pat) { | ||
| 520 | printk(KERN_WARNING "dsp: given tone 0x%x is invalid\n", tone); | ||
| 521 | return -EINVAL; | ||
| 522 | } | ||
| 523 | if (dsp_debug & DEBUG_DSP_TONE) | ||
| 524 | printk(KERN_DEBUG "%s: now starting tone %d (index=%d)\n", | ||
| 525 | __func__, tone, 0); | ||
| 526 | tonet->tone = tone; | ||
| 527 | tonet->pattern = pat; | ||
| 528 | tonet->index = 0; | ||
| 529 | tonet->count = 0; | ||
| 530 | |||
| 531 | if (dsp->features.hfc_loops) { | ||
| 532 | tonet->hardware = 1; | ||
| 533 | /* set first tone */ | ||
| 534 | dsp_tone_hw_message(dsp, pat->data[0], *(pat->siz[0])); | ||
| 535 | /* set timer */ | ||
| 536 | if (timer_pending(&tonet->tl)) | ||
| 537 | del_timer(&tonet->tl); | ||
| 538 | init_timer(&tonet->tl); | ||
| 539 | tonet->tl.expires = jiffies + (pat->seq[0] * HZ) / 8000; | ||
| 540 | add_timer(&tonet->tl); | ||
| 541 | } else { | ||
| 542 | tonet->software = 1; | ||
| 543 | } | ||
| 544 | |||
| 545 | return 0; | ||
| 546 | } | ||
| 547 | |||
| 548 | |||
| 549 | |||
| 550 | |||
| 551 | |||
diff --git a/drivers/isdn/mISDN/fsm.c b/drivers/isdn/mISDN/fsm.c new file mode 100644 index 000000000000..b5d6553f2dc8 --- /dev/null +++ b/drivers/isdn/mISDN/fsm.c | |||
| @@ -0,0 +1,183 @@ | |||
| 1 | /* | ||
| 2 | * finite state machine implementation | ||
| 3 | * | ||
| 4 | * Author Karsten Keil <kkeil@novell.com> | ||
| 5 | * | ||
| 6 | * Thanks to Jan den Ouden | ||
| 7 | * Fritz Elfert | ||
| 8 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/slab.h> | ||
| 23 | #include <linux/module.h> | ||
| 24 | #include <linux/string.h> | ||
| 25 | #include "fsm.h" | ||
| 26 | |||
| 27 | #define FSM_TIMER_DEBUG 0 | ||
| 28 | |||
| 29 | void | ||
| 30 | mISDN_FsmNew(struct Fsm *fsm, | ||
| 31 | struct FsmNode *fnlist, int fncount) | ||
| 32 | { | ||
| 33 | int i; | ||
| 34 | |||
| 35 | fsm->jumpmatrix = kzalloc(sizeof(FSMFNPTR) * fsm->state_count * | ||
| 36 | fsm->event_count, GFP_KERNEL); | ||
| 37 | |||
| 38 | for (i = 0; i < fncount; i++) | ||
| 39 | if ((fnlist[i].state >= fsm->state_count) || | ||
| 40 | (fnlist[i].event >= fsm->event_count)) { | ||
| 41 | printk(KERN_ERR | ||
| 42 | "mISDN_FsmNew Error: %d st(%ld/%ld) ev(%ld/%ld)\n", | ||
| 43 | i, (long)fnlist[i].state, (long)fsm->state_count, | ||
| 44 | (long)fnlist[i].event, (long)fsm->event_count); | ||
| 45 | } else | ||
| 46 | fsm->jumpmatrix[fsm->state_count * fnlist[i].event + | ||
| 47 | fnlist[i].state] = (FSMFNPTR) fnlist[i].routine; | ||
| 48 | } | ||
| 49 | EXPORT_SYMBOL(mISDN_FsmNew); | ||
| 50 | |||
| 51 | void | ||
| 52 | mISDN_FsmFree(struct Fsm *fsm) | ||
| 53 | { | ||
| 54 | kfree((void *) fsm->jumpmatrix); | ||
| 55 | } | ||
| 56 | EXPORT_SYMBOL(mISDN_FsmFree); | ||
| 57 | |||
| 58 | int | ||
| 59 | mISDN_FsmEvent(struct FsmInst *fi, int event, void *arg) | ||
| 60 | { | ||
| 61 | FSMFNPTR r; | ||
| 62 | |||
| 63 | if ((fi->state >= fi->fsm->state_count) || | ||
| 64 | (event >= fi->fsm->event_count)) { | ||
| 65 | printk(KERN_ERR | ||
| 66 | "mISDN_FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n", | ||
| 67 | (long)fi->state, (long)fi->fsm->state_count, event, | ||
| 68 | (long)fi->fsm->event_count); | ||
| 69 | return 1; | ||
| 70 | } | ||
| 71 | r = fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state]; | ||
| 72 | if (r) { | ||
| 73 | if (fi->debug) | ||
| 74 | fi->printdebug(fi, "State %s Event %s", | ||
| 75 | fi->fsm->strState[fi->state], | ||
| 76 | fi->fsm->strEvent[event]); | ||
| 77 | r(fi, event, arg); | ||
| 78 | return 0; | ||
| 79 | } else { | ||
| 80 | if (fi->debug) | ||
| 81 | fi->printdebug(fi, "State %s Event %s no action", | ||
| 82 | fi->fsm->strState[fi->state], | ||
| 83 | fi->fsm->strEvent[event]); | ||
| 84 | return 1; | ||
| 85 | } | ||
| 86 | } | ||
| 87 | EXPORT_SYMBOL(mISDN_FsmEvent); | ||
| 88 | |||
| 89 | void | ||
| 90 | mISDN_FsmChangeState(struct FsmInst *fi, int newstate) | ||
| 91 | { | ||
| 92 | fi->state = newstate; | ||
| 93 | if (fi->debug) | ||
| 94 | fi->printdebug(fi, "ChangeState %s", | ||
| 95 | fi->fsm->strState[newstate]); | ||
| 96 | } | ||
| 97 | EXPORT_SYMBOL(mISDN_FsmChangeState); | ||
| 98 | |||
| 99 | static void | ||
| 100 | FsmExpireTimer(struct FsmTimer *ft) | ||
| 101 | { | ||
| 102 | #if FSM_TIMER_DEBUG | ||
| 103 | if (ft->fi->debug) | ||
| 104 | ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft); | ||
| 105 | #endif | ||
| 106 | mISDN_FsmEvent(ft->fi, ft->event, ft->arg); | ||
| 107 | } | ||
| 108 | |||
| 109 | void | ||
| 110 | mISDN_FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft) | ||
| 111 | { | ||
| 112 | ft->fi = fi; | ||
| 113 | ft->tl.function = (void *) FsmExpireTimer; | ||
| 114 | ft->tl.data = (long) ft; | ||
| 115 | #if FSM_TIMER_DEBUG | ||
| 116 | if (ft->fi->debug) | ||
| 117 | ft->fi->printdebug(ft->fi, "mISDN_FsmInitTimer %lx", (long) ft); | ||
| 118 | #endif | ||
| 119 | init_timer(&ft->tl); | ||
| 120 | } | ||
| 121 | EXPORT_SYMBOL(mISDN_FsmInitTimer); | ||
| 122 | |||
| 123 | void | ||
| 124 | mISDN_FsmDelTimer(struct FsmTimer *ft, int where) | ||
| 125 | { | ||
| 126 | #if FSM_TIMER_DEBUG | ||
| 127 | if (ft->fi->debug) | ||
| 128 | ft->fi->printdebug(ft->fi, "mISDN_FsmDelTimer %lx %d", | ||
| 129 | (long) ft, where); | ||
| 130 | #endif | ||
| 131 | del_timer(&ft->tl); | ||
| 132 | } | ||
| 133 | EXPORT_SYMBOL(mISDN_FsmDelTimer); | ||
| 134 | |||
| 135 | int | ||
| 136 | mISDN_FsmAddTimer(struct FsmTimer *ft, | ||
| 137 | int millisec, int event, void *arg, int where) | ||
| 138 | { | ||
| 139 | |||
| 140 | #if FSM_TIMER_DEBUG | ||
| 141 | if (ft->fi->debug) | ||
| 142 | ft->fi->printdebug(ft->fi, "mISDN_FsmAddTimer %lx %d %d", | ||
| 143 | (long) ft, millisec, where); | ||
| 144 | #endif | ||
| 145 | |||
| 146 | if (timer_pending(&ft->tl)) { | ||
| 147 | if (ft->fi->debug) { | ||
| 148 | printk(KERN_WARNING | ||
| 149 | "mISDN_FsmAddTimer: timer already active!\n"); | ||
| 150 | ft->fi->printdebug(ft->fi, | ||
| 151 | "mISDN_FsmAddTimer already active!"); | ||
| 152 | } | ||
| 153 | return -1; | ||
| 154 | } | ||
| 155 | init_timer(&ft->tl); | ||
| 156 | ft->event = event; | ||
| 157 | ft->arg = arg; | ||
| 158 | ft->tl.expires = jiffies + (millisec * HZ) / 1000; | ||
| 159 | add_timer(&ft->tl); | ||
| 160 | return 0; | ||
| 161 | } | ||
| 162 | EXPORT_SYMBOL(mISDN_FsmAddTimer); | ||
| 163 | |||
| 164 | void | ||
| 165 | mISDN_FsmRestartTimer(struct FsmTimer *ft, | ||
| 166 | int millisec, int event, void *arg, int where) | ||
| 167 | { | ||
| 168 | |||
| 169 | #if FSM_TIMER_DEBUG | ||
| 170 | if (ft->fi->debug) | ||
| 171 | ft->fi->printdebug(ft->fi, "mISDN_FsmRestartTimer %lx %d %d", | ||
| 172 | (long) ft, millisec, where); | ||
| 173 | #endif | ||
| 174 | |||
| 175 | if (timer_pending(&ft->tl)) | ||
| 176 | del_timer(&ft->tl); | ||
| 177 | init_timer(&ft->tl); | ||
| 178 | ft->event = event; | ||
| 179 | ft->arg = arg; | ||
| 180 | ft->tl.expires = jiffies + (millisec * HZ) / 1000; | ||
| 181 | add_timer(&ft->tl); | ||
| 182 | } | ||
| 183 | EXPORT_SYMBOL(mISDN_FsmRestartTimer); | ||
diff --git a/drivers/isdn/mISDN/fsm.h b/drivers/isdn/mISDN/fsm.h new file mode 100644 index 000000000000..928f5be192c1 --- /dev/null +++ b/drivers/isdn/mISDN/fsm.h | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * Author Karsten Keil <kkeil@novell.com> | ||
| 4 | * | ||
| 5 | * Thanks to Jan den Ouden | ||
| 6 | * Fritz Elfert | ||
| 7 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | */ | ||
| 19 | |||
| 20 | #ifndef _MISDN_FSM_H | ||
| 21 | #define _MISDN_FSM_H | ||
| 22 | |||
| 23 | #include <linux/timer.h> | ||
| 24 | |||
| 25 | /* Statemachine */ | ||
| 26 | |||
| 27 | struct FsmInst; | ||
| 28 | |||
| 29 | typedef void (*FSMFNPTR)(struct FsmInst *, int, void *); | ||
| 30 | |||
| 31 | struct Fsm { | ||
| 32 | FSMFNPTR *jumpmatrix; | ||
| 33 | int state_count, event_count; | ||
| 34 | char **strEvent, **strState; | ||
| 35 | }; | ||
| 36 | |||
| 37 | struct FsmInst { | ||
| 38 | struct Fsm *fsm; | ||
| 39 | int state; | ||
| 40 | int debug; | ||
| 41 | void *userdata; | ||
| 42 | int userint; | ||
| 43 | void (*printdebug) (struct FsmInst *, char *, ...); | ||
| 44 | }; | ||
| 45 | |||
| 46 | struct FsmNode { | ||
| 47 | int state, event; | ||
| 48 | void (*routine) (struct FsmInst *, int, void *); | ||
| 49 | }; | ||
| 50 | |||
| 51 | struct FsmTimer { | ||
| 52 | struct FsmInst *fi; | ||
| 53 | struct timer_list tl; | ||
| 54 | int event; | ||
| 55 | void *arg; | ||
| 56 | }; | ||
| 57 | |||
| 58 | extern void mISDN_FsmNew(struct Fsm *, struct FsmNode *, int); | ||
| 59 | extern void mISDN_FsmFree(struct Fsm *); | ||
| 60 | extern int mISDN_FsmEvent(struct FsmInst *, int , void *); | ||
| 61 | extern void mISDN_FsmChangeState(struct FsmInst *, int); | ||
| 62 | extern void mISDN_FsmInitTimer(struct FsmInst *, struct FsmTimer *); | ||
| 63 | extern int mISDN_FsmAddTimer(struct FsmTimer *, int, int, void *, int); | ||
| 64 | extern void mISDN_FsmRestartTimer(struct FsmTimer *, int, int, void *, int); | ||
| 65 | extern void mISDN_FsmDelTimer(struct FsmTimer *, int); | ||
| 66 | |||
| 67 | #endif | ||
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c new file mode 100644 index 000000000000..2596fba4e614 --- /dev/null +++ b/drivers/isdn/mISDN/hwchannel.c | |||
| @@ -0,0 +1,365 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * Author Karsten Keil <kkeil@novell.com> | ||
| 4 | * | ||
| 5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/mISDNhw.h> | ||
| 20 | |||
| 21 | static void | ||
| 22 | dchannel_bh(struct work_struct *ws) | ||
| 23 | { | ||
| 24 | struct dchannel *dch = container_of(ws, struct dchannel, workq); | ||
| 25 | struct sk_buff *skb; | ||
| 26 | int err; | ||
| 27 | |||
| 28 | if (test_and_clear_bit(FLG_RECVQUEUE, &dch->Flags)) { | ||
| 29 | while ((skb = skb_dequeue(&dch->rqueue))) { | ||
| 30 | if (likely(dch->dev.D.peer)) { | ||
| 31 | err = dch->dev.D.recv(dch->dev.D.peer, skb); | ||
| 32 | if (err) | ||
| 33 | dev_kfree_skb(skb); | ||
| 34 | } else | ||
| 35 | dev_kfree_skb(skb); | ||
| 36 | } | ||
| 37 | } | ||
| 38 | if (test_and_clear_bit(FLG_PHCHANGE, &dch->Flags)) { | ||
| 39 | if (dch->phfunc) | ||
| 40 | dch->phfunc(dch); | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | static void | ||
| 45 | bchannel_bh(struct work_struct *ws) | ||
| 46 | { | ||
| 47 | struct bchannel *bch = container_of(ws, struct bchannel, workq); | ||
| 48 | struct sk_buff *skb; | ||
| 49 | int err; | ||
| 50 | |||
| 51 | if (test_and_clear_bit(FLG_RECVQUEUE, &bch->Flags)) { | ||
| 52 | while ((skb = skb_dequeue(&bch->rqueue))) { | ||
| 53 | if (bch->rcount >= 64) | ||
| 54 | printk(KERN_WARNING "B-channel %p receive " | ||
| 55 | "queue if full, but empties...\n", bch); | ||
| 56 | bch->rcount--; | ||
| 57 | if (likely(bch->ch.peer)) { | ||
| 58 | err = bch->ch.recv(bch->ch.peer, skb); | ||
| 59 | if (err) | ||
| 60 | dev_kfree_skb(skb); | ||
| 61 | } else | ||
| 62 | dev_kfree_skb(skb); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | int | ||
| 68 | mISDN_initdchannel(struct dchannel *ch, int maxlen, void *phf) | ||
| 69 | { | ||
| 70 | test_and_set_bit(FLG_HDLC, &ch->Flags); | ||
| 71 | ch->maxlen = maxlen; | ||
| 72 | ch->hw = NULL; | ||
| 73 | ch->rx_skb = NULL; | ||
| 74 | ch->tx_skb = NULL; | ||
| 75 | ch->tx_idx = 0; | ||
| 76 | ch->phfunc = phf; | ||
| 77 | skb_queue_head_init(&ch->squeue); | ||
| 78 | skb_queue_head_init(&ch->rqueue); | ||
| 79 | INIT_LIST_HEAD(&ch->dev.bchannels); | ||
| 80 | INIT_WORK(&ch->workq, dchannel_bh); | ||
| 81 | return 0; | ||
| 82 | } | ||
| 83 | EXPORT_SYMBOL(mISDN_initdchannel); | ||
| 84 | |||
| 85 | int | ||
| 86 | mISDN_initbchannel(struct bchannel *ch, int maxlen) | ||
| 87 | { | ||
| 88 | ch->Flags = 0; | ||
| 89 | ch->maxlen = maxlen; | ||
| 90 | ch->hw = NULL; | ||
| 91 | ch->rx_skb = NULL; | ||
| 92 | ch->tx_skb = NULL; | ||
| 93 | ch->tx_idx = 0; | ||
| 94 | skb_queue_head_init(&ch->rqueue); | ||
| 95 | ch->rcount = 0; | ||
| 96 | ch->next_skb = NULL; | ||
| 97 | INIT_WORK(&ch->workq, bchannel_bh); | ||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | EXPORT_SYMBOL(mISDN_initbchannel); | ||
| 101 | |||
| 102 | int | ||
| 103 | mISDN_freedchannel(struct dchannel *ch) | ||
| 104 | { | ||
| 105 | if (ch->tx_skb) { | ||
| 106 | dev_kfree_skb(ch->tx_skb); | ||
| 107 | ch->tx_skb = NULL; | ||
| 108 | } | ||
| 109 | if (ch->rx_skb) { | ||
| 110 | dev_kfree_skb(ch->rx_skb); | ||
| 111 | ch->rx_skb = NULL; | ||
| 112 | } | ||
| 113 | skb_queue_purge(&ch->squeue); | ||
| 114 | skb_queue_purge(&ch->rqueue); | ||
| 115 | flush_scheduled_work(); | ||
| 116 | return 0; | ||
| 117 | } | ||
| 118 | EXPORT_SYMBOL(mISDN_freedchannel); | ||
| 119 | |||
| 120 | int | ||
| 121 | mISDN_freebchannel(struct bchannel *ch) | ||
| 122 | { | ||
| 123 | if (ch->tx_skb) { | ||
| 124 | dev_kfree_skb(ch->tx_skb); | ||
| 125 | ch->tx_skb = NULL; | ||
| 126 | } | ||
| 127 | if (ch->rx_skb) { | ||
| 128 | dev_kfree_skb(ch->rx_skb); | ||
| 129 | ch->rx_skb = NULL; | ||
| 130 | } | ||
| 131 | if (ch->next_skb) { | ||
| 132 | dev_kfree_skb(ch->next_skb); | ||
| 133 | ch->next_skb = NULL; | ||
| 134 | } | ||
| 135 | skb_queue_purge(&ch->rqueue); | ||
| 136 | ch->rcount = 0; | ||
| 137 | flush_scheduled_work(); | ||
| 138 | return 0; | ||
| 139 | } | ||
| 140 | EXPORT_SYMBOL(mISDN_freebchannel); | ||
| 141 | |||
| 142 | static inline u_int | ||
| 143 | get_sapi_tei(u_char *p) | ||
| 144 | { | ||
| 145 | u_int sapi, tei; | ||
| 146 | |||
| 147 | sapi = *p >> 2; | ||
| 148 | tei = p[1] >> 1; | ||
| 149 | return sapi | (tei << 8); | ||
| 150 | } | ||
| 151 | |||
| 152 | void | ||
| 153 | recv_Dchannel(struct dchannel *dch) | ||
| 154 | { | ||
| 155 | struct mISDNhead *hh; | ||
| 156 | |||
| 157 | if (dch->rx_skb->len < 2) { /* at least 2 for sapi / tei */ | ||
| 158 | dev_kfree_skb(dch->rx_skb); | ||
| 159 | dch->rx_skb = NULL; | ||
| 160 | return; | ||
| 161 | } | ||
| 162 | hh = mISDN_HEAD_P(dch->rx_skb); | ||
| 163 | hh->prim = PH_DATA_IND; | ||
| 164 | hh->id = get_sapi_tei(dch->rx_skb->data); | ||
| 165 | skb_queue_tail(&dch->rqueue, dch->rx_skb); | ||
| 166 | dch->rx_skb = NULL; | ||
| 167 | schedule_event(dch, FLG_RECVQUEUE); | ||
| 168 | } | ||
| 169 | EXPORT_SYMBOL(recv_Dchannel); | ||
| 170 | |||
| 171 | void | ||
| 172 | recv_Bchannel(struct bchannel *bch) | ||
| 173 | { | ||
| 174 | struct mISDNhead *hh; | ||
| 175 | |||
| 176 | hh = mISDN_HEAD_P(bch->rx_skb); | ||
| 177 | hh->prim = PH_DATA_IND; | ||
| 178 | hh->id = MISDN_ID_ANY; | ||
| 179 | if (bch->rcount >= 64) { | ||
| 180 | dev_kfree_skb(bch->rx_skb); | ||
| 181 | bch->rx_skb = NULL; | ||
| 182 | return; | ||
| 183 | } | ||
| 184 | bch->rcount++; | ||
| 185 | skb_queue_tail(&bch->rqueue, bch->rx_skb); | ||
| 186 | bch->rx_skb = NULL; | ||
| 187 | schedule_event(bch, FLG_RECVQUEUE); | ||
| 188 | } | ||
| 189 | EXPORT_SYMBOL(recv_Bchannel); | ||
| 190 | |||
| 191 | void | ||
| 192 | recv_Dchannel_skb(struct dchannel *dch, struct sk_buff *skb) | ||
| 193 | { | ||
| 194 | skb_queue_tail(&dch->rqueue, skb); | ||
| 195 | schedule_event(dch, FLG_RECVQUEUE); | ||
| 196 | } | ||
| 197 | EXPORT_SYMBOL(recv_Dchannel_skb); | ||
| 198 | |||
| 199 | void | ||
| 200 | recv_Bchannel_skb(struct bchannel *bch, struct sk_buff *skb) | ||
| 201 | { | ||
| 202 | if (bch->rcount >= 64) { | ||
| 203 | dev_kfree_skb(skb); | ||
| 204 | return; | ||
| 205 | } | ||
| 206 | bch->rcount++; | ||
| 207 | skb_queue_tail(&bch->rqueue, skb); | ||
| 208 | schedule_event(bch, FLG_RECVQUEUE); | ||
| 209 | } | ||
| 210 | EXPORT_SYMBOL(recv_Bchannel_skb); | ||
| 211 | |||
| 212 | static void | ||
| 213 | confirm_Dsend(struct dchannel *dch) | ||
| 214 | { | ||
| 215 | struct sk_buff *skb; | ||
| 216 | |||
| 217 | skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(dch->tx_skb), | ||
| 218 | 0, NULL, GFP_ATOMIC); | ||
| 219 | if (!skb) { | ||
| 220 | printk(KERN_ERR "%s: no skb id %x\n", __func__, | ||
| 221 | mISDN_HEAD_ID(dch->tx_skb)); | ||
| 222 | return; | ||
| 223 | } | ||
| 224 | skb_queue_tail(&dch->rqueue, skb); | ||
| 225 | schedule_event(dch, FLG_RECVQUEUE); | ||
| 226 | } | ||
| 227 | |||
| 228 | int | ||
| 229 | get_next_dframe(struct dchannel *dch) | ||
| 230 | { | ||
| 231 | dch->tx_idx = 0; | ||
| 232 | dch->tx_skb = skb_dequeue(&dch->squeue); | ||
| 233 | if (dch->tx_skb) { | ||
| 234 | confirm_Dsend(dch); | ||
| 235 | return 1; | ||
| 236 | } | ||
| 237 | dch->tx_skb = NULL; | ||
| 238 | test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); | ||
| 239 | return 0; | ||
| 240 | } | ||
| 241 | EXPORT_SYMBOL(get_next_dframe); | ||
| 242 | |||
| 243 | void | ||
| 244 | confirm_Bsend(struct bchannel *bch) | ||
| 245 | { | ||
| 246 | struct sk_buff *skb; | ||
| 247 | |||
| 248 | if (bch->rcount >= 64) | ||
| 249 | return; | ||
| 250 | skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(bch->tx_skb), | ||
| 251 | 0, NULL, GFP_ATOMIC); | ||
| 252 | if (!skb) { | ||
| 253 | printk(KERN_ERR "%s: no skb id %x\n", __func__, | ||
| 254 | mISDN_HEAD_ID(bch->tx_skb)); | ||
| 255 | return; | ||
| 256 | } | ||
| 257 | bch->rcount++; | ||
| 258 | skb_queue_tail(&bch->rqueue, skb); | ||
| 259 | schedule_event(bch, FLG_RECVQUEUE); | ||
| 260 | } | ||
| 261 | EXPORT_SYMBOL(confirm_Bsend); | ||
| 262 | |||
| 263 | int | ||
| 264 | get_next_bframe(struct bchannel *bch) | ||
| 265 | { | ||
| 266 | bch->tx_idx = 0; | ||
| 267 | if (test_bit(FLG_TX_NEXT, &bch->Flags)) { | ||
| 268 | bch->tx_skb = bch->next_skb; | ||
| 269 | if (bch->tx_skb) { | ||
| 270 | bch->next_skb = NULL; | ||
| 271 | test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); | ||
| 272 | if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) | ||
| 273 | confirm_Bsend(bch); /* not for transparent */ | ||
| 274 | return 1; | ||
| 275 | } else { | ||
| 276 | test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); | ||
| 277 | printk(KERN_WARNING "B TX_NEXT without skb\n"); | ||
| 278 | } | ||
| 279 | } | ||
| 280 | bch->tx_skb = NULL; | ||
| 281 | test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); | ||
| 282 | return 0; | ||
| 283 | } | ||
| 284 | EXPORT_SYMBOL(get_next_bframe); | ||
| 285 | |||
| 286 | void | ||
| 287 | queue_ch_frame(struct mISDNchannel *ch, u_int pr, int id, struct sk_buff *skb) | ||
| 288 | { | ||
| 289 | struct mISDNhead *hh; | ||
| 290 | |||
| 291 | if (!skb) { | ||
| 292 | _queue_data(ch, pr, id, 0, NULL, GFP_ATOMIC); | ||
| 293 | } else { | ||
| 294 | if (ch->peer) { | ||
| 295 | hh = mISDN_HEAD_P(skb); | ||
| 296 | hh->prim = pr; | ||
| 297 | hh->id = id; | ||
| 298 | if (!ch->recv(ch->peer, skb)) | ||
| 299 | return; | ||
| 300 | } | ||
| 301 | dev_kfree_skb(skb); | ||
| 302 | } | ||
| 303 | } | ||
| 304 | EXPORT_SYMBOL(queue_ch_frame); | ||
| 305 | |||
| 306 | int | ||
| 307 | dchannel_senddata(struct dchannel *ch, struct sk_buff *skb) | ||
| 308 | { | ||
| 309 | /* check oversize */ | ||
| 310 | if (skb->len <= 0) { | ||
| 311 | printk(KERN_WARNING "%s: skb too small\n", __func__); | ||
| 312 | return -EINVAL; | ||
| 313 | } | ||
| 314 | if (skb->len > ch->maxlen) { | ||
| 315 | printk(KERN_WARNING "%s: skb too large(%d/%d)\n", | ||
| 316 | __func__, skb->len, ch->maxlen); | ||
| 317 | return -EINVAL; | ||
| 318 | } | ||
| 319 | /* HW lock must be obtained */ | ||
| 320 | if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) { | ||
| 321 | skb_queue_tail(&ch->squeue, skb); | ||
| 322 | return 0; | ||
| 323 | } else { | ||
| 324 | /* write to fifo */ | ||
| 325 | ch->tx_skb = skb; | ||
| 326 | ch->tx_idx = 0; | ||
| 327 | return 1; | ||
| 328 | } | ||
| 329 | } | ||
| 330 | EXPORT_SYMBOL(dchannel_senddata); | ||
| 331 | |||
| 332 | int | ||
| 333 | bchannel_senddata(struct bchannel *ch, struct sk_buff *skb) | ||
| 334 | { | ||
| 335 | |||
| 336 | /* check oversize */ | ||
| 337 | if (skb->len <= 0) { | ||
| 338 | printk(KERN_WARNING "%s: skb too small\n", __func__); | ||
| 339 | return -EINVAL; | ||
| 340 | } | ||
| 341 | if (skb->len > ch->maxlen) { | ||
| 342 | printk(KERN_WARNING "%s: skb too large(%d/%d)\n", | ||
| 343 | __func__, skb->len, ch->maxlen); | ||
| 344 | return -EINVAL; | ||
| 345 | } | ||
| 346 | /* HW lock must be obtained */ | ||
| 347 | /* check for pending next_skb */ | ||
| 348 | if (ch->next_skb) { | ||
| 349 | printk(KERN_WARNING | ||
| 350 | "%s: next_skb exist ERROR (skb->len=%d next_skb->len=%d)\n", | ||
| 351 | __func__, skb->len, ch->next_skb->len); | ||
| 352 | return -EBUSY; | ||
| 353 | } | ||
| 354 | if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) { | ||
| 355 | test_and_set_bit(FLG_TX_NEXT, &ch->Flags); | ||
| 356 | ch->next_skb = skb; | ||
| 357 | return 0; | ||
| 358 | } else { | ||
| 359 | /* write to fifo */ | ||
| 360 | ch->tx_skb = skb; | ||
| 361 | ch->tx_idx = 0; | ||
| 362 | return 1; | ||
| 363 | } | ||
| 364 | } | ||
| 365 | EXPORT_SYMBOL(bchannel_senddata); | ||
diff --git a/drivers/isdn/mISDN/l1oip.h b/drivers/isdn/mISDN/l1oip.h new file mode 100644 index 000000000000..a23d575449f6 --- /dev/null +++ b/drivers/isdn/mISDN/l1oip.h | |||
| @@ -0,0 +1,91 @@ | |||
| 1 | /* | ||
| 2 | * see notice in l1oip.c | ||
| 3 | */ | ||
| 4 | |||
| 5 | /* debugging */ | ||
| 6 | #define DEBUG_L1OIP_INIT 0x00010000 | ||
| 7 | #define DEBUG_L1OIP_SOCKET 0x00020000 | ||
| 8 | #define DEBUG_L1OIP_MGR 0x00040000 | ||
| 9 | #define DEBUG_L1OIP_MSG 0x00080000 | ||
| 10 | |||
| 11 | /* enable to disorder received bchannels by sequence 2143658798... */ | ||
| 12 | /* | ||
| 13 | #define REORDER_DEBUG | ||
| 14 | */ | ||
| 15 | |||
| 16 | /* frames */ | ||
| 17 | #define L1OIP_MAX_LEN 2048 /* max packet size form l2 */ | ||
| 18 | #define L1OIP_MAX_PERFRAME 1400 /* max data size in one frame */ | ||
| 19 | |||
| 20 | |||
| 21 | /* timers */ | ||
| 22 | #define L1OIP_KEEPALIVE 15 | ||
| 23 | #define L1OIP_TIMEOUT 65 | ||
| 24 | |||
| 25 | |||
| 26 | /* socket */ | ||
| 27 | #define L1OIP_DEFAULTPORT 931 | ||
| 28 | |||
| 29 | |||
| 30 | /* channel structure */ | ||
| 31 | struct l1oip_chan { | ||
| 32 | struct dchannel *dch; | ||
| 33 | struct bchannel *bch; | ||
| 34 | u32 tx_counter; /* counts xmit bytes/packets */ | ||
| 35 | u32 rx_counter; /* counts recv bytes/packets */ | ||
| 36 | u32 codecstate; /* used by codec to save data */ | ||
| 37 | #ifdef REORDER_DEBUG | ||
| 38 | int disorder_flag; | ||
| 39 | struct sk_buff *disorder_skb; | ||
| 40 | u32 disorder_cnt; | ||
| 41 | #endif | ||
| 42 | }; | ||
| 43 | |||
| 44 | |||
| 45 | /* card structure */ | ||
| 46 | struct l1oip { | ||
| 47 | struct list_head list; | ||
| 48 | |||
| 49 | /* card */ | ||
| 50 | int registered; /* if registered with mISDN */ | ||
| 51 | char name[MISDN_MAX_IDLEN]; | ||
| 52 | int idx; /* card index */ | ||
| 53 | int pri; /* 1=pri, 0=bri */ | ||
| 54 | int d_idx; /* current dchannel number */ | ||
| 55 | int b_num; /* number of bchannels */ | ||
| 56 | u32 id; /* id of connection */ | ||
| 57 | int ondemand; /* if transmis. is on demand */ | ||
| 58 | int bundle; /* bundle channels in one frm */ | ||
| 59 | int codec; /* codec to use for transmis. */ | ||
| 60 | int limit; /* limit number of bchannels */ | ||
| 61 | |||
| 62 | /* timer */ | ||
| 63 | struct timer_list keep_tl; | ||
| 64 | struct timer_list timeout_tl; | ||
| 65 | int timeout_on; | ||
| 66 | struct work_struct workq; | ||
| 67 | |||
| 68 | /* socket */ | ||
| 69 | struct socket *socket; /* if set, socket is created */ | ||
| 70 | struct completion socket_complete;/* completion of sock thread */ | ||
| 71 | struct task_struct *socket_thread; | ||
| 72 | spinlock_t socket_lock; /* access sock outside thread */ | ||
| 73 | u32 remoteip; /* if all set, ip is assigned */ | ||
| 74 | u16 localport; /* must always be set */ | ||
| 75 | u16 remoteport; /* must always be set */ | ||
| 76 | struct sockaddr_in sin_local; /* local socket name */ | ||
| 77 | struct sockaddr_in sin_remote; /* remote socket name */ | ||
| 78 | struct msghdr sendmsg; /* ip message to send */ | ||
| 79 | struct iovec sendiov; /* iov for message */ | ||
| 80 | |||
| 81 | /* frame */ | ||
| 82 | struct l1oip_chan chan[128]; /* channel instances */ | ||
| 83 | }; | ||
| 84 | |||
| 85 | extern int l1oip_law_to_4bit(u8 *data, int len, u8 *result, u32 *state); | ||
| 86 | extern int l1oip_4bit_to_law(u8 *data, int len, u8 *result); | ||
| 87 | extern int l1oip_alaw_to_ulaw(u8 *data, int len, u8 *result); | ||
| 88 | extern int l1oip_ulaw_to_alaw(u8 *data, int len, u8 *result); | ||
| 89 | extern void l1oip_4bit_free(void); | ||
| 90 | extern int l1oip_4bit_alloc(int ulaw); | ||
| 91 | |||
diff --git a/drivers/isdn/mISDN/l1oip_codec.c b/drivers/isdn/mISDN/l1oip_codec.c new file mode 100644 index 000000000000..a2dc4570ef43 --- /dev/null +++ b/drivers/isdn/mISDN/l1oip_codec.c | |||
| @@ -0,0 +1,374 @@ | |||
| 1 | /* | ||
| 2 | |||
| 3 | * l1oip_codec.c generic codec using lookup table | ||
| 4 | * -> conversion from a-Law to u-Law | ||
| 5 | * -> conversion from u-Law to a-Law | ||
| 6 | * -> compression by reducing the number of sample resolution to 4 | ||
| 7 | * | ||
| 8 | * NOTE: It is not compatible with any standard codec like ADPCM. | ||
| 9 | * | ||
| 10 | * Author Andreas Eversberg (jolly@eversberg.eu) | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License as published by | ||
| 14 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 15 | * any later version. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU General Public License for more details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU General Public License | ||
| 23 | * along with this program; if not, write to the Free Software | ||
| 24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 25 | |||
| 26 | */ | ||
| 27 | |||
| 28 | /* | ||
| 29 | |||
| 30 | How the codec works: | ||
| 31 | -------------------- | ||
| 32 | |||
| 33 | The volume is increased to increase the dynamic range of the audio signal. | ||
| 34 | Each sample is converted to a-LAW with only 16 steps of level resolution. | ||
| 35 | A pair of two samples are stored in one byte. | ||
| 36 | |||
| 37 | The first byte is stored in the upper bits, the second byte is stored in the | ||
| 38 | lower bits. | ||
| 39 | |||
| 40 | To speed up compression and decompression, two lookup tables are formed: | ||
| 41 | |||
| 42 | - 16 bits index for two samples (law encoded) with 8 bit compressed result. | ||
| 43 | - 8 bits index for one compressed data with 16 bits decompressed result. | ||
| 44 | |||
| 45 | NOTE: The bytes are handled as they are law-encoded. | ||
| 46 | |||
| 47 | */ | ||
| 48 | |||
| 49 | #include <linux/vmalloc.h> | ||
| 50 | #include <linux/mISDNif.h> | ||
| 51 | #include "core.h" | ||
| 52 | |||
| 53 | /* definitions of codec. don't use calculations, code may run slower. */ | ||
| 54 | |||
| 55 | static u8 *table_com; | ||
| 56 | static u16 *table_dec; | ||
| 57 | |||
| 58 | |||
| 59 | /* alaw -> ulaw */ | ||
| 60 | static u8 alaw_to_ulaw[256] = | ||
| 61 | { | ||
| 62 | 0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49, | ||
| 63 | 0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57, | ||
| 64 | 0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41, | ||
| 65 | 0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f, | ||
| 66 | 0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d, | ||
| 67 | 0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b, | ||
| 68 | 0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45, | ||
| 69 | 0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53, | ||
| 70 | 0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47, | ||
| 71 | 0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55, | ||
| 72 | 0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f, | ||
| 73 | 0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e, | ||
| 74 | 0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b, | ||
| 75 | 0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59, | ||
| 76 | 0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43, | ||
| 77 | 0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51, | ||
| 78 | 0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a, | ||
| 79 | 0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58, | ||
| 80 | 0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42, | ||
| 81 | 0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50, | ||
| 82 | 0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e, | ||
| 83 | 0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c, | ||
| 84 | 0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46, | ||
| 85 | 0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54, | ||
| 86 | 0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48, | ||
| 87 | 0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56, | ||
| 88 | 0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40, | ||
| 89 | 0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f, | ||
| 90 | 0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c, | ||
| 91 | 0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a, | ||
| 92 | 0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44, | ||
| 93 | 0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52 | ||
| 94 | }; | ||
| 95 | |||
| 96 | /* ulaw -> alaw */ | ||
| 97 | static u8 ulaw_to_alaw[256] = | ||
| 98 | { | ||
| 99 | 0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35, | ||
| 100 | 0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25, | ||
| 101 | 0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d, | ||
| 102 | 0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d, | ||
| 103 | 0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31, | ||
| 104 | 0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21, | ||
| 105 | 0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9, | ||
| 106 | 0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9, | ||
| 107 | 0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47, | ||
| 108 | 0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf, | ||
| 109 | 0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f, | ||
| 110 | 0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33, | ||
| 111 | 0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23, | ||
| 112 | 0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b, | ||
| 113 | 0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b, | ||
| 114 | 0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b, | ||
| 115 | 0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34, | ||
| 116 | 0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24, | ||
| 117 | 0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c, | ||
| 118 | 0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c, | ||
| 119 | 0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30, | ||
| 120 | 0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20, | ||
| 121 | 0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8, | ||
| 122 | 0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8, | ||
| 123 | 0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46, | ||
| 124 | 0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde, | ||
| 125 | 0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e, | ||
| 126 | 0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32, | ||
| 127 | 0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22, | ||
| 128 | 0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a, | ||
| 129 | 0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a, | ||
| 130 | 0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a | ||
| 131 | }; | ||
| 132 | |||
| 133 | /* alaw -> 4bit compression */ | ||
| 134 | static u8 alaw_to_4bit[256] = { | ||
| 135 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
| 136 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
| 137 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
| 138 | 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
| 139 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
| 140 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
| 141 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
| 142 | 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
| 143 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
| 144 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
| 145 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0d, 0x02, | ||
| 146 | 0x0e, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
| 147 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
| 148 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
| 149 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
| 150 | 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
| 151 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
| 152 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
| 153 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
| 154 | 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
| 155 | 0x0e, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
| 156 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x01, 0x0a, 0x05, | ||
| 157 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
| 158 | 0x0d, 0x02, 0x09, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
| 159 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
| 160 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
| 161 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
| 162 | 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
| 163 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
| 164 | 0x0d, 0x02, 0x08, 0x07, 0x0f, 0x00, 0x0b, 0x04, | ||
| 165 | 0x0e, 0x01, 0x0a, 0x05, 0x0f, 0x00, 0x0c, 0x03, | ||
| 166 | 0x0d, 0x02, 0x09, 0x06, 0x0f, 0x00, 0x0b, 0x04, | ||
| 167 | }; | ||
| 168 | |||
| 169 | /* 4bit -> alaw decompression */ | ||
| 170 | static u8 _4bit_to_alaw[16] = { | ||
| 171 | 0x5d, 0x51, 0xd9, 0xd7, 0x5f, 0x53, 0xa3, 0x4b, | ||
| 172 | 0x2a, 0x3a, 0x22, 0x2e, 0x26, 0x56, 0x20, 0x2c, | ||
| 173 | }; | ||
| 174 | |||
| 175 | /* ulaw -> 4bit compression */ | ||
| 176 | static u8 ulaw_to_4bit[256] = { | ||
| 177 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 178 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 179 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 180 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 181 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||
| 182 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||
| 183 | 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, | ||
| 184 | 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, | ||
| 185 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, | ||
| 186 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, | ||
| 187 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, | ||
| 188 | 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, | ||
| 189 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, | ||
| 190 | 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, | ||
| 191 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, | ||
| 192 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, | ||
| 193 | 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, | ||
| 194 | 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, | ||
| 195 | 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, | ||
| 196 | 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, | ||
| 197 | 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, | ||
| 198 | 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, | ||
| 199 | 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, | ||
| 200 | 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, | ||
| 201 | 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, | ||
| 202 | 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, | ||
| 203 | 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, | ||
| 204 | 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, | ||
| 205 | 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, | ||
| 206 | 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, | ||
| 207 | 0x09, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, | ||
| 208 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, | ||
| 209 | }; | ||
| 210 | |||
| 211 | /* 4bit -> ulaw decompression */ | ||
| 212 | static u8 _4bit_to_ulaw[16] = { | ||
| 213 | 0x11, 0x21, 0x31, 0x40, 0x4e, 0x5c, 0x68, 0x71, | ||
| 214 | 0xfe, 0xef, 0xe7, 0xdb, 0xcd, 0xbf, 0xaf, 0x9f, | ||
| 215 | }; | ||
| 216 | |||
| 217 | |||
| 218 | /* | ||
| 219 | * Compresses data to the result buffer | ||
| 220 | * The result size must be at least half of the input buffer. | ||
| 221 | * The number of samples also must be even! | ||
| 222 | */ | ||
| 223 | int | ||
| 224 | l1oip_law_to_4bit(u8 *data, int len, u8 *result, u32 *state) | ||
| 225 | { | ||
| 226 | int ii, i = 0, o = 0; | ||
| 227 | |||
| 228 | if (!len) | ||
| 229 | return 0; | ||
| 230 | |||
| 231 | /* send saved byte and first input byte */ | ||
| 232 | if (*state) { | ||
| 233 | *result++ = table_com[(((*state)<<8)&0xff00) | (*data++)]; | ||
| 234 | len--; | ||
| 235 | o++; | ||
| 236 | } | ||
| 237 | |||
| 238 | ii = len >> 1; | ||
| 239 | |||
| 240 | while (i < ii) { | ||
| 241 | *result++ = table_com[(data[0]<<8) | (data[1])]; | ||
| 242 | data += 2; | ||
| 243 | i++; | ||
| 244 | o++; | ||
| 245 | } | ||
| 246 | |||
| 247 | /* if len has an odd number, we save byte for next call */ | ||
| 248 | if (len & 1) | ||
| 249 | *state = 0x100 + *data; | ||
| 250 | else | ||
| 251 | *state = 0; | ||
| 252 | |||
| 253 | return o; | ||
| 254 | } | ||
| 255 | |||
| 256 | /* Decompress data to the result buffer | ||
| 257 | * The result size must be the number of sample in packet. (2 * input data) | ||
| 258 | * The number of samples in the result are even! | ||
| 259 | */ | ||
| 260 | int | ||
| 261 | l1oip_4bit_to_law(u8 *data, int len, u8 *result) | ||
| 262 | { | ||
| 263 | int i = 0; | ||
| 264 | u16 r; | ||
| 265 | |||
| 266 | while (i < len) { | ||
| 267 | r = table_dec[*data++]; | ||
| 268 | *result++ = r>>8; | ||
| 269 | *result++ = r; | ||
| 270 | i++; | ||
| 271 | } | ||
| 272 | |||
| 273 | return len << 1; | ||
| 274 | } | ||
| 275 | |||
| 276 | |||
| 277 | /* | ||
| 278 | * law conversion | ||
| 279 | */ | ||
| 280 | int | ||
| 281 | l1oip_alaw_to_ulaw(u8 *data, int len, u8 *result) | ||
| 282 | { | ||
| 283 | int i = 0; | ||
| 284 | |||
| 285 | while (i < len) { | ||
| 286 | *result++ = alaw_to_ulaw[*data++]; | ||
| 287 | i++; | ||
| 288 | } | ||
| 289 | |||
| 290 | return len; | ||
| 291 | } | ||
| 292 | |||
| 293 | int | ||
| 294 | l1oip_ulaw_to_alaw(u8 *data, int len, u8 *result) | ||
| 295 | { | ||
| 296 | int i = 0; | ||
| 297 | |||
| 298 | while (i < len) { | ||
| 299 | *result++ = ulaw_to_alaw[*data++]; | ||
| 300 | i++; | ||
| 301 | } | ||
| 302 | |||
| 303 | return len; | ||
| 304 | } | ||
| 305 | |||
| 306 | |||
| 307 | /* | ||
| 308 | * generate/free compression and decompression table | ||
| 309 | */ | ||
| 310 | void | ||
| 311 | l1oip_4bit_free(void) | ||
| 312 | { | ||
| 313 | if (table_dec) | ||
| 314 | vfree(table_dec); | ||
| 315 | if (table_com) | ||
| 316 | vfree(table_com); | ||
| 317 | table_com = NULL; | ||
| 318 | table_dec = NULL; | ||
| 319 | } | ||
| 320 | |||
| 321 | int | ||
| 322 | l1oip_4bit_alloc(int ulaw) | ||
| 323 | { | ||
| 324 | int i1, i2, c, sample; | ||
| 325 | |||
| 326 | /* in case, it is called again */ | ||
| 327 | if (table_dec) | ||
| 328 | return 0; | ||
| 329 | |||
| 330 | /* alloc conversion tables */ | ||
| 331 | table_com = vmalloc(65536); | ||
| 332 | table_dec = vmalloc(512); | ||
| 333 | if (!table_com | !table_dec) { | ||
| 334 | l1oip_4bit_free(); | ||
| 335 | return -ENOMEM; | ||
| 336 | } | ||
| 337 | memset(table_com, 0, 65536); | ||
| 338 | memset(table_dec, 0, 512); | ||
| 339 | /* generate compression table */ | ||
| 340 | i1 = 0; | ||
| 341 | while (i1 < 256) { | ||
| 342 | if (ulaw) | ||
| 343 | c = ulaw_to_4bit[i1]; | ||
| 344 | else | ||
| 345 | c = alaw_to_4bit[i1]; | ||
| 346 | i2 = 0; | ||
| 347 | while (i2 < 256) { | ||
| 348 | table_com[(i1<<8) | i2] |= (c<<4); | ||
| 349 | table_com[(i2<<8) | i1] |= c; | ||
| 350 | i2++; | ||
| 351 | } | ||
| 352 | i1++; | ||
| 353 | } | ||
| 354 | |||
| 355 | /* generate decompression table */ | ||
| 356 | i1 = 0; | ||
| 357 | while (i1 < 16) { | ||
| 358 | if (ulaw) | ||
| 359 | sample = _4bit_to_ulaw[i1]; | ||
| 360 | else | ||
| 361 | sample = _4bit_to_alaw[i1]; | ||
| 362 | i2 = 0; | ||
| 363 | while (i2 < 16) { | ||
| 364 | table_dec[(i1<<4) | i2] |= (sample<<8); | ||
| 365 | table_dec[(i2<<4) | i1] |= sample; | ||
| 366 | i2++; | ||
| 367 | } | ||
| 368 | i1++; | ||
| 369 | } | ||
| 370 | |||
| 371 | return 0; | ||
| 372 | } | ||
| 373 | |||
| 374 | |||
diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c new file mode 100644 index 000000000000..155b99780c4f --- /dev/null +++ b/drivers/isdn/mISDN/l1oip_core.c | |||
| @@ -0,0 +1,1518 @@ | |||
| 1 | /* | ||
| 2 | |||
| 3 | * l1oip.c low level driver for tunneling layer 1 over IP | ||
| 4 | * | ||
| 5 | * NOTE: It is not compatible with TDMoIP nor "ISDN over IP". | ||
| 6 | * | ||
| 7 | * Author Andreas Eversberg (jolly@eversberg.eu) | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 12 | * any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 22 | * | ||
| 23 | */ | ||
| 24 | |||
| 25 | /* module parameters: | ||
| 26 | * type: | ||
| 27 | Value 1 = BRI | ||
| 28 | Value 2 = PRI | ||
| 29 | Value 3 = BRI (multi channel frame, not supported yet) | ||
| 30 | Value 4 = PRI (multi channel frame, not supported yet) | ||
| 31 | A multi channel frame reduces overhead to a single frame for all | ||
| 32 | b-channels, but increases delay. | ||
| 33 | (NOTE: Multi channel frames are not implemented yet.) | ||
| 34 | |||
| 35 | * codec: | ||
| 36 | Value 0 = transparent (default) | ||
| 37 | Value 1 = transfer ALAW | ||
| 38 | Value 2 = transfer ULAW | ||
| 39 | Value 3 = transfer generic 4 bit compression. | ||
| 40 | |||
| 41 | * ulaw: | ||
| 42 | 0 = we use a-Law (default) | ||
| 43 | 1 = we use u-Law | ||
| 44 | |||
| 45 | * limit: | ||
| 46 | limitation of B-channels to control bandwidth (1...126) | ||
| 47 | BRI: 1 or 2 | ||
| 48 | PRI: 1-30, 31-126 (126, because dchannel ist not counted here) | ||
| 49 | Also limited ressources are used for stack, resulting in less channels. | ||
| 50 | It is possible to have more channels than 30 in PRI mode, this must | ||
| 51 | be supported by the application. | ||
| 52 | |||
| 53 | * ip: | ||
| 54 | byte representation of remote ip address (127.0.0.1 -> 127,0,0,1) | ||
| 55 | If not given or four 0, no remote address is set. | ||
| 56 | For multiple interfaces, concat ip addresses. (127,0,0,1,127,0,0,1) | ||
| 57 | |||
| 58 | * port: | ||
| 59 | port number (local interface) | ||
| 60 | If not given or 0, port 931 is used for fist instance, 932 for next... | ||
| 61 | For multiple interfaces, different ports must be given. | ||
| 62 | |||
| 63 | * remoteport: | ||
| 64 | port number (remote interface) | ||
| 65 | If not given or 0, remote port equals local port | ||
| 66 | For multiple interfaces on equal sites, different ports must be given. | ||
| 67 | |||
| 68 | * ondemand: | ||
| 69 | 0 = fixed (always transmit packets, even when remote side timed out) | ||
| 70 | 1 = on demand (only transmit packets, when remote side is detected) | ||
| 71 | the default is 0 | ||
| 72 | NOTE: ID must also be set for on demand. | ||
| 73 | |||
| 74 | * id: | ||
| 75 | optional value to identify frames. This value must be equal on both | ||
| 76 | peers and should be random. If omitted or 0, no ID is transmitted. | ||
| 77 | |||
| 78 | * debug: | ||
| 79 | NOTE: only one debug value must be given for all cards | ||
| 80 | enable debugging (see l1oip.h for debug options) | ||
| 81 | |||
| 82 | |||
| 83 | Special mISDN controls: | ||
| 84 | |||
| 85 | op = MISDN_CTRL_SETPEER* | ||
| 86 | p1 = bytes 0-3 : remote IP address in network order (left element first) | ||
| 87 | p2 = bytes 1-2 : remote port in network order (high byte first) | ||
| 88 | optional: | ||
| 89 | p2 = bytes 3-4 : local port in network order (high byte first) | ||
| 90 | |||
| 91 | op = MISDN_CTRL_UNSETPEER* | ||
| 92 | |||
| 93 | * Use l1oipctrl for comfortable setting or removing ip address. | ||
| 94 | (Layer 1 Over IP CTRL) | ||
| 95 | |||
| 96 | |||
| 97 | L1oIP-Protocol | ||
| 98 | -------------- | ||
| 99 | |||
| 100 | Frame Header: | ||
| 101 | |||
| 102 | 7 6 5 4 3 2 1 0 | ||
| 103 | +---------------+ | ||
| 104 | |Ver|T|I|Coding | | ||
| 105 | +---------------+ | ||
| 106 | | ID byte 3 * | | ||
| 107 | +---------------+ | ||
| 108 | | ID byte 2 * | | ||
| 109 | +---------------+ | ||
| 110 | | ID byte 1 * | | ||
| 111 | +---------------+ | ||
| 112 | | ID byte 0 * | | ||
| 113 | +---------------+ | ||
| 114 | |M| Channel | | ||
| 115 | +---------------+ | ||
| 116 | | Length * | | ||
| 117 | +---------------+ | ||
| 118 | | Time Base MSB | | ||
| 119 | +---------------+ | ||
| 120 | | Time Base LSB | | ||
| 121 | +---------------+ | ||
| 122 | | Data.... | | ||
| 123 | |||
| 124 | ... | ||
| 125 | |||
| 126 | | | | ||
| 127 | +---------------+ | ||
| 128 | |M| Channel | | ||
| 129 | +---------------+ | ||
| 130 | | Length * | | ||
| 131 | +---------------+ | ||
| 132 | | Time Base MSB | | ||
| 133 | +---------------+ | ||
| 134 | | Time Base LSB | | ||
| 135 | +---------------+ | ||
| 136 | | Data.... | | ||
| 137 | |||
| 138 | ... | ||
| 139 | |||
| 140 | |||
| 141 | * Only included in some cases. | ||
| 142 | |||
| 143 | - Ver = Version | ||
| 144 | If version is missmatch, the frame must be ignored. | ||
| 145 | |||
| 146 | - T = Type of interface | ||
| 147 | Must be 0 for S0 or 1 for E1. | ||
| 148 | |||
| 149 | - I = Id present | ||
| 150 | If bit is set, four ID bytes are included in frame. | ||
| 151 | |||
| 152 | - ID = Connection ID | ||
| 153 | Additional ID to prevent Denial of Service attacs. Also it prevents hijacking | ||
| 154 | connections with dynamic IP. The ID should be random and must not be 0. | ||
| 155 | |||
| 156 | - Coding = Type of codec | ||
| 157 | Must be 0 for no transcoding. Also for D-channel and other HDLC frames. | ||
| 158 | 1 and 2 are reserved for explicitly use of a-LAW or u-LAW codec. | ||
| 159 | 3 is used for generic table compressor. | ||
| 160 | |||
| 161 | - M = More channels to come. If this flag is 1, the following byte contains | ||
| 162 | the length of the channel data. After the data block, the next channel will | ||
| 163 | be defined. The flag for the last channel block (or if only one channel is | ||
| 164 | transmitted), must be 0 and no length is given. | ||
| 165 | |||
| 166 | - Channel = Channel number | ||
| 167 | 0 reserved | ||
| 168 | 1-3 channel data for S0 (3 is D-channel) | ||
| 169 | 1-31 channel data for E1 (16 is D-channel) | ||
| 170 | 32-127 channel data for extended E1 (16 is D-channel) | ||
| 171 | |||
| 172 | - The length is used if the M-flag is 1. It is used to find the next channel | ||
| 173 | inside frame. | ||
| 174 | NOTE: A value of 0 equals 256 bytes of data. | ||
| 175 | -> For larger data blocks, a single frame must be used. | ||
| 176 | -> For larger streams, a single frame or multiple blocks with same channel ID | ||
| 177 | must be used. | ||
| 178 | |||
| 179 | - Time Base = Timestamp of first sample in frame | ||
| 180 | The "Time Base" is used to rearange packets and to detect packet loss. | ||
| 181 | The 16 bits are sent in network order (MSB first) and count 1/8000 th of a | ||
| 182 | second. This causes a wrap arround each 8,192 seconds. There is no requirement | ||
| 183 | for the initial "Time Base", but 0 should be used for the first packet. | ||
| 184 | In case of HDLC data, this timestamp counts the packet or byte number. | ||
| 185 | |||
| 186 | |||
| 187 | Two Timers: | ||
| 188 | |||
| 189 | After initialisation, a timer of 15 seconds is started. Whenever a packet is | ||
| 190 | transmitted, the timer is reset to 15 seconds again. If the timer expires, an | ||
| 191 | empty packet is transmitted. This keep the connection alive. | ||
| 192 | |||
| 193 | When a valid packet is received, a timer 65 seconds is started. The interface | ||
| 194 | become ACTIVE. If the timer expires, the interface becomes INACTIVE. | ||
| 195 | |||
| 196 | |||
| 197 | Dynamic IP handling: | ||
| 198 | |||
| 199 | To allow dynamic IP, the ID must be non 0. In this case, any packet with the | ||
| 200 | correct port number and ID will be accepted. If the remote side changes its IP | ||
| 201 | the new IP is used for all transmitted packets until it changes again. | ||
| 202 | |||
| 203 | |||
| 204 | On Demand: | ||
| 205 | |||
| 206 | If the ondemand parameter is given, the remote IP is set to 0 on timeout. | ||
| 207 | This will stop keepalive traffic to remote. If the remote is online again, | ||
| 208 | traffic will continue to the remote address. This is usefull for road warriors. | ||
| 209 | This feature only works with ID set, otherwhise it is highly unsecure. | ||
| 210 | |||
| 211 | |||
| 212 | Socket and Thread | ||
| 213 | ----------------- | ||
| 214 | |||
| 215 | The complete socket opening and closing is done by a thread. | ||
| 216 | When the thread opened a socket, the hc->socket descriptor is set. Whenever a | ||
| 217 | packet shall be sent to the socket, the hc->socket must be checked wheter not | ||
| 218 | NULL. To prevent change in socket descriptor, the hc->socket_lock must be used. | ||
| 219 | To change the socket, a recall of l1oip_socket_open() will safely kill the | ||
| 220 | socket process and create a new one. | ||
| 221 | |||
| 222 | */ | ||
| 223 | |||
| 224 | #define L1OIP_VERSION 0 /* 0...3 */ | ||
| 225 | |||
| 226 | #include <linux/module.h> | ||
| 227 | #include <linux/delay.h> | ||
| 228 | #include <linux/mISDNif.h> | ||
| 229 | #include <linux/mISDNhw.h> | ||
| 230 | #include <linux/mISDNdsp.h> | ||
| 231 | #include <linux/init.h> | ||
| 232 | #include <linux/in.h> | ||
| 233 | #include <linux/inet.h> | ||
| 234 | #include <linux/workqueue.h> | ||
| 235 | #include <linux/kthread.h> | ||
| 236 | #include <net/sock.h> | ||
| 237 | #include "core.h" | ||
| 238 | #include "l1oip.h" | ||
| 239 | |||
| 240 | static const char *l1oip_revision = "2.00"; | ||
| 241 | |||
| 242 | static int l1oip_cnt; | ||
| 243 | static spinlock_t l1oip_lock; | ||
| 244 | static struct list_head l1oip_ilist; | ||
| 245 | |||
| 246 | #define MAX_CARDS 16 | ||
| 247 | static u_int type[MAX_CARDS]; | ||
| 248 | static u_int codec[MAX_CARDS]; | ||
| 249 | static u_int ip[MAX_CARDS*4]; | ||
| 250 | static u_int port[MAX_CARDS]; | ||
| 251 | static u_int remoteport[MAX_CARDS]; | ||
| 252 | static u_int ondemand[MAX_CARDS]; | ||
| 253 | static u_int limit[MAX_CARDS]; | ||
| 254 | static u_int id[MAX_CARDS]; | ||
| 255 | static int debug; | ||
| 256 | static int ulaw; | ||
| 257 | |||
| 258 | MODULE_AUTHOR("Andreas Eversberg"); | ||
| 259 | MODULE_LICENSE("GPL"); | ||
| 260 | module_param_array(type, uint, NULL, S_IRUGO | S_IWUSR); | ||
| 261 | module_param_array(codec, uint, NULL, S_IRUGO | S_IWUSR); | ||
| 262 | module_param_array(ip, uint, NULL, S_IRUGO | S_IWUSR); | ||
| 263 | module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR); | ||
| 264 | module_param_array(remoteport, uint, NULL, S_IRUGO | S_IWUSR); | ||
| 265 | module_param_array(ondemand, uint, NULL, S_IRUGO | S_IWUSR); | ||
| 266 | module_param_array(limit, uint, NULL, S_IRUGO | S_IWUSR); | ||
| 267 | module_param_array(id, uint, NULL, S_IRUGO | S_IWUSR); | ||
| 268 | module_param(ulaw, uint, S_IRUGO | S_IWUSR); | ||
| 269 | module_param(debug, uint, S_IRUGO | S_IWUSR); | ||
| 270 | |||
| 271 | /* | ||
| 272 | * send a frame via socket, if open and restart timer | ||
| 273 | */ | ||
| 274 | static int | ||
| 275 | l1oip_socket_send(struct l1oip *hc, u8 localcodec, u8 channel, u32 chanmask, | ||
| 276 | u16 timebase, u8 *buf, int len) | ||
| 277 | { | ||
| 278 | u8 *p; | ||
| 279 | int multi = 0; | ||
| 280 | u8 frame[len+32]; | ||
| 281 | struct socket *socket = NULL; | ||
| 282 | mm_segment_t oldfs; | ||
| 283 | |||
| 284 | if (debug & DEBUG_L1OIP_MSG) | ||
| 285 | printk(KERN_DEBUG "%s: sending data to socket (len = %d)\n", | ||
| 286 | __func__, len); | ||
| 287 | |||
| 288 | p = frame; | ||
| 289 | |||
| 290 | /* restart timer */ | ||
| 291 | if ((int)(hc->keep_tl.expires-jiffies) < 5*HZ) { | ||
| 292 | del_timer(&hc->keep_tl); | ||
| 293 | hc->keep_tl.expires = jiffies + L1OIP_KEEPALIVE*HZ; | ||
| 294 | add_timer(&hc->keep_tl); | ||
| 295 | } else | ||
| 296 | hc->keep_tl.expires = jiffies + L1OIP_KEEPALIVE*HZ; | ||
| 297 | |||
| 298 | if (debug & DEBUG_L1OIP_MSG) | ||
| 299 | printk(KERN_DEBUG "%s: resetting timer\n", __func__); | ||
| 300 | |||
| 301 | /* drop if we have no remote ip or port */ | ||
| 302 | if (!hc->sin_remote.sin_addr.s_addr || !hc->sin_remote.sin_port) { | ||
| 303 | if (debug & DEBUG_L1OIP_MSG) | ||
| 304 | printk(KERN_DEBUG "%s: dropping frame, because remote " | ||
| 305 | "IP is not set.\n", __func__); | ||
| 306 | return len; | ||
| 307 | } | ||
| 308 | |||
| 309 | /* assemble frame */ | ||
| 310 | *p++ = (L1OIP_VERSION<<6) /* version and coding */ | ||
| 311 | | (hc->pri?0x20:0x00) /* type */ | ||
| 312 | | (hc->id?0x10:0x00) /* id */ | ||
| 313 | | localcodec; | ||
| 314 | if (hc->id) { | ||
| 315 | *p++ = hc->id>>24; /* id */ | ||
| 316 | *p++ = hc->id>>16; | ||
| 317 | *p++ = hc->id>>8; | ||
| 318 | *p++ = hc->id; | ||
| 319 | } | ||
| 320 | *p++ = (multi == 1)?0x80:0x00 + channel; /* m-flag, channel */ | ||
| 321 | if (multi == 1) | ||
| 322 | *p++ = len; /* length */ | ||
| 323 | *p++ = timebase>>8; /* time base */ | ||
| 324 | *p++ = timebase; | ||
| 325 | |||
| 326 | if (buf && len) { /* add data to frame */ | ||
| 327 | if (localcodec == 1 && ulaw) | ||
| 328 | l1oip_ulaw_to_alaw(buf, len, p); | ||
| 329 | else if (localcodec == 2 && !ulaw) | ||
| 330 | l1oip_alaw_to_ulaw(buf, len, p); | ||
| 331 | else if (localcodec == 3) | ||
| 332 | len = l1oip_law_to_4bit(buf, len, p, | ||
| 333 | &hc->chan[channel].codecstate); | ||
| 334 | else | ||
| 335 | memcpy(p, buf, len); | ||
| 336 | } | ||
| 337 | len += p - frame; | ||
| 338 | |||
| 339 | /* check for socket in safe condition */ | ||
| 340 | spin_lock(&hc->socket_lock); | ||
| 341 | if (!hc->socket) { | ||
| 342 | spin_unlock(&hc->socket_lock); | ||
| 343 | return 0; | ||
| 344 | } | ||
| 345 | /* seize socket */ | ||
| 346 | socket = hc->socket; | ||
| 347 | hc->socket = NULL; | ||
| 348 | spin_unlock(&hc->socket_lock); | ||
| 349 | /* send packet */ | ||
| 350 | if (debug & DEBUG_L1OIP_MSG) | ||
| 351 | printk(KERN_DEBUG "%s: sending packet to socket (len " | ||
| 352 | "= %d)\n", __func__, len); | ||
| 353 | hc->sendiov.iov_base = frame; | ||
| 354 | hc->sendiov.iov_len = len; | ||
| 355 | oldfs = get_fs(); | ||
| 356 | set_fs(KERNEL_DS); | ||
| 357 | len = sock_sendmsg(socket, &hc->sendmsg, len); | ||
| 358 | set_fs(oldfs); | ||
| 359 | /* give socket back */ | ||
| 360 | hc->socket = socket; /* no locking required */ | ||
| 361 | |||
| 362 | return len; | ||
| 363 | } | ||
| 364 | |||
| 365 | |||
| 366 | /* | ||
| 367 | * receive channel data from socket | ||
| 368 | */ | ||
| 369 | static void | ||
| 370 | l1oip_socket_recv(struct l1oip *hc, u8 remotecodec, u8 channel, u16 timebase, | ||
| 371 | u8 *buf, int len) | ||
| 372 | { | ||
| 373 | struct sk_buff *nskb; | ||
| 374 | struct bchannel *bch; | ||
| 375 | struct dchannel *dch; | ||
| 376 | u8 *p; | ||
| 377 | u32 rx_counter; | ||
| 378 | |||
| 379 | if (len == 0) { | ||
| 380 | if (debug & DEBUG_L1OIP_MSG) | ||
| 381 | printk(KERN_DEBUG "%s: received empty keepalive data, " | ||
| 382 | "ignoring\n", __func__); | ||
| 383 | return; | ||
| 384 | } | ||
| 385 | |||
| 386 | if (debug & DEBUG_L1OIP_MSG) | ||
| 387 | printk(KERN_DEBUG "%s: received data, sending to mISDN (%d)\n", | ||
| 388 | __func__, len); | ||
| 389 | |||
| 390 | if (channel < 1 || channel > 127) { | ||
| 391 | printk(KERN_WARNING "%s: packet error - channel %d out of " | ||
| 392 | "range\n", __func__, channel); | ||
| 393 | return; | ||
| 394 | } | ||
| 395 | dch = hc->chan[channel].dch; | ||
| 396 | bch = hc->chan[channel].bch; | ||
| 397 | if (!dch && !bch) { | ||
| 398 | printk(KERN_WARNING "%s: packet error - channel %d not in " | ||
| 399 | "stack\n", __func__, channel); | ||
| 400 | return; | ||
| 401 | } | ||
| 402 | |||
| 403 | /* prepare message */ | ||
| 404 | nskb = mI_alloc_skb((remotecodec == 3)?(len<<1):len, GFP_ATOMIC); | ||
| 405 | if (!nskb) { | ||
| 406 | printk(KERN_ERR "%s: No mem for skb.\n", __func__); | ||
| 407 | return; | ||
| 408 | } | ||
| 409 | p = skb_put(nskb, (remotecodec == 3)?(len<<1):len); | ||
| 410 | |||
| 411 | if (remotecodec == 1 && ulaw) | ||
| 412 | l1oip_alaw_to_ulaw(buf, len, p); | ||
| 413 | else if (remotecodec == 2 && !ulaw) | ||
| 414 | l1oip_ulaw_to_alaw(buf, len, p); | ||
| 415 | else if (remotecodec == 3) | ||
| 416 | len = l1oip_4bit_to_law(buf, len, p); | ||
| 417 | else | ||
| 418 | memcpy(p, buf, len); | ||
| 419 | |||
| 420 | /* send message up */ | ||
| 421 | if (dch && len >= 2) { | ||
| 422 | dch->rx_skb = nskb; | ||
| 423 | recv_Dchannel(dch); | ||
| 424 | } | ||
| 425 | if (bch) { | ||
| 426 | /* expand 16 bit sequence number to 32 bit sequence number */ | ||
| 427 | rx_counter = hc->chan[channel].rx_counter; | ||
| 428 | if (((s16)(timebase - rx_counter)) >= 0) { | ||
| 429 | /* time has changed forward */ | ||
| 430 | if (timebase >= (rx_counter & 0xffff)) | ||
| 431 | rx_counter = | ||
| 432 | (rx_counter & 0xffff0000) | timebase; | ||
| 433 | else | ||
| 434 | rx_counter = ((rx_counter & 0xffff0000)+0x10000) | ||
| 435 | | timebase; | ||
| 436 | } else { | ||
| 437 | /* time has changed backwards */ | ||
| 438 | if (timebase < (rx_counter & 0xffff)) | ||
| 439 | rx_counter = | ||
| 440 | (rx_counter & 0xffff0000) | timebase; | ||
| 441 | else | ||
| 442 | rx_counter = ((rx_counter & 0xffff0000)-0x10000) | ||
| 443 | | timebase; | ||
| 444 | } | ||
| 445 | hc->chan[channel].rx_counter = rx_counter; | ||
| 446 | |||
| 447 | #ifdef REORDER_DEBUG | ||
| 448 | if (hc->chan[channel].disorder_flag) { | ||
| 449 | struct sk_buff *skb; | ||
| 450 | int cnt; | ||
| 451 | skb = hc->chan[channel].disorder_skb; | ||
| 452 | hc->chan[channel].disorder_skb = nskb; | ||
| 453 | nskb = skb; | ||
| 454 | cnt = hc->chan[channel].disorder_cnt; | ||
| 455 | hc->chan[channel].disorder_cnt = rx_counter; | ||
| 456 | rx_counter = cnt; | ||
| 457 | } | ||
| 458 | hc->chan[channel].disorder_flag ^= 1; | ||
| 459 | if (nskb) | ||
| 460 | #endif | ||
| 461 | queue_ch_frame(&bch->ch, PH_DATA_IND, rx_counter, nskb); | ||
| 462 | } | ||
| 463 | } | ||
| 464 | |||
| 465 | |||
| 466 | /* | ||
| 467 | * parse frame and extract channel data | ||
| 468 | */ | ||
| 469 | static void | ||
| 470 | l1oip_socket_parse(struct l1oip *hc, struct sockaddr_in *sin, u8 *buf, int len) | ||
| 471 | { | ||
| 472 | u32 id; | ||
| 473 | u8 channel; | ||
| 474 | u8 remotecodec; | ||
| 475 | u16 timebase; | ||
| 476 | int m, mlen; | ||
| 477 | int len_start = len; /* initial frame length */ | ||
| 478 | struct dchannel *dch = hc->chan[hc->d_idx].dch; | ||
| 479 | |||
| 480 | if (debug & DEBUG_L1OIP_MSG) | ||
| 481 | printk(KERN_DEBUG "%s: received frame, parsing... (%d)\n", | ||
| 482 | __func__, len); | ||
| 483 | |||
| 484 | /* check lenght */ | ||
| 485 | if (len < 1+1+2) { | ||
| 486 | printk(KERN_WARNING "%s: packet error - length %d below " | ||
| 487 | "4 bytes\n", __func__, len); | ||
| 488 | return; | ||
| 489 | } | ||
| 490 | |||
| 491 | /* check version */ | ||
| 492 | if (((*buf)>>6) != L1OIP_VERSION) { | ||
| 493 | printk(KERN_WARNING "%s: packet error - unknown version %d\n", | ||
| 494 | __func__, buf[0]>>6); | ||
| 495 | return; | ||
| 496 | } | ||
| 497 | |||
| 498 | /* check type */ | ||
| 499 | if (((*buf)&0x20) && !hc->pri) { | ||
| 500 | printk(KERN_WARNING "%s: packet error - received E1 packet " | ||
| 501 | "on S0 interface\n", __func__); | ||
| 502 | return; | ||
| 503 | } | ||
| 504 | if (!((*buf)&0x20) && hc->pri) { | ||
| 505 | printk(KERN_WARNING "%s: packet error - received S0 packet " | ||
| 506 | "on E1 interface\n", __func__); | ||
| 507 | return; | ||
| 508 | } | ||
| 509 | |||
| 510 | /* get id flag */ | ||
| 511 | id = (*buf>>4)&1; | ||
| 512 | |||
| 513 | /* check coding */ | ||
| 514 | remotecodec = (*buf) & 0x0f; | ||
| 515 | if (remotecodec > 3) { | ||
| 516 | printk(KERN_WARNING "%s: packet error - remotecodec %d " | ||
| 517 | "unsupported\n", __func__, remotecodec); | ||
| 518 | return; | ||
| 519 | } | ||
| 520 | buf++; | ||
| 521 | len--; | ||
| 522 | |||
| 523 | /* check id */ | ||
| 524 | if (id) { | ||
| 525 | if (!hc->id) { | ||
| 526 | printk(KERN_WARNING "%s: packet error - packet has id " | ||
| 527 | "0x%x, but we have not\n", __func__, id); | ||
| 528 | return; | ||
| 529 | } | ||
| 530 | if (len < 4) { | ||
| 531 | printk(KERN_WARNING "%s: packet error - packet too " | ||
| 532 | "short for ID value\n", __func__); | ||
| 533 | return; | ||
| 534 | } | ||
| 535 | id = (*buf++) << 24; | ||
| 536 | id += (*buf++) << 16; | ||
| 537 | id += (*buf++) << 8; | ||
| 538 | id += (*buf++); | ||
| 539 | len -= 4; | ||
| 540 | |||
| 541 | if (id != hc->id) { | ||
| 542 | printk(KERN_WARNING "%s: packet error - ID mismatch, " | ||
| 543 | "got 0x%x, we 0x%x\n", | ||
| 544 | __func__, id, hc->id); | ||
| 545 | return; | ||
| 546 | } | ||
| 547 | } else { | ||
| 548 | if (hc->id) { | ||
| 549 | printk(KERN_WARNING "%s: packet error - packet has no " | ||
| 550 | "ID, but we have\n", __func__); | ||
| 551 | return; | ||
| 552 | } | ||
| 553 | } | ||
| 554 | |||
| 555 | multiframe: | ||
| 556 | if (len < 1) { | ||
| 557 | printk(KERN_WARNING "%s: packet error - packet too short, " | ||
| 558 | "channel expected at position %d.\n", | ||
| 559 | __func__, len-len_start+1); | ||
| 560 | return; | ||
| 561 | } | ||
| 562 | |||
| 563 | /* get channel and multiframe flag */ | ||
| 564 | channel = *buf&0x7f; | ||
| 565 | m = *buf >> 7; | ||
| 566 | buf++; | ||
| 567 | len--; | ||
| 568 | |||
| 569 | /* check length on multiframe */ | ||
| 570 | if (m) { | ||
| 571 | if (len < 1) { | ||
| 572 | printk(KERN_WARNING "%s: packet error - packet too " | ||
| 573 | "short, length expected at position %d.\n", | ||
| 574 | __func__, len_start-len-1); | ||
| 575 | return; | ||
| 576 | } | ||
| 577 | |||
| 578 | mlen = *buf++; | ||
| 579 | len--; | ||
| 580 | if (mlen == 0) | ||
| 581 | mlen = 256; | ||
| 582 | if (len < mlen+3) { | ||
| 583 | printk(KERN_WARNING "%s: packet error - length %d at " | ||
| 584 | "position %d exceeds total length %d.\n", | ||
| 585 | __func__, mlen, len_start-len-1, len_start); | ||
| 586 | return; | ||
| 587 | } | ||
| 588 | if (len == mlen+3) { | ||
| 589 | printk(KERN_WARNING "%s: packet error - length %d at " | ||
| 590 | "position %d will not allow additional " | ||
| 591 | "packet.\n", | ||
| 592 | __func__, mlen, len_start-len+1); | ||
| 593 | return; | ||
| 594 | } | ||
| 595 | } else | ||
| 596 | mlen = len-2; /* single frame, substract timebase */ | ||
| 597 | |||
| 598 | if (len < 2) { | ||
| 599 | printk(KERN_WARNING "%s: packet error - packet too short, time " | ||
| 600 | "base expected at position %d.\n", | ||
| 601 | __func__, len-len_start+1); | ||
| 602 | return; | ||
| 603 | } | ||
| 604 | |||
| 605 | /* get time base */ | ||
| 606 | timebase = (*buf++) << 8; | ||
| 607 | timebase |= (*buf++); | ||
| 608 | len -= 2; | ||
| 609 | |||
| 610 | /* if inactive, we send up a PH_ACTIVATE and activate */ | ||
| 611 | if (!test_bit(FLG_ACTIVE, &dch->Flags)) { | ||
| 612 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
| 613 | printk(KERN_DEBUG "%s: interface become active due to " | ||
| 614 | "received packet\n", __func__); | ||
| 615 | test_and_set_bit(FLG_ACTIVE, &dch->Flags); | ||
| 616 | _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, | ||
| 617 | NULL, GFP_ATOMIC); | ||
| 618 | } | ||
| 619 | |||
| 620 | /* distribute packet */ | ||
| 621 | l1oip_socket_recv(hc, remotecodec, channel, timebase, buf, mlen); | ||
| 622 | buf += mlen; | ||
| 623 | len -= mlen; | ||
| 624 | |||
| 625 | /* multiframe */ | ||
| 626 | if (m) | ||
| 627 | goto multiframe; | ||
| 628 | |||
| 629 | /* restart timer */ | ||
| 630 | if ((int)(hc->timeout_tl.expires-jiffies) < 5*HZ || !hc->timeout_on) { | ||
| 631 | hc->timeout_on = 1; | ||
| 632 | del_timer(&hc->timeout_tl); | ||
| 633 | hc->timeout_tl.expires = jiffies + L1OIP_TIMEOUT*HZ; | ||
| 634 | add_timer(&hc->timeout_tl); | ||
| 635 | } else /* only adjust timer */ | ||
| 636 | hc->timeout_tl.expires = jiffies + L1OIP_TIMEOUT*HZ; | ||
| 637 | |||
| 638 | /* if ip or source port changes */ | ||
| 639 | if ((hc->sin_remote.sin_addr.s_addr != sin->sin_addr.s_addr) | ||
| 640 | || (hc->sin_remote.sin_port != sin->sin_port)) { | ||
| 641 | if (debug & DEBUG_L1OIP_SOCKET) | ||
| 642 | printk(KERN_DEBUG "%s: remote address changes from " | ||
| 643 | "0x%08x to 0x%08x (port %d to %d)\n", __func__, | ||
| 644 | ntohl(hc->sin_remote.sin_addr.s_addr), | ||
| 645 | ntohl(sin->sin_addr.s_addr), | ||
| 646 | ntohs(hc->sin_remote.sin_port), | ||
| 647 | ntohs(sin->sin_port)); | ||
| 648 | hc->sin_remote.sin_addr.s_addr = sin->sin_addr.s_addr; | ||
| 649 | hc->sin_remote.sin_port = sin->sin_port; | ||
| 650 | } | ||
| 651 | } | ||
| 652 | |||
| 653 | |||
| 654 | /* | ||
| 655 | * socket stuff | ||
| 656 | */ | ||
| 657 | static int | ||
| 658 | l1oip_socket_thread(void *data) | ||
| 659 | { | ||
| 660 | struct l1oip *hc = (struct l1oip *)data; | ||
| 661 | int ret = 0; | ||
| 662 | struct msghdr msg; | ||
| 663 | struct iovec iov; | ||
| 664 | mm_segment_t oldfs; | ||
| 665 | struct sockaddr_in sin_rx; | ||
| 666 | unsigned char recvbuf[1500]; | ||
| 667 | int recvlen; | ||
| 668 | struct socket *socket = NULL; | ||
| 669 | DECLARE_COMPLETION(wait); | ||
| 670 | |||
| 671 | /* make daemon */ | ||
| 672 | allow_signal(SIGTERM); | ||
| 673 | |||
| 674 | /* create socket */ | ||
| 675 | if (sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &socket)) { | ||
| 676 | printk(KERN_ERR "%s: Failed to create socket.\n", __func__); | ||
| 677 | return -EIO; | ||
| 678 | } | ||
| 679 | |||
| 680 | /* set incoming address */ | ||
| 681 | hc->sin_local.sin_family = AF_INET; | ||
| 682 | hc->sin_local.sin_addr.s_addr = INADDR_ANY; | ||
| 683 | hc->sin_local.sin_port = htons((unsigned short)hc->localport); | ||
| 684 | |||
| 685 | /* set outgoing address */ | ||
| 686 | hc->sin_remote.sin_family = AF_INET; | ||
| 687 | hc->sin_remote.sin_addr.s_addr = htonl(hc->remoteip); | ||
| 688 | hc->sin_remote.sin_port = htons((unsigned short)hc->remoteport); | ||
| 689 | |||
| 690 | /* bind to incomming port */ | ||
| 691 | if (socket->ops->bind(socket, (struct sockaddr *)&hc->sin_local, | ||
| 692 | sizeof(hc->sin_local))) { | ||
| 693 | printk(KERN_ERR "%s: Failed to bind socket to port %d.\n", | ||
| 694 | __func__, hc->localport); | ||
| 695 | ret = -EINVAL; | ||
| 696 | goto fail; | ||
| 697 | } | ||
| 698 | |||
| 699 | /* check sk */ | ||
| 700 | if (socket->sk == NULL) { | ||
| 701 | printk(KERN_ERR "%s: socket->sk == NULL\n", __func__); | ||
| 702 | ret = -EIO; | ||
| 703 | goto fail; | ||
| 704 | } | ||
| 705 | |||
| 706 | /* build receive message */ | ||
| 707 | msg.msg_name = &sin_rx; | ||
| 708 | msg.msg_namelen = sizeof(sin_rx); | ||
| 709 | msg.msg_control = NULL; | ||
| 710 | msg.msg_controllen = 0; | ||
| 711 | msg.msg_iov = &iov; | ||
| 712 | msg.msg_iovlen = 1; | ||
| 713 | |||
| 714 | /* build send message */ | ||
| 715 | hc->sendmsg.msg_name = &hc->sin_remote; | ||
| 716 | hc->sendmsg.msg_namelen = sizeof(hc->sin_remote); | ||
| 717 | hc->sendmsg.msg_control = NULL; | ||
| 718 | hc->sendmsg.msg_controllen = 0; | ||
| 719 | hc->sendmsg.msg_iov = &hc->sendiov; | ||
| 720 | hc->sendmsg.msg_iovlen = 1; | ||
| 721 | |||
| 722 | /* give away socket */ | ||
| 723 | spin_lock(&hc->socket_lock); | ||
| 724 | hc->socket = socket; | ||
| 725 | spin_unlock(&hc->socket_lock); | ||
| 726 | |||
| 727 | /* read loop */ | ||
| 728 | if (debug & DEBUG_L1OIP_SOCKET) | ||
| 729 | printk(KERN_DEBUG "%s: socket created and open\n", | ||
| 730 | __func__); | ||
| 731 | while (!signal_pending(current)) { | ||
| 732 | iov.iov_base = recvbuf; | ||
| 733 | iov.iov_len = sizeof(recvbuf); | ||
| 734 | oldfs = get_fs(); | ||
| 735 | set_fs(KERNEL_DS); | ||
| 736 | recvlen = sock_recvmsg(socket, &msg, sizeof(recvbuf), 0); | ||
| 737 | set_fs(oldfs); | ||
| 738 | if (recvlen > 0) { | ||
| 739 | l1oip_socket_parse(hc, &sin_rx, recvbuf, recvlen); | ||
| 740 | } else { | ||
| 741 | if (debug & DEBUG_L1OIP_SOCKET) | ||
| 742 | printk(KERN_WARNING "%s: broken pipe on socket\n", | ||
| 743 | __func__); | ||
| 744 | } | ||
| 745 | } | ||
| 746 | |||
| 747 | /* get socket back, check first if in use, maybe by send function */ | ||
| 748 | spin_lock(&hc->socket_lock); | ||
| 749 | /* if hc->socket is NULL, it is in use until it is given back */ | ||
| 750 | while (!hc->socket) { | ||
| 751 | spin_unlock(&hc->socket_lock); | ||
| 752 | schedule_timeout(HZ/10); | ||
| 753 | spin_lock(&hc->socket_lock); | ||
| 754 | } | ||
| 755 | hc->socket = NULL; | ||
| 756 | spin_unlock(&hc->socket_lock); | ||
| 757 | |||
| 758 | if (debug & DEBUG_L1OIP_SOCKET) | ||
| 759 | printk(KERN_DEBUG "%s: socket thread terminating\n", | ||
| 760 | __func__); | ||
| 761 | |||
| 762 | fail: | ||
| 763 | /* close socket */ | ||
| 764 | if (socket) | ||
| 765 | sock_release(socket); | ||
| 766 | |||
| 767 | /* if we got killed, signal completion */ | ||
| 768 | complete(&hc->socket_complete); | ||
| 769 | hc->socket_thread = NULL; /* show termination of thread */ | ||
| 770 | |||
| 771 | if (debug & DEBUG_L1OIP_SOCKET) | ||
| 772 | printk(KERN_DEBUG "%s: socket thread terminated\n", | ||
| 773 | __func__); | ||
| 774 | return ret; | ||
| 775 | } | ||
| 776 | |||
| 777 | static void | ||
| 778 | l1oip_socket_close(struct l1oip *hc) | ||
| 779 | { | ||
| 780 | /* kill thread */ | ||
| 781 | if (hc->socket_thread) { | ||
| 782 | if (debug & DEBUG_L1OIP_SOCKET) | ||
| 783 | printk(KERN_DEBUG "%s: socket thread exists, " | ||
| 784 | "killing...\n", __func__); | ||
| 785 | send_sig(SIGTERM, hc->socket_thread, 0); | ||
| 786 | wait_for_completion(&hc->socket_complete); | ||
| 787 | } | ||
| 788 | } | ||
| 789 | |||
| 790 | static int | ||
| 791 | l1oip_socket_open(struct l1oip *hc) | ||
| 792 | { | ||
| 793 | /* in case of reopen, we need to close first */ | ||
| 794 | l1oip_socket_close(hc); | ||
| 795 | |||
| 796 | init_completion(&hc->socket_complete); | ||
| 797 | |||
| 798 | /* create receive process */ | ||
| 799 | hc->socket_thread = kthread_run(l1oip_socket_thread, hc, "l1oip_%s", | ||
| 800 | hc->name); | ||
| 801 | if (IS_ERR(hc->socket_thread)) { | ||
| 802 | int err = PTR_ERR(hc->socket_thread); | ||
| 803 | printk(KERN_ERR "%s: Failed (%d) to create socket process.\n", | ||
| 804 | __func__, err); | ||
| 805 | hc->socket_thread = NULL; | ||
| 806 | sock_release(hc->socket); | ||
| 807 | return err; | ||
| 808 | } | ||
| 809 | if (debug & DEBUG_L1OIP_SOCKET) | ||
| 810 | printk(KERN_DEBUG "%s: socket thread created\n", __func__); | ||
| 811 | |||
| 812 | return 0; | ||
| 813 | } | ||
| 814 | |||
| 815 | |||
| 816 | static void | ||
| 817 | l1oip_send_bh(struct work_struct *work) | ||
| 818 | { | ||
| 819 | struct l1oip *hc = container_of(work, struct l1oip, workq); | ||
| 820 | |||
| 821 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
| 822 | printk(KERN_DEBUG "%s: keepalive timer expired, sending empty " | ||
| 823 | "frame on dchannel\n", __func__); | ||
| 824 | |||
| 825 | /* send an empty l1oip frame at D-channel */ | ||
| 826 | l1oip_socket_send(hc, 0, hc->d_idx, 0, 0, NULL, 0); | ||
| 827 | } | ||
| 828 | |||
| 829 | |||
| 830 | /* | ||
| 831 | * timer stuff | ||
| 832 | */ | ||
| 833 | static void | ||
| 834 | l1oip_keepalive(void *data) | ||
| 835 | { | ||
| 836 | struct l1oip *hc = (struct l1oip *)data; | ||
| 837 | |||
| 838 | schedule_work(&hc->workq); | ||
| 839 | } | ||
| 840 | |||
| 841 | static void | ||
| 842 | l1oip_timeout(void *data) | ||
| 843 | { | ||
| 844 | struct l1oip *hc = (struct l1oip *)data; | ||
| 845 | struct dchannel *dch = hc->chan[hc->d_idx].dch; | ||
| 846 | |||
| 847 | if (debug & DEBUG_L1OIP_MSG) | ||
| 848 | printk(KERN_DEBUG "%s: timeout timer expired, turn layer one " | ||
| 849 | "down.\n", __func__); | ||
| 850 | |||
| 851 | hc->timeout_on = 0; /* state that timer must be initialized next time */ | ||
| 852 | |||
| 853 | /* if timeout, we send up a PH_DEACTIVATE and deactivate */ | ||
| 854 | if (test_bit(FLG_ACTIVE, &dch->Flags)) { | ||
| 855 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
| 856 | printk(KERN_DEBUG "%s: interface become deactivated " | ||
| 857 | "due to timeout\n", __func__); | ||
| 858 | test_and_clear_bit(FLG_ACTIVE, &dch->Flags); | ||
| 859 | _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, | ||
| 860 | NULL, GFP_ATOMIC); | ||
| 861 | } | ||
| 862 | |||
| 863 | /* if we have ondemand set, we remove ip address */ | ||
| 864 | if (hc->ondemand) { | ||
| 865 | if (debug & DEBUG_L1OIP_MSG) | ||
| 866 | printk(KERN_DEBUG "%s: on demand causes ip address to " | ||
| 867 | "be removed\n", __func__); | ||
| 868 | hc->sin_remote.sin_addr.s_addr = 0; | ||
| 869 | } | ||
| 870 | } | ||
| 871 | |||
| 872 | |||
| 873 | /* | ||
| 874 | * message handling | ||
| 875 | */ | ||
| 876 | static int | ||
| 877 | handle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb) | ||
| 878 | { | ||
| 879 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
| 880 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
| 881 | struct l1oip *hc = dch->hw; | ||
| 882 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
| 883 | int ret = -EINVAL; | ||
| 884 | int l, ll; | ||
| 885 | unsigned char *p; | ||
| 886 | |||
| 887 | switch (hh->prim) { | ||
| 888 | case PH_DATA_REQ: | ||
| 889 | if (skb->len < 1) { | ||
| 890 | printk(KERN_WARNING "%s: skb too small\n", | ||
| 891 | __func__); | ||
| 892 | break; | ||
| 893 | } | ||
| 894 | if (skb->len > MAX_DFRAME_LEN_L1 || skb->len > L1OIP_MAX_LEN) { | ||
| 895 | printk(KERN_WARNING "%s: skb too large\n", | ||
| 896 | __func__); | ||
| 897 | break; | ||
| 898 | } | ||
| 899 | /* send frame */ | ||
| 900 | p = skb->data; | ||
| 901 | l = skb->len; | ||
| 902 | while (l) { | ||
| 903 | ll = (l < L1OIP_MAX_PERFRAME)?l:L1OIP_MAX_PERFRAME; | ||
| 904 | l1oip_socket_send(hc, 0, dch->slot, 0, | ||
| 905 | hc->chan[dch->slot].tx_counter++, p, ll); | ||
| 906 | p += ll; | ||
| 907 | l -= ll; | ||
| 908 | } | ||
| 909 | skb_trim(skb, 0); | ||
| 910 | queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb); | ||
| 911 | return 0; | ||
| 912 | case PH_ACTIVATE_REQ: | ||
| 913 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
| 914 | printk(KERN_DEBUG "%s: PH_ACTIVATE channel %d (1..%d)\n" | ||
| 915 | , __func__, dch->slot, hc->b_num+1); | ||
| 916 | skb_trim(skb, 0); | ||
| 917 | if (test_bit(FLG_ACTIVE, &dch->Flags)) | ||
| 918 | queue_ch_frame(ch, PH_ACTIVATE_IND, hh->id, skb); | ||
| 919 | else | ||
| 920 | queue_ch_frame(ch, PH_DEACTIVATE_IND, hh->id, skb); | ||
| 921 | return 0; | ||
| 922 | case PH_DEACTIVATE_REQ: | ||
| 923 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
| 924 | printk(KERN_DEBUG "%s: PH_DEACTIVATE channel %d " | ||
| 925 | "(1..%d)\n", __func__, dch->slot, | ||
| 926 | hc->b_num+1); | ||
| 927 | skb_trim(skb, 0); | ||
| 928 | if (test_bit(FLG_ACTIVE, &dch->Flags)) | ||
| 929 | queue_ch_frame(ch, PH_ACTIVATE_IND, hh->id, skb); | ||
| 930 | else | ||
| 931 | queue_ch_frame(ch, PH_DEACTIVATE_IND, hh->id, skb); | ||
| 932 | return 0; | ||
| 933 | } | ||
| 934 | if (!ret) | ||
| 935 | dev_kfree_skb(skb); | ||
| 936 | return ret; | ||
| 937 | } | ||
| 938 | |||
| 939 | static int | ||
| 940 | channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) | ||
| 941 | { | ||
| 942 | int ret = 0; | ||
| 943 | struct l1oip *hc = dch->hw; | ||
| 944 | |||
| 945 | switch (cq->op) { | ||
| 946 | case MISDN_CTRL_GETOP: | ||
| 947 | cq->op = MISDN_CTRL_SETPEER | MISDN_CTRL_UNSETPEER; | ||
| 948 | break; | ||
| 949 | case MISDN_CTRL_SETPEER: | ||
| 950 | hc->remoteip = (u32)cq->p1; | ||
| 951 | hc->remoteport = cq->p2 & 0xffff; | ||
| 952 | hc->localport = cq->p2 >> 16; | ||
| 953 | if (!hc->remoteport) | ||
| 954 | hc->remoteport = hc->localport; | ||
| 955 | if (debug & DEBUG_L1OIP_SOCKET) | ||
| 956 | printk(KERN_DEBUG "%s: got new ip address from user " | ||
| 957 | "space.\n", __func__); | ||
| 958 | l1oip_socket_open(hc); | ||
| 959 | break; | ||
| 960 | case MISDN_CTRL_UNSETPEER: | ||
| 961 | if (debug & DEBUG_L1OIP_SOCKET) | ||
| 962 | printk(KERN_DEBUG "%s: removing ip address.\n", | ||
| 963 | __func__); | ||
| 964 | hc->remoteip = 0; | ||
| 965 | l1oip_socket_open(hc); | ||
| 966 | break; | ||
| 967 | default: | ||
| 968 | printk(KERN_WARNING "%s: unknown Op %x\n", | ||
| 969 | __func__, cq->op); | ||
| 970 | ret = -EINVAL; | ||
| 971 | break; | ||
| 972 | } | ||
| 973 | return ret; | ||
| 974 | } | ||
| 975 | |||
| 976 | static int | ||
| 977 | open_dchannel(struct l1oip *hc, struct dchannel *dch, struct channel_req *rq) | ||
| 978 | { | ||
| 979 | if (debug & DEBUG_HW_OPEN) | ||
| 980 | printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__, | ||
| 981 | dch->dev.id, __builtin_return_address(0)); | ||
| 982 | if (rq->protocol == ISDN_P_NONE) | ||
| 983 | return -EINVAL; | ||
| 984 | if ((dch->dev.D.protocol != ISDN_P_NONE) && | ||
| 985 | (dch->dev.D.protocol != rq->protocol)) { | ||
| 986 | if (debug & DEBUG_HW_OPEN) | ||
| 987 | printk(KERN_WARNING "%s: change protocol %x to %x\n", | ||
| 988 | __func__, dch->dev.D.protocol, rq->protocol); | ||
| 989 | } | ||
| 990 | if (dch->dev.D.protocol != rq->protocol) | ||
| 991 | dch->dev.D.protocol = rq->protocol; | ||
| 992 | |||
| 993 | if (test_bit(FLG_ACTIVE, &dch->Flags)) { | ||
| 994 | _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, | ||
| 995 | 0, NULL, GFP_KERNEL); | ||
| 996 | } | ||
| 997 | rq->ch = &dch->dev.D; | ||
| 998 | if (!try_module_get(THIS_MODULE)) | ||
| 999 | printk(KERN_WARNING "%s:cannot get module\n", __func__); | ||
| 1000 | return 0; | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | static int | ||
| 1004 | open_bchannel(struct l1oip *hc, struct dchannel *dch, struct channel_req *rq) | ||
| 1005 | { | ||
| 1006 | struct bchannel *bch; | ||
| 1007 | int ch; | ||
| 1008 | |||
| 1009 | if (!test_bit(rq->adr.channel & 0x1f, | ||
| 1010 | &dch->dev.channelmap[rq->adr.channel >> 5])) | ||
| 1011 | return -EINVAL; | ||
| 1012 | if (rq->protocol == ISDN_P_NONE) | ||
| 1013 | return -EINVAL; | ||
| 1014 | ch = rq->adr.channel; /* BRI: 1=B1 2=B2 PRI: 1..15,17.. */ | ||
| 1015 | bch = hc->chan[ch].bch; | ||
| 1016 | if (!bch) { | ||
| 1017 | printk(KERN_ERR "%s:internal error ch %d has no bch\n", | ||
| 1018 | __func__, ch); | ||
| 1019 | return -EINVAL; | ||
| 1020 | } | ||
| 1021 | if (test_and_set_bit(FLG_OPEN, &bch->Flags)) | ||
| 1022 | return -EBUSY; /* b-channel can be only open once */ | ||
| 1023 | bch->ch.protocol = rq->protocol; | ||
| 1024 | rq->ch = &bch->ch; | ||
| 1025 | if (!try_module_get(THIS_MODULE)) | ||
| 1026 | printk(KERN_WARNING "%s:cannot get module\n", __func__); | ||
| 1027 | return 0; | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | static int | ||
| 1031 | l1oip_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
| 1032 | { | ||
| 1033 | struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); | ||
| 1034 | struct dchannel *dch = container_of(dev, struct dchannel, dev); | ||
| 1035 | struct l1oip *hc = dch->hw; | ||
| 1036 | struct channel_req *rq; | ||
| 1037 | int err = 0; | ||
| 1038 | |||
| 1039 | if (dch->debug & DEBUG_HW) | ||
| 1040 | printk(KERN_DEBUG "%s: cmd:%x %p\n", | ||
| 1041 | __func__, cmd, arg); | ||
| 1042 | switch (cmd) { | ||
| 1043 | case OPEN_CHANNEL: | ||
| 1044 | rq = arg; | ||
| 1045 | switch (rq->protocol) { | ||
| 1046 | case ISDN_P_TE_S0: | ||
| 1047 | case ISDN_P_NT_S0: | ||
| 1048 | if (hc->pri) { | ||
| 1049 | err = -EINVAL; | ||
| 1050 | break; | ||
| 1051 | } | ||
| 1052 | err = open_dchannel(hc, dch, rq); | ||
| 1053 | break; | ||
| 1054 | case ISDN_P_TE_E1: | ||
| 1055 | case ISDN_P_NT_E1: | ||
| 1056 | if (!hc->pri) { | ||
| 1057 | err = -EINVAL; | ||
| 1058 | break; | ||
| 1059 | } | ||
| 1060 | err = open_dchannel(hc, dch, rq); | ||
| 1061 | break; | ||
| 1062 | default: | ||
| 1063 | err = open_bchannel(hc, dch, rq); | ||
| 1064 | } | ||
| 1065 | break; | ||
| 1066 | case CLOSE_CHANNEL: | ||
| 1067 | if (debug & DEBUG_HW_OPEN) | ||
| 1068 | printk(KERN_DEBUG "%s: dev(%d) close from %p\n", | ||
| 1069 | __func__, dch->dev.id, | ||
| 1070 | __builtin_return_address(0)); | ||
| 1071 | module_put(THIS_MODULE); | ||
| 1072 | break; | ||
| 1073 | case CONTROL_CHANNEL: | ||
| 1074 | err = channel_dctrl(dch, arg); | ||
| 1075 | break; | ||
| 1076 | default: | ||
| 1077 | if (dch->debug & DEBUG_HW) | ||
| 1078 | printk(KERN_DEBUG "%s: unknown command %x\n", | ||
| 1079 | __func__, cmd); | ||
| 1080 | err = -EINVAL; | ||
| 1081 | } | ||
| 1082 | return err; | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | static int | ||
| 1086 | handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) | ||
| 1087 | { | ||
| 1088 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
| 1089 | struct l1oip *hc = bch->hw; | ||
| 1090 | int ret = -EINVAL; | ||
| 1091 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
| 1092 | int l, ll, i; | ||
| 1093 | unsigned char *p; | ||
| 1094 | |||
| 1095 | switch (hh->prim) { | ||
| 1096 | case PH_DATA_REQ: | ||
| 1097 | if (skb->len <= 0) { | ||
| 1098 | printk(KERN_WARNING "%s: skb too small\n", | ||
| 1099 | __func__); | ||
| 1100 | break; | ||
| 1101 | } | ||
| 1102 | if (skb->len > MAX_DFRAME_LEN_L1 || skb->len > L1OIP_MAX_LEN) { | ||
| 1103 | printk(KERN_WARNING "%s: skb too large\n", | ||
| 1104 | __func__); | ||
| 1105 | break; | ||
| 1106 | } | ||
| 1107 | /* check for AIS / ulaw-silence */ | ||
| 1108 | p = skb->data; | ||
| 1109 | l = skb->len; | ||
| 1110 | for (i = 0; i < l; i++) { | ||
| 1111 | if (*p++ != 0xff) | ||
| 1112 | break; | ||
| 1113 | } | ||
| 1114 | if (i == l) { | ||
| 1115 | if (debug & DEBUG_L1OIP_MSG) | ||
| 1116 | printk(KERN_DEBUG "%s: got AIS, not sending, " | ||
| 1117 | "but counting\n", __func__); | ||
| 1118 | hc->chan[bch->slot].tx_counter += l; | ||
| 1119 | skb_trim(skb, 0); | ||
| 1120 | queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb); | ||
| 1121 | return 0; | ||
| 1122 | } | ||
| 1123 | /* check for silence */ | ||
| 1124 | p = skb->data; | ||
| 1125 | l = skb->len; | ||
| 1126 | for (i = 0; i < l; i++) { | ||
| 1127 | if (*p++ != 0x2a) | ||
| 1128 | break; | ||
| 1129 | } | ||
| 1130 | if (i == l) { | ||
| 1131 | if (debug & DEBUG_L1OIP_MSG) | ||
| 1132 | printk(KERN_DEBUG "%s: got silence, not sending" | ||
| 1133 | ", but counting\n", __func__); | ||
| 1134 | hc->chan[bch->slot].tx_counter += l; | ||
| 1135 | skb_trim(skb, 0); | ||
| 1136 | queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb); | ||
| 1137 | return 0; | ||
| 1138 | } | ||
| 1139 | |||
| 1140 | /* send frame */ | ||
| 1141 | p = skb->data; | ||
| 1142 | l = skb->len; | ||
| 1143 | while (l) { | ||
| 1144 | ll = (l < L1OIP_MAX_PERFRAME)?l:L1OIP_MAX_PERFRAME; | ||
| 1145 | l1oip_socket_send(hc, hc->codec, bch->slot, 0, | ||
| 1146 | hc->chan[bch->slot].tx_counter, p, ll); | ||
| 1147 | hc->chan[bch->slot].tx_counter += ll; | ||
| 1148 | p += ll; | ||
| 1149 | l -= ll; | ||
| 1150 | } | ||
| 1151 | skb_trim(skb, 0); | ||
| 1152 | queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb); | ||
| 1153 | return 0; | ||
| 1154 | case PH_ACTIVATE_REQ: | ||
| 1155 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
| 1156 | printk(KERN_DEBUG "%s: PH_ACTIVATE channel %d (1..%d)\n" | ||
| 1157 | , __func__, bch->slot, hc->b_num+1); | ||
| 1158 | hc->chan[bch->slot].codecstate = 0; | ||
| 1159 | test_and_set_bit(FLG_ACTIVE, &bch->Flags); | ||
| 1160 | skb_trim(skb, 0); | ||
| 1161 | queue_ch_frame(ch, PH_ACTIVATE_IND, hh->id, skb); | ||
| 1162 | return 0; | ||
| 1163 | case PH_DEACTIVATE_REQ: | ||
| 1164 | if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) | ||
| 1165 | printk(KERN_DEBUG "%s: PH_DEACTIVATE channel %d " | ||
| 1166 | "(1..%d)\n", __func__, bch->slot, | ||
| 1167 | hc->b_num+1); | ||
| 1168 | test_and_clear_bit(FLG_ACTIVE, &bch->Flags); | ||
| 1169 | skb_trim(skb, 0); | ||
| 1170 | queue_ch_frame(ch, PH_DEACTIVATE_IND, hh->id, skb); | ||
| 1171 | return 0; | ||
| 1172 | } | ||
| 1173 | if (!ret) | ||
| 1174 | dev_kfree_skb(skb); | ||
| 1175 | return ret; | ||
| 1176 | } | ||
| 1177 | |||
| 1178 | static int | ||
| 1179 | channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) | ||
| 1180 | { | ||
| 1181 | int ret = 0; | ||
| 1182 | struct dsp_features *features = | ||
| 1183 | (struct dsp_features *)(*((u_long *)&cq->p1)); | ||
| 1184 | |||
| 1185 | switch (cq->op) { | ||
| 1186 | case MISDN_CTRL_GETOP: | ||
| 1187 | cq->op = MISDN_CTRL_HW_FEATURES_OP; | ||
| 1188 | break; | ||
| 1189 | case MISDN_CTRL_HW_FEATURES: /* fill features structure */ | ||
| 1190 | if (debug & DEBUG_L1OIP_MSG) | ||
| 1191 | printk(KERN_DEBUG "%s: HW_FEATURE request\n", | ||
| 1192 | __func__); | ||
| 1193 | /* create confirm */ | ||
| 1194 | features->unclocked = 1; | ||
| 1195 | features->unordered = 1; | ||
| 1196 | break; | ||
| 1197 | default: | ||
| 1198 | printk(KERN_WARNING "%s: unknown Op %x\n", | ||
| 1199 | __func__, cq->op); | ||
| 1200 | ret = -EINVAL; | ||
| 1201 | break; | ||
| 1202 | } | ||
| 1203 | return ret; | ||
| 1204 | } | ||
| 1205 | |||
| 1206 | static int | ||
| 1207 | l1oip_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
| 1208 | { | ||
| 1209 | struct bchannel *bch = container_of(ch, struct bchannel, ch); | ||
| 1210 | int err = -EINVAL; | ||
| 1211 | |||
| 1212 | if (bch->debug & DEBUG_HW) | ||
| 1213 | printk(KERN_DEBUG "%s: cmd:%x %p\n", | ||
| 1214 | __func__, cmd, arg); | ||
| 1215 | switch (cmd) { | ||
| 1216 | case CLOSE_CHANNEL: | ||
| 1217 | test_and_clear_bit(FLG_OPEN, &bch->Flags); | ||
| 1218 | test_and_clear_bit(FLG_ACTIVE, &bch->Flags); | ||
| 1219 | ch->protocol = ISDN_P_NONE; | ||
| 1220 | ch->peer = NULL; | ||
| 1221 | module_put(THIS_MODULE); | ||
| 1222 | err = 0; | ||
| 1223 | break; | ||
| 1224 | case CONTROL_CHANNEL: | ||
| 1225 | err = channel_bctrl(bch, arg); | ||
| 1226 | break; | ||
| 1227 | default: | ||
| 1228 | printk(KERN_WARNING "%s: unknown prim(%x)\n", | ||
| 1229 | __func__, cmd); | ||
| 1230 | } | ||
| 1231 | return err; | ||
| 1232 | } | ||
| 1233 | |||
| 1234 | |||
| 1235 | /* | ||
| 1236 | * cleanup module and stack | ||
| 1237 | */ | ||
| 1238 | static void | ||
| 1239 | release_card(struct l1oip *hc) | ||
| 1240 | { | ||
| 1241 | int ch; | ||
| 1242 | |||
| 1243 | if (timer_pending(&hc->keep_tl)) | ||
| 1244 | del_timer(&hc->keep_tl); | ||
| 1245 | |||
| 1246 | if (timer_pending(&hc->timeout_tl)) | ||
| 1247 | del_timer(&hc->timeout_tl); | ||
| 1248 | |||
| 1249 | if (hc->socket_thread) | ||
| 1250 | l1oip_socket_close(hc); | ||
| 1251 | |||
| 1252 | if (hc->registered && hc->chan[hc->d_idx].dch) | ||
| 1253 | mISDN_unregister_device(&hc->chan[hc->d_idx].dch->dev); | ||
| 1254 | for (ch = 0; ch < 128; ch++) { | ||
| 1255 | if (hc->chan[ch].dch) { | ||
| 1256 | mISDN_freedchannel(hc->chan[ch].dch); | ||
| 1257 | kfree(hc->chan[ch].dch); | ||
| 1258 | } | ||
| 1259 | if (hc->chan[ch].bch) { | ||
| 1260 | mISDN_freebchannel(hc->chan[ch].bch); | ||
| 1261 | kfree(hc->chan[ch].bch); | ||
| 1262 | #ifdef REORDER_DEBUG | ||
| 1263 | if (hc->chan[ch].disorder_skb) | ||
| 1264 | dev_kfree_skb(hc->chan[ch].disorder_skb); | ||
| 1265 | #endif | ||
| 1266 | } | ||
| 1267 | } | ||
| 1268 | |||
| 1269 | spin_lock(&l1oip_lock); | ||
| 1270 | list_del(&hc->list); | ||
| 1271 | spin_unlock(&l1oip_lock); | ||
| 1272 | |||
| 1273 | kfree(hc); | ||
| 1274 | } | ||
| 1275 | |||
| 1276 | static void | ||
| 1277 | l1oip_cleanup(void) | ||
| 1278 | { | ||
| 1279 | struct l1oip *hc, *next; | ||
| 1280 | |||
| 1281 | list_for_each_entry_safe(hc, next, &l1oip_ilist, list) | ||
| 1282 | release_card(hc); | ||
| 1283 | |||
| 1284 | l1oip_4bit_free(); | ||
| 1285 | } | ||
| 1286 | |||
| 1287 | |||
| 1288 | /* | ||
| 1289 | * module and stack init | ||
| 1290 | */ | ||
| 1291 | static int | ||
| 1292 | init_card(struct l1oip *hc, int pri, int bundle) | ||
| 1293 | { | ||
| 1294 | struct dchannel *dch; | ||
| 1295 | struct bchannel *bch; | ||
| 1296 | int ret; | ||
| 1297 | int i, ch; | ||
| 1298 | |||
| 1299 | spin_lock_init(&hc->socket_lock); | ||
| 1300 | hc->idx = l1oip_cnt; | ||
| 1301 | hc->pri = pri; | ||
| 1302 | hc->d_idx = pri?16:3; | ||
| 1303 | hc->b_num = pri?30:2; | ||
| 1304 | hc->bundle = bundle; | ||
| 1305 | if (hc->pri) | ||
| 1306 | sprintf(hc->name, "l1oip-e1.%d", l1oip_cnt + 1); | ||
| 1307 | else | ||
| 1308 | sprintf(hc->name, "l1oip-s0.%d", l1oip_cnt + 1); | ||
| 1309 | |||
| 1310 | switch (codec[l1oip_cnt]) { | ||
| 1311 | case 0: /* as is */ | ||
| 1312 | case 1: /* alaw */ | ||
| 1313 | case 2: /* ulaw */ | ||
| 1314 | case 3: /* 4bit */ | ||
| 1315 | break; | ||
| 1316 | default: | ||
| 1317 | printk(KERN_ERR "Codec(%d) not supported.\n", | ||
| 1318 | codec[l1oip_cnt]); | ||
| 1319 | return -EINVAL; | ||
| 1320 | } | ||
| 1321 | hc->codec = codec[l1oip_cnt]; | ||
| 1322 | if (debug & DEBUG_L1OIP_INIT) | ||
| 1323 | printk(KERN_DEBUG "%s: using codec %d\n", | ||
| 1324 | __func__, hc->codec); | ||
| 1325 | |||
| 1326 | if (id[l1oip_cnt] == 0) { | ||
| 1327 | printk(KERN_WARNING "Warning: No 'id' value given or " | ||
| 1328 | "0, this is highly unsecure. Please use 32 " | ||
| 1329 | "bit randmom number 0x...\n"); | ||
| 1330 | } | ||
| 1331 | hc->id = id[l1oip_cnt]; | ||
| 1332 | if (debug & DEBUG_L1OIP_INIT) | ||
| 1333 | printk(KERN_DEBUG "%s: using id 0x%x\n", __func__, hc->id); | ||
| 1334 | |||
| 1335 | hc->ondemand = ondemand[l1oip_cnt]; | ||
| 1336 | if (hc->ondemand && !hc->id) { | ||
| 1337 | printk(KERN_ERR "%s: ondemand option only allowed in " | ||
| 1338 | "conjunction with non 0 ID\n", __func__); | ||
| 1339 | return -EINVAL; | ||
| 1340 | } | ||
| 1341 | |||
| 1342 | if (limit[l1oip_cnt]) | ||
| 1343 | hc->b_num = limit[l1oip_cnt]; | ||
| 1344 | if (!pri && hc->b_num > 2) { | ||
| 1345 | printk(KERN_ERR "Maximum limit for BRI interface is 2 " | ||
| 1346 | "channels.\n"); | ||
| 1347 | return -EINVAL; | ||
| 1348 | } | ||
| 1349 | if (pri && hc->b_num > 126) { | ||
| 1350 | printk(KERN_ERR "Maximum limit for PRI interface is 126 " | ||
| 1351 | "channels.\n"); | ||
| 1352 | return -EINVAL; | ||
| 1353 | } | ||
| 1354 | if (pri && hc->b_num > 30) { | ||
| 1355 | printk(KERN_WARNING "Maximum limit for BRI interface is 30 " | ||
| 1356 | "channels.\n"); | ||
| 1357 | printk(KERN_WARNING "Your selection of %d channels must be " | ||
| 1358 | "supported by application.\n", hc->limit); | ||
| 1359 | } | ||
| 1360 | |||
| 1361 | hc->remoteip = ip[l1oip_cnt<<2] << 24 | ||
| 1362 | | ip[(l1oip_cnt<<2)+1] << 16 | ||
| 1363 | | ip[(l1oip_cnt<<2)+2] << 8 | ||
| 1364 | | ip[(l1oip_cnt<<2)+3]; | ||
| 1365 | hc->localport = port[l1oip_cnt]?:(L1OIP_DEFAULTPORT+l1oip_cnt); | ||
| 1366 | if (remoteport[l1oip_cnt]) | ||
| 1367 | hc->remoteport = remoteport[l1oip_cnt]; | ||
| 1368 | else | ||
| 1369 | hc->remoteport = hc->localport; | ||
| 1370 | if (debug & DEBUG_L1OIP_INIT) | ||
| 1371 | printk(KERN_DEBUG "%s: using local port %d remote ip " | ||
| 1372 | "%d.%d.%d.%d port %d ondemand %d\n", __func__, | ||
| 1373 | hc->localport, hc->remoteip >> 24, | ||
| 1374 | (hc->remoteip >> 16) & 0xff, | ||
| 1375 | (hc->remoteip >> 8) & 0xff, hc->remoteip & 0xff, | ||
| 1376 | hc->remoteport, hc->ondemand); | ||
| 1377 | |||
| 1378 | dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL); | ||
| 1379 | if (!dch) | ||
| 1380 | return -ENOMEM; | ||
| 1381 | dch->debug = debug; | ||
| 1382 | mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, NULL); | ||
| 1383 | dch->hw = hc; | ||
| 1384 | if (pri) | ||
| 1385 | dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1); | ||
| 1386 | else | ||
| 1387 | dch->dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0); | ||
| 1388 | dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | | ||
| 1389 | (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); | ||
| 1390 | dch->dev.D.send = handle_dmsg; | ||
| 1391 | dch->dev.D.ctrl = l1oip_dctrl; | ||
| 1392 | dch->dev.nrbchan = hc->b_num; | ||
| 1393 | dch->slot = hc->d_idx; | ||
| 1394 | hc->chan[hc->d_idx].dch = dch; | ||
| 1395 | i = 1; | ||
| 1396 | for (ch = 0; ch < dch->dev.nrbchan; ch++) { | ||
| 1397 | if (ch == 15) | ||
| 1398 | i++; | ||
| 1399 | bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL); | ||
| 1400 | if (!bch) { | ||
| 1401 | printk(KERN_ERR "%s: no memory for bchannel\n", | ||
| 1402 | __func__); | ||
| 1403 | return -ENOMEM; | ||
| 1404 | } | ||
| 1405 | bch->nr = i + ch; | ||
| 1406 | bch->slot = i + ch; | ||
| 1407 | bch->debug = debug; | ||
| 1408 | mISDN_initbchannel(bch, MAX_DATA_MEM); | ||
| 1409 | bch->hw = hc; | ||
| 1410 | bch->ch.send = handle_bmsg; | ||
| 1411 | bch->ch.ctrl = l1oip_bctrl; | ||
| 1412 | bch->ch.nr = i + ch; | ||
| 1413 | list_add(&bch->ch.list, &dch->dev.bchannels); | ||
| 1414 | hc->chan[i + ch].bch = bch; | ||
| 1415 | test_and_set_bit(bch->nr & 0x1f, | ||
| 1416 | &dch->dev.channelmap[bch->nr >> 5]); | ||
| 1417 | } | ||
| 1418 | ret = mISDN_register_device(&dch->dev, hc->name); | ||
| 1419 | if (ret) | ||
| 1420 | return ret; | ||
| 1421 | hc->registered = 1; | ||
| 1422 | |||
| 1423 | if (debug & DEBUG_L1OIP_INIT) | ||
| 1424 | printk(KERN_DEBUG "%s: Setting up network card(%d)\n", | ||
| 1425 | __func__, l1oip_cnt + 1); | ||
| 1426 | ret = l1oip_socket_open(hc); | ||
| 1427 | if (ret) | ||
| 1428 | return ret; | ||
| 1429 | |||
| 1430 | hc->keep_tl.function = (void *)l1oip_keepalive; | ||
| 1431 | hc->keep_tl.data = (ulong)hc; | ||
| 1432 | init_timer(&hc->keep_tl); | ||
| 1433 | hc->keep_tl.expires = jiffies + 2*HZ; /* two seconds first time */ | ||
| 1434 | add_timer(&hc->keep_tl); | ||
| 1435 | |||
| 1436 | hc->timeout_tl.function = (void *)l1oip_timeout; | ||
| 1437 | hc->timeout_tl.data = (ulong)hc; | ||
| 1438 | init_timer(&hc->timeout_tl); | ||
| 1439 | hc->timeout_on = 0; /* state that we have timer off */ | ||
| 1440 | |||
| 1441 | return 0; | ||
| 1442 | } | ||
| 1443 | |||
| 1444 | static int __init | ||
| 1445 | l1oip_init(void) | ||
| 1446 | { | ||
| 1447 | int pri, bundle; | ||
| 1448 | struct l1oip *hc; | ||
| 1449 | int ret; | ||
| 1450 | |||
| 1451 | printk(KERN_INFO "mISDN: Layer-1-over-IP driver Rev. %s\n", | ||
| 1452 | l1oip_revision); | ||
| 1453 | |||
| 1454 | INIT_LIST_HEAD(&l1oip_ilist); | ||
| 1455 | spin_lock_init(&l1oip_lock); | ||
| 1456 | |||
| 1457 | if (l1oip_4bit_alloc(ulaw)) | ||
| 1458 | return -ENOMEM; | ||
| 1459 | |||
| 1460 | l1oip_cnt = 0; | ||
| 1461 | while (type[l1oip_cnt] && l1oip_cnt < MAX_CARDS) { | ||
| 1462 | switch (type[l1oip_cnt] & 0xff) { | ||
| 1463 | case 1: | ||
| 1464 | pri = 0; | ||
| 1465 | bundle = 0; | ||
| 1466 | break; | ||
| 1467 | case 2: | ||
| 1468 | pri = 1; | ||
| 1469 | bundle = 0; | ||
| 1470 | break; | ||
| 1471 | case 3: | ||
| 1472 | pri = 0; | ||
| 1473 | bundle = 1; | ||
| 1474 | break; | ||
| 1475 | case 4: | ||
| 1476 | pri = 1; | ||
| 1477 | bundle = 1; | ||
| 1478 | break; | ||
| 1479 | default: | ||
| 1480 | printk(KERN_ERR "Card type(%d) not supported.\n", | ||
| 1481 | type[l1oip_cnt] & 0xff); | ||
| 1482 | l1oip_cleanup(); | ||
| 1483 | return -EINVAL; | ||
| 1484 | } | ||
| 1485 | |||
| 1486 | if (debug & DEBUG_L1OIP_INIT) | ||
| 1487 | printk(KERN_DEBUG "%s: interface %d is %s with %s.\n", | ||
| 1488 | __func__, l1oip_cnt, pri?"PRI":"BRI", | ||
| 1489 | bundle?"bundled IP packet for all B-channels" | ||
| 1490 | :"seperate IP packets for every B-channel"); | ||
| 1491 | |||
| 1492 | hc = kzalloc(sizeof(struct l1oip), GFP_ATOMIC); | ||
| 1493 | if (!hc) { | ||
| 1494 | printk(KERN_ERR "No kmem for L1-over-IP driver.\n"); | ||
| 1495 | l1oip_cleanup(); | ||
| 1496 | return -ENOMEM; | ||
| 1497 | } | ||
| 1498 | INIT_WORK(&hc->workq, (void *)l1oip_send_bh); | ||
| 1499 | |||
| 1500 | spin_lock(&l1oip_lock); | ||
| 1501 | list_add_tail(&hc->list, &l1oip_ilist); | ||
| 1502 | spin_unlock(&l1oip_lock); | ||
| 1503 | |||
| 1504 | ret = init_card(hc, pri, bundle); | ||
| 1505 | if (ret) { | ||
| 1506 | l1oip_cleanup(); | ||
| 1507 | return ret; | ||
| 1508 | } | ||
| 1509 | |||
| 1510 | l1oip_cnt++; | ||
| 1511 | } | ||
| 1512 | printk(KERN_INFO "%d virtual devices registered\n", l1oip_cnt); | ||
| 1513 | return 0; | ||
| 1514 | } | ||
| 1515 | |||
| 1516 | module_init(l1oip_init); | ||
| 1517 | module_exit(l1oip_cleanup); | ||
| 1518 | |||
diff --git a/drivers/isdn/mISDN/layer1.c b/drivers/isdn/mISDN/layer1.c new file mode 100644 index 000000000000..fced1a2755f8 --- /dev/null +++ b/drivers/isdn/mISDN/layer1.c | |||
| @@ -0,0 +1,403 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * Author Karsten Keil <kkeil@novell.com> | ||
| 4 | * | ||
| 5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | |||
| 19 | #include <linux/module.h> | ||
| 20 | #include <linux/mISDNhw.h> | ||
| 21 | #include "layer1.h" | ||
| 22 | #include "fsm.h" | ||
| 23 | |||
| 24 | static int *debug; | ||
| 25 | |||
| 26 | struct layer1 { | ||
| 27 | u_long Flags; | ||
| 28 | struct FsmInst l1m; | ||
| 29 | struct FsmTimer timer; | ||
| 30 | int delay; | ||
| 31 | struct dchannel *dch; | ||
| 32 | dchannel_l1callback *dcb; | ||
| 33 | }; | ||
| 34 | |||
| 35 | #define TIMER3_VALUE 7000 | ||
| 36 | |||
| 37 | static | ||
| 38 | struct Fsm l1fsm_s = {NULL, 0, 0, NULL, NULL}; | ||
| 39 | |||
| 40 | enum { | ||
| 41 | ST_L1_F2, | ||
| 42 | ST_L1_F3, | ||
| 43 | ST_L1_F4, | ||
| 44 | ST_L1_F5, | ||
| 45 | ST_L1_F6, | ||
| 46 | ST_L1_F7, | ||
| 47 | ST_L1_F8, | ||
| 48 | }; | ||
| 49 | |||
| 50 | #define L1S_STATE_COUNT (ST_L1_F8+1) | ||
| 51 | |||
| 52 | static char *strL1SState[] = | ||
| 53 | { | ||
| 54 | "ST_L1_F2", | ||
| 55 | "ST_L1_F3", | ||
| 56 | "ST_L1_F4", | ||
| 57 | "ST_L1_F5", | ||
| 58 | "ST_L1_F6", | ||
| 59 | "ST_L1_F7", | ||
| 60 | "ST_L1_F8", | ||
| 61 | }; | ||
| 62 | |||
| 63 | enum { | ||
| 64 | EV_PH_ACTIVATE, | ||
| 65 | EV_PH_DEACTIVATE, | ||
| 66 | EV_RESET_IND, | ||
| 67 | EV_DEACT_CNF, | ||
| 68 | EV_DEACT_IND, | ||
| 69 | EV_POWER_UP, | ||
| 70 | EV_ANYSIG_IND, | ||
| 71 | EV_INFO2_IND, | ||
| 72 | EV_INFO4_IND, | ||
| 73 | EV_TIMER_DEACT, | ||
| 74 | EV_TIMER_ACT, | ||
| 75 | EV_TIMER3, | ||
| 76 | }; | ||
| 77 | |||
| 78 | #define L1_EVENT_COUNT (EV_TIMER3 + 1) | ||
| 79 | |||
| 80 | static char *strL1Event[] = | ||
| 81 | { | ||
| 82 | "EV_PH_ACTIVATE", | ||
| 83 | "EV_PH_DEACTIVATE", | ||
| 84 | "EV_RESET_IND", | ||
| 85 | "EV_DEACT_CNF", | ||
| 86 | "EV_DEACT_IND", | ||
| 87 | "EV_POWER_UP", | ||
| 88 | "EV_ANYSIG_IND", | ||
| 89 | "EV_INFO2_IND", | ||
| 90 | "EV_INFO4_IND", | ||
| 91 | "EV_TIMER_DEACT", | ||
| 92 | "EV_TIMER_ACT", | ||
| 93 | "EV_TIMER3", | ||
| 94 | }; | ||
| 95 | |||
| 96 | static void | ||
| 97 | l1m_debug(struct FsmInst *fi, char *fmt, ...) | ||
| 98 | { | ||
| 99 | struct layer1 *l1 = fi->userdata; | ||
| 100 | va_list va; | ||
| 101 | |||
| 102 | va_start(va, fmt); | ||
| 103 | printk(KERN_DEBUG "%s: ", l1->dch->dev.name); | ||
| 104 | vprintk(fmt, va); | ||
| 105 | printk("\n"); | ||
| 106 | va_end(va); | ||
| 107 | } | ||
| 108 | |||
| 109 | static void | ||
| 110 | l1_reset(struct FsmInst *fi, int event, void *arg) | ||
| 111 | { | ||
| 112 | mISDN_FsmChangeState(fi, ST_L1_F3); | ||
| 113 | } | ||
| 114 | |||
| 115 | static void | ||
| 116 | l1_deact_cnf(struct FsmInst *fi, int event, void *arg) | ||
| 117 | { | ||
| 118 | struct layer1 *l1 = fi->userdata; | ||
| 119 | |||
| 120 | mISDN_FsmChangeState(fi, ST_L1_F3); | ||
| 121 | if (test_bit(FLG_L1_ACTIVATING, &l1->Flags)) | ||
| 122 | l1->dcb(l1->dch, HW_POWERUP_REQ); | ||
| 123 | } | ||
| 124 | |||
| 125 | static void | ||
| 126 | l1_deact_req_s(struct FsmInst *fi, int event, void *arg) | ||
| 127 | { | ||
| 128 | struct layer1 *l1 = fi->userdata; | ||
| 129 | |||
| 130 | mISDN_FsmChangeState(fi, ST_L1_F3); | ||
| 131 | mISDN_FsmRestartTimer(&l1->timer, 550, EV_TIMER_DEACT, NULL, 2); | ||
| 132 | test_and_set_bit(FLG_L1_DEACTTIMER, &l1->Flags); | ||
| 133 | } | ||
| 134 | |||
| 135 | static void | ||
| 136 | l1_power_up_s(struct FsmInst *fi, int event, void *arg) | ||
| 137 | { | ||
| 138 | struct layer1 *l1 = fi->userdata; | ||
| 139 | |||
| 140 | if (test_bit(FLG_L1_ACTIVATING, &l1->Flags)) { | ||
| 141 | mISDN_FsmChangeState(fi, ST_L1_F4); | ||
| 142 | l1->dcb(l1->dch, INFO3_P8); | ||
| 143 | } else | ||
| 144 | mISDN_FsmChangeState(fi, ST_L1_F3); | ||
| 145 | } | ||
| 146 | |||
| 147 | static void | ||
| 148 | l1_go_F5(struct FsmInst *fi, int event, void *arg) | ||
| 149 | { | ||
| 150 | mISDN_FsmChangeState(fi, ST_L1_F5); | ||
| 151 | } | ||
| 152 | |||
| 153 | static void | ||
| 154 | l1_go_F8(struct FsmInst *fi, int event, void *arg) | ||
| 155 | { | ||
| 156 | mISDN_FsmChangeState(fi, ST_L1_F8); | ||
| 157 | } | ||
| 158 | |||
| 159 | static void | ||
| 160 | l1_info2_ind(struct FsmInst *fi, int event, void *arg) | ||
| 161 | { | ||
| 162 | struct layer1 *l1 = fi->userdata; | ||
| 163 | |||
| 164 | mISDN_FsmChangeState(fi, ST_L1_F6); | ||
| 165 | l1->dcb(l1->dch, INFO3_P8); | ||
| 166 | } | ||
| 167 | |||
| 168 | static void | ||
| 169 | l1_info4_ind(struct FsmInst *fi, int event, void *arg) | ||
| 170 | { | ||
| 171 | struct layer1 *l1 = fi->userdata; | ||
| 172 | |||
| 173 | mISDN_FsmChangeState(fi, ST_L1_F7); | ||
| 174 | l1->dcb(l1->dch, INFO3_P8); | ||
| 175 | if (test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags)) | ||
| 176 | mISDN_FsmDelTimer(&l1->timer, 4); | ||
| 177 | if (!test_bit(FLG_L1_ACTIVATED, &l1->Flags)) { | ||
| 178 | if (test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags)) | ||
| 179 | mISDN_FsmDelTimer(&l1->timer, 3); | ||
| 180 | mISDN_FsmRestartTimer(&l1->timer, 110, EV_TIMER_ACT, NULL, 2); | ||
| 181 | test_and_set_bit(FLG_L1_ACTTIMER, &l1->Flags); | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | static void | ||
| 186 | l1_timer3(struct FsmInst *fi, int event, void *arg) | ||
| 187 | { | ||
| 188 | struct layer1 *l1 = fi->userdata; | ||
| 189 | |||
| 190 | test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags); | ||
| 191 | if (test_and_clear_bit(FLG_L1_ACTIVATING, &l1->Flags)) { | ||
| 192 | if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags)) | ||
| 193 | l1->dcb(l1->dch, HW_D_NOBLOCKED); | ||
| 194 | l1->dcb(l1->dch, PH_DEACTIVATE_IND); | ||
| 195 | } | ||
| 196 | if (l1->l1m.state != ST_L1_F6) { | ||
| 197 | mISDN_FsmChangeState(fi, ST_L1_F3); | ||
| 198 | l1->dcb(l1->dch, HW_POWERUP_REQ); | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | static void | ||
| 203 | l1_timer_act(struct FsmInst *fi, int event, void *arg) | ||
| 204 | { | ||
| 205 | struct layer1 *l1 = fi->userdata; | ||
| 206 | |||
| 207 | test_and_clear_bit(FLG_L1_ACTTIMER, &l1->Flags); | ||
| 208 | test_and_set_bit(FLG_L1_ACTIVATED, &l1->Flags); | ||
| 209 | l1->dcb(l1->dch, PH_ACTIVATE_IND); | ||
| 210 | } | ||
| 211 | |||
| 212 | static void | ||
| 213 | l1_timer_deact(struct FsmInst *fi, int event, void *arg) | ||
| 214 | { | ||
| 215 | struct layer1 *l1 = fi->userdata; | ||
| 216 | |||
| 217 | test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags); | ||
| 218 | test_and_clear_bit(FLG_L1_ACTIVATED, &l1->Flags); | ||
| 219 | if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags)) | ||
| 220 | l1->dcb(l1->dch, HW_D_NOBLOCKED); | ||
| 221 | l1->dcb(l1->dch, PH_DEACTIVATE_IND); | ||
| 222 | l1->dcb(l1->dch, HW_DEACT_REQ); | ||
| 223 | } | ||
| 224 | |||
| 225 | static void | ||
| 226 | l1_activate_s(struct FsmInst *fi, int event, void *arg) | ||
| 227 | { | ||
| 228 | struct layer1 *l1 = fi->userdata; | ||
| 229 | |||
| 230 | mISDN_FsmRestartTimer(&l1->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); | ||
| 231 | test_and_set_bit(FLG_L1_T3RUN, &l1->Flags); | ||
| 232 | l1->dcb(l1->dch, HW_RESET_REQ); | ||
| 233 | } | ||
| 234 | |||
| 235 | static void | ||
| 236 | l1_activate_no(struct FsmInst *fi, int event, void *arg) | ||
| 237 | { | ||
| 238 | struct layer1 *l1 = fi->userdata; | ||
| 239 | |||
| 240 | if ((!test_bit(FLG_L1_DEACTTIMER, &l1->Flags)) && | ||
| 241 | (!test_bit(FLG_L1_T3RUN, &l1->Flags))) { | ||
| 242 | test_and_clear_bit(FLG_L1_ACTIVATING, &l1->Flags); | ||
| 243 | if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags)) | ||
| 244 | l1->dcb(l1->dch, HW_D_NOBLOCKED); | ||
| 245 | l1->dcb(l1->dch, PH_DEACTIVATE_IND); | ||
| 246 | } | ||
| 247 | } | ||
| 248 | |||
| 249 | static struct FsmNode L1SFnList[] = | ||
| 250 | { | ||
| 251 | {ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s}, | ||
| 252 | {ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no}, | ||
| 253 | {ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no}, | ||
| 254 | {ST_L1_F3, EV_RESET_IND, l1_reset}, | ||
| 255 | {ST_L1_F4, EV_RESET_IND, l1_reset}, | ||
| 256 | {ST_L1_F5, EV_RESET_IND, l1_reset}, | ||
| 257 | {ST_L1_F6, EV_RESET_IND, l1_reset}, | ||
| 258 | {ST_L1_F7, EV_RESET_IND, l1_reset}, | ||
| 259 | {ST_L1_F8, EV_RESET_IND, l1_reset}, | ||
| 260 | {ST_L1_F3, EV_DEACT_CNF, l1_deact_cnf}, | ||
| 261 | {ST_L1_F4, EV_DEACT_CNF, l1_deact_cnf}, | ||
| 262 | {ST_L1_F5, EV_DEACT_CNF, l1_deact_cnf}, | ||
| 263 | {ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf}, | ||
| 264 | {ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf}, | ||
| 265 | {ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf}, | ||
| 266 | {ST_L1_F6, EV_DEACT_IND, l1_deact_req_s}, | ||
| 267 | {ST_L1_F7, EV_DEACT_IND, l1_deact_req_s}, | ||
| 268 | {ST_L1_F8, EV_DEACT_IND, l1_deact_req_s}, | ||
| 269 | {ST_L1_F3, EV_POWER_UP, l1_power_up_s}, | ||
| 270 | {ST_L1_F4, EV_ANYSIG_IND, l1_go_F5}, | ||
| 271 | {ST_L1_F6, EV_ANYSIG_IND, l1_go_F8}, | ||
| 272 | {ST_L1_F7, EV_ANYSIG_IND, l1_go_F8}, | ||
| 273 | {ST_L1_F3, EV_INFO2_IND, l1_info2_ind}, | ||
| 274 | {ST_L1_F4, EV_INFO2_IND, l1_info2_ind}, | ||
| 275 | {ST_L1_F5, EV_INFO2_IND, l1_info2_ind}, | ||
| 276 | {ST_L1_F7, EV_INFO2_IND, l1_info2_ind}, | ||
| 277 | {ST_L1_F8, EV_INFO2_IND, l1_info2_ind}, | ||
| 278 | {ST_L1_F3, EV_INFO4_IND, l1_info4_ind}, | ||
| 279 | {ST_L1_F4, EV_INFO4_IND, l1_info4_ind}, | ||
| 280 | {ST_L1_F5, EV_INFO4_IND, l1_info4_ind}, | ||
| 281 | {ST_L1_F6, EV_INFO4_IND, l1_info4_ind}, | ||
| 282 | {ST_L1_F8, EV_INFO4_IND, l1_info4_ind}, | ||
| 283 | {ST_L1_F3, EV_TIMER3, l1_timer3}, | ||
| 284 | {ST_L1_F4, EV_TIMER3, l1_timer3}, | ||
| 285 | {ST_L1_F5, EV_TIMER3, l1_timer3}, | ||
| 286 | {ST_L1_F6, EV_TIMER3, l1_timer3}, | ||
| 287 | {ST_L1_F8, EV_TIMER3, l1_timer3}, | ||
| 288 | {ST_L1_F7, EV_TIMER_ACT, l1_timer_act}, | ||
| 289 | {ST_L1_F3, EV_TIMER_DEACT, l1_timer_deact}, | ||
| 290 | {ST_L1_F4, EV_TIMER_DEACT, l1_timer_deact}, | ||
| 291 | {ST_L1_F5, EV_TIMER_DEACT, l1_timer_deact}, | ||
| 292 | {ST_L1_F6, EV_TIMER_DEACT, l1_timer_deact}, | ||
| 293 | {ST_L1_F7, EV_TIMER_DEACT, l1_timer_deact}, | ||
| 294 | {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact}, | ||
| 295 | }; | ||
| 296 | |||
| 297 | static void | ||
| 298 | release_l1(struct layer1 *l1) { | ||
| 299 | mISDN_FsmDelTimer(&l1->timer, 0); | ||
| 300 | if (l1->dch) | ||
| 301 | l1->dch->l1 = NULL; | ||
| 302 | module_put(THIS_MODULE); | ||
| 303 | kfree(l1); | ||
| 304 | } | ||
| 305 | |||
| 306 | int | ||
| 307 | l1_event(struct layer1 *l1, u_int event) | ||
| 308 | { | ||
| 309 | int err = 0; | ||
| 310 | |||
| 311 | if (!l1) | ||
| 312 | return -EINVAL; | ||
| 313 | switch (event) { | ||
| 314 | case HW_RESET_IND: | ||
| 315 | mISDN_FsmEvent(&l1->l1m, EV_RESET_IND, NULL); | ||
| 316 | break; | ||
| 317 | case HW_DEACT_IND: | ||
| 318 | mISDN_FsmEvent(&l1->l1m, EV_DEACT_IND, NULL); | ||
| 319 | break; | ||
| 320 | case HW_POWERUP_IND: | ||
| 321 | mISDN_FsmEvent(&l1->l1m, EV_POWER_UP, NULL); | ||
| 322 | break; | ||
| 323 | case HW_DEACT_CNF: | ||
| 324 | mISDN_FsmEvent(&l1->l1m, EV_DEACT_CNF, NULL); | ||
| 325 | break; | ||
| 326 | case ANYSIGNAL: | ||
| 327 | mISDN_FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL); | ||
| 328 | break; | ||
| 329 | case LOSTFRAMING: | ||
| 330 | mISDN_FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL); | ||
| 331 | break; | ||
| 332 | case INFO2: | ||
| 333 | mISDN_FsmEvent(&l1->l1m, EV_INFO2_IND, NULL); | ||
| 334 | break; | ||
| 335 | case INFO4_P8: | ||
| 336 | mISDN_FsmEvent(&l1->l1m, EV_INFO4_IND, NULL); | ||
| 337 | break; | ||
| 338 | case INFO4_P10: | ||
| 339 | mISDN_FsmEvent(&l1->l1m, EV_INFO4_IND, NULL); | ||
| 340 | break; | ||
| 341 | case PH_ACTIVATE_REQ: | ||
| 342 | if (test_bit(FLG_L1_ACTIVATED, &l1->Flags)) | ||
| 343 | l1->dcb(l1->dch, PH_ACTIVATE_IND); | ||
| 344 | else { | ||
| 345 | test_and_set_bit(FLG_L1_ACTIVATING, &l1->Flags); | ||
| 346 | mISDN_FsmEvent(&l1->l1m, EV_PH_ACTIVATE, NULL); | ||
| 347 | } | ||
| 348 | break; | ||
| 349 | case CLOSE_CHANNEL: | ||
| 350 | release_l1(l1); | ||
| 351 | break; | ||
| 352 | default: | ||
| 353 | if (*debug & DEBUG_L1) | ||
| 354 | printk(KERN_DEBUG "%s %x unhandled\n", | ||
| 355 | __func__, event); | ||
| 356 | err = -EINVAL; | ||
| 357 | } | ||
| 358 | return err; | ||
| 359 | } | ||
| 360 | EXPORT_SYMBOL(l1_event); | ||
| 361 | |||
| 362 | int | ||
| 363 | create_l1(struct dchannel *dch, dchannel_l1callback *dcb) { | ||
| 364 | struct layer1 *nl1; | ||
| 365 | |||
| 366 | nl1 = kzalloc(sizeof(struct layer1), GFP_ATOMIC); | ||
| 367 | if (!nl1) { | ||
| 368 | printk(KERN_ERR "kmalloc struct layer1 failed\n"); | ||
| 369 | return -ENOMEM; | ||
| 370 | } | ||
| 371 | nl1->l1m.fsm = &l1fsm_s; | ||
| 372 | nl1->l1m.state = ST_L1_F3; | ||
| 373 | nl1->Flags = 0; | ||
| 374 | nl1->l1m.debug = *debug & DEBUG_L1_FSM; | ||
| 375 | nl1->l1m.userdata = nl1; | ||
| 376 | nl1->l1m.userint = 0; | ||
| 377 | nl1->l1m.printdebug = l1m_debug; | ||
| 378 | nl1->dch = dch; | ||
| 379 | nl1->dcb = dcb; | ||
| 380 | mISDN_FsmInitTimer(&nl1->l1m, &nl1->timer); | ||
| 381 | __module_get(THIS_MODULE); | ||
| 382 | dch->l1 = nl1; | ||
| 383 | return 0; | ||
| 384 | } | ||
| 385 | EXPORT_SYMBOL(create_l1); | ||
| 386 | |||
| 387 | int | ||
| 388 | l1_init(u_int *deb) | ||
| 389 | { | ||
| 390 | debug = deb; | ||
| 391 | l1fsm_s.state_count = L1S_STATE_COUNT; | ||
| 392 | l1fsm_s.event_count = L1_EVENT_COUNT; | ||
| 393 | l1fsm_s.strEvent = strL1Event; | ||
| 394 | l1fsm_s.strState = strL1SState; | ||
| 395 | mISDN_FsmNew(&l1fsm_s, L1SFnList, ARRAY_SIZE(L1SFnList)); | ||
| 396 | return 0; | ||
| 397 | } | ||
| 398 | |||
| 399 | void | ||
| 400 | l1_cleanup(void) | ||
| 401 | { | ||
| 402 | mISDN_FsmFree(&l1fsm_s); | ||
| 403 | } | ||
diff --git a/drivers/isdn/mISDN/layer1.h b/drivers/isdn/mISDN/layer1.h new file mode 100644 index 000000000000..9c8125fd89af --- /dev/null +++ b/drivers/isdn/mISDN/layer1.h | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * Layer 1 defines | ||
| 4 | * | ||
| 5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #define FLG_L1_ACTIVATING 1 | ||
| 19 | #define FLG_L1_ACTIVATED 2 | ||
| 20 | #define FLG_L1_DEACTTIMER 3 | ||
| 21 | #define FLG_L1_ACTTIMER 4 | ||
| 22 | #define FLG_L1_T3RUN 5 | ||
| 23 | #define FLG_L1_PULL_REQ 6 | ||
| 24 | #define FLG_L1_UINT 7 | ||
| 25 | #define FLG_L1_DBLOCKED 8 | ||
| 26 | |||
diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c new file mode 100644 index 000000000000..a7915a156c04 --- /dev/null +++ b/drivers/isdn/mISDN/layer2.c | |||
| @@ -0,0 +1,2216 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * Author Karsten Keil <kkeil@novell.com> | ||
| 4 | * | ||
| 5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include "fsm.h" | ||
| 19 | #include "layer2.h" | ||
| 20 | |||
| 21 | static int *debug; | ||
| 22 | |||
| 23 | static | ||
| 24 | struct Fsm l2fsm = {NULL, 0, 0, NULL, NULL}; | ||
| 25 | |||
| 26 | static char *strL2State[] = | ||
| 27 | { | ||
| 28 | "ST_L2_1", | ||
| 29 | "ST_L2_2", | ||
| 30 | "ST_L2_3", | ||
| 31 | "ST_L2_4", | ||
| 32 | "ST_L2_5", | ||
| 33 | "ST_L2_6", | ||
| 34 | "ST_L2_7", | ||
| 35 | "ST_L2_8", | ||
| 36 | }; | ||
| 37 | |||
| 38 | enum { | ||
| 39 | EV_L2_UI, | ||
| 40 | EV_L2_SABME, | ||
| 41 | EV_L2_DISC, | ||
| 42 | EV_L2_DM, | ||
| 43 | EV_L2_UA, | ||
| 44 | EV_L2_FRMR, | ||
| 45 | EV_L2_SUPER, | ||
| 46 | EV_L2_I, | ||
| 47 | EV_L2_DL_DATA, | ||
| 48 | EV_L2_ACK_PULL, | ||
| 49 | EV_L2_DL_UNITDATA, | ||
| 50 | EV_L2_DL_ESTABLISH_REQ, | ||
| 51 | EV_L2_DL_RELEASE_REQ, | ||
| 52 | EV_L2_MDL_ASSIGN, | ||
| 53 | EV_L2_MDL_REMOVE, | ||
| 54 | EV_L2_MDL_ERROR, | ||
| 55 | EV_L1_DEACTIVATE, | ||
| 56 | EV_L2_T200, | ||
| 57 | EV_L2_T203, | ||
| 58 | EV_L2_SET_OWN_BUSY, | ||
| 59 | EV_L2_CLEAR_OWN_BUSY, | ||
| 60 | EV_L2_FRAME_ERROR, | ||
| 61 | }; | ||
| 62 | |||
| 63 | #define L2_EVENT_COUNT (EV_L2_FRAME_ERROR+1) | ||
| 64 | |||
| 65 | static char *strL2Event[] = | ||
| 66 | { | ||
| 67 | "EV_L2_UI", | ||
| 68 | "EV_L2_SABME", | ||
| 69 | "EV_L2_DISC", | ||
| 70 | "EV_L2_DM", | ||
| 71 | "EV_L2_UA", | ||
| 72 | "EV_L2_FRMR", | ||
| 73 | "EV_L2_SUPER", | ||
| 74 | "EV_L2_I", | ||
| 75 | "EV_L2_DL_DATA", | ||
| 76 | "EV_L2_ACK_PULL", | ||
| 77 | "EV_L2_DL_UNITDATA", | ||
| 78 | "EV_L2_DL_ESTABLISH_REQ", | ||
| 79 | "EV_L2_DL_RELEASE_REQ", | ||
| 80 | "EV_L2_MDL_ASSIGN", | ||
| 81 | "EV_L2_MDL_REMOVE", | ||
| 82 | "EV_L2_MDL_ERROR", | ||
| 83 | "EV_L1_DEACTIVATE", | ||
| 84 | "EV_L2_T200", | ||
| 85 | "EV_L2_T203", | ||
| 86 | "EV_L2_SET_OWN_BUSY", | ||
| 87 | "EV_L2_CLEAR_OWN_BUSY", | ||
| 88 | "EV_L2_FRAME_ERROR", | ||
| 89 | }; | ||
| 90 | |||
| 91 | static void | ||
| 92 | l2m_debug(struct FsmInst *fi, char *fmt, ...) | ||
| 93 | { | ||
| 94 | struct layer2 *l2 = fi->userdata; | ||
| 95 | va_list va; | ||
| 96 | |||
| 97 | if (!(*debug & DEBUG_L2_FSM)) | ||
| 98 | return; | ||
| 99 | va_start(va, fmt); | ||
| 100 | printk(KERN_DEBUG "l2 (tei %d): ", l2->tei); | ||
| 101 | vprintk(fmt, va); | ||
| 102 | printk("\n"); | ||
| 103 | va_end(va); | ||
| 104 | } | ||
| 105 | |||
| 106 | inline u_int | ||
| 107 | l2headersize(struct layer2 *l2, int ui) | ||
| 108 | { | ||
| 109 | return ((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) + | ||
| 110 | (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1); | ||
| 111 | } | ||
| 112 | |||
| 113 | inline u_int | ||
| 114 | l2addrsize(struct layer2 *l2) | ||
| 115 | { | ||
| 116 | return test_bit(FLG_LAPD, &l2->flag) ? 2 : 1; | ||
| 117 | } | ||
| 118 | |||
| 119 | static u_int | ||
| 120 | l2_newid(struct layer2 *l2) | ||
| 121 | { | ||
| 122 | u_int id; | ||
| 123 | |||
| 124 | id = l2->next_id++; | ||
| 125 | if (id == 0x7fff) | ||
| 126 | l2->next_id = 1; | ||
| 127 | id <<= 16; | ||
| 128 | id |= l2->tei << 8; | ||
| 129 | id |= l2->sapi; | ||
| 130 | return id; | ||
| 131 | } | ||
| 132 | |||
| 133 | static void | ||
| 134 | l2up(struct layer2 *l2, u_int prim, struct sk_buff *skb) | ||
| 135 | { | ||
| 136 | int err; | ||
| 137 | |||
| 138 | if (!l2->up) | ||
| 139 | return; | ||
| 140 | mISDN_HEAD_PRIM(skb) = prim; | ||
| 141 | mISDN_HEAD_ID(skb) = (l2->ch.nr << 16) | l2->ch.addr; | ||
| 142 | err = l2->up->send(l2->up, skb); | ||
| 143 | if (err) { | ||
| 144 | printk(KERN_WARNING "%s: err=%d\n", __func__, err); | ||
| 145 | dev_kfree_skb(skb); | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | static void | ||
| 150 | l2up_create(struct layer2 *l2, u_int prim, int len, void *arg) | ||
| 151 | { | ||
| 152 | struct sk_buff *skb; | ||
| 153 | struct mISDNhead *hh; | ||
| 154 | int err; | ||
| 155 | |||
| 156 | if (!l2->up) | ||
| 157 | return; | ||
| 158 | skb = mI_alloc_skb(len, GFP_ATOMIC); | ||
| 159 | if (!skb) | ||
| 160 | return; | ||
| 161 | hh = mISDN_HEAD_P(skb); | ||
| 162 | hh->prim = prim; | ||
| 163 | hh->id = (l2->ch.nr << 16) | l2->ch.addr; | ||
| 164 | if (len) | ||
| 165 | memcpy(skb_put(skb, len), arg, len); | ||
| 166 | err = l2->up->send(l2->up, skb); | ||
| 167 | if (err) { | ||
| 168 | printk(KERN_WARNING "%s: err=%d\n", __func__, err); | ||
| 169 | dev_kfree_skb(skb); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | static int | ||
| 174 | l2down_skb(struct layer2 *l2, struct sk_buff *skb) { | ||
| 175 | int ret; | ||
| 176 | |||
| 177 | ret = l2->ch.recv(l2->ch.peer, skb); | ||
| 178 | if (ret && (*debug & DEBUG_L2_RECV)) | ||
| 179 | printk(KERN_DEBUG "l2down_skb: ret(%d)\n", ret); | ||
| 180 | return ret; | ||
| 181 | } | ||
| 182 | |||
| 183 | static int | ||
| 184 | l2down_raw(struct layer2 *l2, struct sk_buff *skb) | ||
| 185 | { | ||
| 186 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
| 187 | |||
| 188 | if (hh->prim == PH_DATA_REQ) { | ||
| 189 | if (test_and_set_bit(FLG_L1_NOTREADY, &l2->flag)) { | ||
| 190 | skb_queue_tail(&l2->down_queue, skb); | ||
| 191 | return 0; | ||
| 192 | } | ||
| 193 | l2->down_id = mISDN_HEAD_ID(skb); | ||
| 194 | } | ||
| 195 | return l2down_skb(l2, skb); | ||
| 196 | } | ||
| 197 | |||
| 198 | static int | ||
| 199 | l2down(struct layer2 *l2, u_int prim, u_int id, struct sk_buff *skb) | ||
| 200 | { | ||
| 201 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
| 202 | |||
| 203 | hh->prim = prim; | ||
| 204 | hh->id = id; | ||
| 205 | return l2down_raw(l2, skb); | ||
| 206 | } | ||
| 207 | |||
| 208 | static int | ||
| 209 | l2down_create(struct layer2 *l2, u_int prim, u_int id, int len, void *arg) | ||
| 210 | { | ||
| 211 | struct sk_buff *skb; | ||
| 212 | int err; | ||
| 213 | struct mISDNhead *hh; | ||
| 214 | |||
| 215 | skb = mI_alloc_skb(len, GFP_ATOMIC); | ||
| 216 | if (!skb) | ||
| 217 | return -ENOMEM; | ||
| 218 | hh = mISDN_HEAD_P(skb); | ||
| 219 | hh->prim = prim; | ||
| 220 | hh->id = id; | ||
| 221 | if (len) | ||
| 222 | memcpy(skb_put(skb, len), arg, len); | ||
| 223 | err = l2down_raw(l2, skb); | ||
| 224 | if (err) | ||
| 225 | dev_kfree_skb(skb); | ||
| 226 | return err; | ||
| 227 | } | ||
| 228 | |||
| 229 | static int | ||
| 230 | ph_data_confirm(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) { | ||
| 231 | struct sk_buff *nskb = skb; | ||
| 232 | int ret = -EAGAIN; | ||
| 233 | |||
| 234 | if (test_bit(FLG_L1_NOTREADY, &l2->flag)) { | ||
| 235 | if (hh->id == l2->down_id) { | ||
| 236 | nskb = skb_dequeue(&l2->down_queue); | ||
| 237 | if (nskb) { | ||
| 238 | l2->down_id = mISDN_HEAD_ID(nskb); | ||
| 239 | if (l2down_skb(l2, nskb)) { | ||
| 240 | dev_kfree_skb(nskb); | ||
| 241 | l2->down_id = MISDN_ID_NONE; | ||
| 242 | } | ||
| 243 | } else | ||
| 244 | l2->down_id = MISDN_ID_NONE; | ||
| 245 | if (ret) { | ||
| 246 | dev_kfree_skb(skb); | ||
| 247 | ret = 0; | ||
| 248 | } | ||
| 249 | if (l2->down_id == MISDN_ID_NONE) { | ||
| 250 | test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag); | ||
| 251 | mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL); | ||
| 252 | } | ||
| 253 | } | ||
| 254 | } | ||
| 255 | if (!test_and_set_bit(FLG_L1_NOTREADY, &l2->flag)) { | ||
| 256 | nskb = skb_dequeue(&l2->down_queue); | ||
| 257 | if (nskb) { | ||
| 258 | l2->down_id = mISDN_HEAD_ID(nskb); | ||
| 259 | if (l2down_skb(l2, nskb)) { | ||
| 260 | dev_kfree_skb(nskb); | ||
| 261 | l2->down_id = MISDN_ID_NONE; | ||
| 262 | test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag); | ||
| 263 | } | ||
| 264 | } else | ||
| 265 | test_and_clear_bit(FLG_L1_NOTREADY, &l2->flag); | ||
| 266 | } | ||
| 267 | return ret; | ||
| 268 | } | ||
| 269 | |||
| 270 | static int | ||
| 271 | l2mgr(struct layer2 *l2, u_int prim, void *arg) { | ||
| 272 | long c = (long)arg; | ||
| 273 | |||
| 274 | printk(KERN_WARNING | ||
| 275 | "l2mgr: addr:%x prim %x %c\n", l2->id, prim, (char)c); | ||
| 276 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
| 277 | !test_bit(FLG_FIXED_TEI, &l2->flag)) { | ||
| 278 | switch (c) { | ||
| 279 | case 'C': | ||
| 280 | case 'D': | ||
| 281 | case 'G': | ||
| 282 | case 'H': | ||
| 283 | l2_tei(l2, prim, (u_long)arg); | ||
| 284 | break; | ||
| 285 | } | ||
| 286 | } | ||
| 287 | return 0; | ||
| 288 | } | ||
| 289 | |||
| 290 | static void | ||
| 291 | set_peer_busy(struct layer2 *l2) { | ||
| 292 | test_and_set_bit(FLG_PEER_BUSY, &l2->flag); | ||
| 293 | if (skb_queue_len(&l2->i_queue) || skb_queue_len(&l2->ui_queue)) | ||
| 294 | test_and_set_bit(FLG_L2BLOCK, &l2->flag); | ||
| 295 | } | ||
| 296 | |||
| 297 | static void | ||
| 298 | clear_peer_busy(struct layer2 *l2) { | ||
| 299 | if (test_and_clear_bit(FLG_PEER_BUSY, &l2->flag)) | ||
| 300 | test_and_clear_bit(FLG_L2BLOCK, &l2->flag); | ||
| 301 | } | ||
| 302 | |||
| 303 | static void | ||
| 304 | InitWin(struct layer2 *l2) | ||
| 305 | { | ||
| 306 | int i; | ||
| 307 | |||
| 308 | for (i = 0; i < MAX_WINDOW; i++) | ||
| 309 | l2->windowar[i] = NULL; | ||
| 310 | } | ||
| 311 | |||
| 312 | static int | ||
| 313 | freewin(struct layer2 *l2) | ||
| 314 | { | ||
| 315 | int i, cnt = 0; | ||
| 316 | |||
| 317 | for (i = 0; i < MAX_WINDOW; i++) { | ||
| 318 | if (l2->windowar[i]) { | ||
| 319 | cnt++; | ||
| 320 | dev_kfree_skb(l2->windowar[i]); | ||
| 321 | l2->windowar[i] = NULL; | ||
| 322 | } | ||
| 323 | } | ||
| 324 | return cnt; | ||
| 325 | } | ||
| 326 | |||
| 327 | static void | ||
| 328 | ReleaseWin(struct layer2 *l2) | ||
| 329 | { | ||
| 330 | int cnt = freewin(l2); | ||
| 331 | |||
| 332 | if (cnt) | ||
| 333 | printk(KERN_WARNING | ||
| 334 | "isdnl2 freed %d skbuffs in release\n", cnt); | ||
| 335 | } | ||
| 336 | |||
| 337 | inline unsigned int | ||
| 338 | cansend(struct layer2 *l2) | ||
| 339 | { | ||
| 340 | unsigned int p1; | ||
| 341 | |||
| 342 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
| 343 | p1 = (l2->vs - l2->va) % 128; | ||
| 344 | else | ||
| 345 | p1 = (l2->vs - l2->va) % 8; | ||
| 346 | return (p1 < l2->window) && !test_bit(FLG_PEER_BUSY, &l2->flag); | ||
| 347 | } | ||
| 348 | |||
| 349 | inline void | ||
| 350 | clear_exception(struct layer2 *l2) | ||
| 351 | { | ||
| 352 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
| 353 | test_and_clear_bit(FLG_REJEXC, &l2->flag); | ||
| 354 | test_and_clear_bit(FLG_OWN_BUSY, &l2->flag); | ||
| 355 | clear_peer_busy(l2); | ||
| 356 | } | ||
| 357 | |||
| 358 | static int | ||
| 359 | sethdraddr(struct layer2 *l2, u_char *header, int rsp) | ||
| 360 | { | ||
| 361 | u_char *ptr = header; | ||
| 362 | int crbit = rsp; | ||
| 363 | |||
| 364 | if (test_bit(FLG_LAPD, &l2->flag)) { | ||
| 365 | if (test_bit(FLG_LAPD_NET, &l2->flag)) | ||
| 366 | crbit = !crbit; | ||
| 367 | *ptr++ = (l2->sapi << 2) | (crbit ? 2 : 0); | ||
| 368 | *ptr++ = (l2->tei << 1) | 1; | ||
| 369 | return 2; | ||
| 370 | } else { | ||
| 371 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
| 372 | crbit = !crbit; | ||
| 373 | if (crbit) | ||
| 374 | *ptr++ = l2->addr.B; | ||
| 375 | else | ||
| 376 | *ptr++ = l2->addr.A; | ||
| 377 | return 1; | ||
| 378 | } | ||
| 379 | } | ||
| 380 | |||
| 381 | static inline void | ||
| 382 | enqueue_super(struct layer2 *l2, struct sk_buff *skb) | ||
| 383 | { | ||
| 384 | if (l2down(l2, PH_DATA_REQ, l2_newid(l2), skb)) | ||
| 385 | dev_kfree_skb(skb); | ||
| 386 | } | ||
| 387 | |||
| 388 | static inline void | ||
| 389 | enqueue_ui(struct layer2 *l2, struct sk_buff *skb) | ||
| 390 | { | ||
| 391 | if (l2->tm) | ||
| 392 | l2_tei(l2, MDL_STATUS_UI_IND, 0); | ||
| 393 | if (l2down(l2, PH_DATA_REQ, l2_newid(l2), skb)) | ||
| 394 | dev_kfree_skb(skb); | ||
| 395 | } | ||
| 396 | |||
| 397 | inline int | ||
| 398 | IsUI(u_char *data) | ||
| 399 | { | ||
| 400 | return (data[0] & 0xef) == UI; | ||
| 401 | } | ||
| 402 | |||
| 403 | inline int | ||
| 404 | IsUA(u_char *data) | ||
| 405 | { | ||
| 406 | return (data[0] & 0xef) == UA; | ||
| 407 | } | ||
| 408 | |||
| 409 | inline int | ||
| 410 | IsDM(u_char *data) | ||
| 411 | { | ||
| 412 | return (data[0] & 0xef) == DM; | ||
| 413 | } | ||
| 414 | |||
| 415 | inline int | ||
| 416 | IsDISC(u_char *data) | ||
| 417 | { | ||
| 418 | return (data[0] & 0xef) == DISC; | ||
| 419 | } | ||
| 420 | |||
| 421 | inline int | ||
| 422 | IsRR(u_char *data, struct layer2 *l2) | ||
| 423 | { | ||
| 424 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
| 425 | return data[0] == RR; | ||
| 426 | else | ||
| 427 | return (data[0] & 0xf) == 1; | ||
| 428 | } | ||
| 429 | |||
| 430 | inline int | ||
| 431 | IsSFrame(u_char *data, struct layer2 *l2) | ||
| 432 | { | ||
| 433 | register u_char d = *data; | ||
| 434 | |||
| 435 | if (!test_bit(FLG_MOD128, &l2->flag)) | ||
| 436 | d &= 0xf; | ||
| 437 | return ((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c); | ||
| 438 | } | ||
| 439 | |||
| 440 | inline int | ||
| 441 | IsSABME(u_char *data, struct layer2 *l2) | ||
| 442 | { | ||
| 443 | u_char d = data[0] & ~0x10; | ||
| 444 | |||
| 445 | return test_bit(FLG_MOD128, &l2->flag) ? d == SABME : d == SABM; | ||
| 446 | } | ||
| 447 | |||
| 448 | inline int | ||
| 449 | IsREJ(u_char *data, struct layer2 *l2) | ||
| 450 | { | ||
| 451 | return test_bit(FLG_MOD128, &l2->flag) ? | ||
| 452 | data[0] == REJ : (data[0] & 0xf) == REJ; | ||
| 453 | } | ||
| 454 | |||
| 455 | inline int | ||
| 456 | IsFRMR(u_char *data) | ||
| 457 | { | ||
| 458 | return (data[0] & 0xef) == FRMR; | ||
| 459 | } | ||
| 460 | |||
| 461 | inline int | ||
| 462 | IsRNR(u_char *data, struct layer2 *l2) | ||
| 463 | { | ||
| 464 | return test_bit(FLG_MOD128, &l2->flag) ? | ||
| 465 | data[0] == RNR : (data[0] & 0xf) == RNR; | ||
| 466 | } | ||
| 467 | |||
| 468 | int | ||
| 469 | iframe_error(struct layer2 *l2, struct sk_buff *skb) | ||
| 470 | { | ||
| 471 | u_int i; | ||
| 472 | int rsp = *skb->data & 0x2; | ||
| 473 | |||
| 474 | i = l2addrsize(l2) + (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1); | ||
| 475 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
| 476 | rsp = !rsp; | ||
| 477 | if (rsp) | ||
| 478 | return 'L'; | ||
| 479 | if (skb->len < i) | ||
| 480 | return 'N'; | ||
| 481 | if ((skb->len - i) > l2->maxlen) | ||
| 482 | return 'O'; | ||
| 483 | return 0; | ||
| 484 | } | ||
| 485 | |||
| 486 | int | ||
| 487 | super_error(struct layer2 *l2, struct sk_buff *skb) | ||
| 488 | { | ||
| 489 | if (skb->len != l2addrsize(l2) + | ||
| 490 | (test_bit(FLG_MOD128, &l2->flag) ? 2 : 1)) | ||
| 491 | return 'N'; | ||
| 492 | return 0; | ||
| 493 | } | ||
| 494 | |||
| 495 | int | ||
| 496 | unnum_error(struct layer2 *l2, struct sk_buff *skb, int wantrsp) | ||
| 497 | { | ||
| 498 | int rsp = (*skb->data & 0x2) >> 1; | ||
| 499 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
| 500 | rsp = !rsp; | ||
| 501 | if (rsp != wantrsp) | ||
| 502 | return 'L'; | ||
| 503 | if (skb->len != l2addrsize(l2) + 1) | ||
| 504 | return 'N'; | ||
| 505 | return 0; | ||
| 506 | } | ||
| 507 | |||
| 508 | int | ||
| 509 | UI_error(struct layer2 *l2, struct sk_buff *skb) | ||
| 510 | { | ||
| 511 | int rsp = *skb->data & 0x2; | ||
| 512 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
| 513 | rsp = !rsp; | ||
| 514 | if (rsp) | ||
| 515 | return 'L'; | ||
| 516 | if (skb->len > l2->maxlen + l2addrsize(l2) + 1) | ||
| 517 | return 'O'; | ||
| 518 | return 0; | ||
| 519 | } | ||
| 520 | |||
| 521 | int | ||
| 522 | FRMR_error(struct layer2 *l2, struct sk_buff *skb) | ||
| 523 | { | ||
| 524 | u_int headers = l2addrsize(l2) + 1; | ||
| 525 | u_char *datap = skb->data + headers; | ||
| 526 | int rsp = *skb->data & 0x2; | ||
| 527 | |||
| 528 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
| 529 | rsp = !rsp; | ||
| 530 | if (!rsp) | ||
| 531 | return 'L'; | ||
| 532 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
| 533 | if (skb->len < headers + 5) | ||
| 534 | return 'N'; | ||
| 535 | else if (*debug & DEBUG_L2) | ||
| 536 | l2m_debug(&l2->l2m, | ||
| 537 | "FRMR information %2x %2x %2x %2x %2x", | ||
| 538 | datap[0], datap[1], datap[2], datap[3], datap[4]); | ||
| 539 | } else { | ||
| 540 | if (skb->len < headers + 3) | ||
| 541 | return 'N'; | ||
| 542 | else if (*debug & DEBUG_L2) | ||
| 543 | l2m_debug(&l2->l2m, | ||
| 544 | "FRMR information %2x %2x %2x", | ||
| 545 | datap[0], datap[1], datap[2]); | ||
| 546 | } | ||
| 547 | return 0; | ||
| 548 | } | ||
| 549 | |||
| 550 | static unsigned int | ||
| 551 | legalnr(struct layer2 *l2, unsigned int nr) | ||
| 552 | { | ||
| 553 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
| 554 | return ((nr - l2->va) % 128) <= ((l2->vs - l2->va) % 128); | ||
| 555 | else | ||
| 556 | return ((nr - l2->va) % 8) <= ((l2->vs - l2->va) % 8); | ||
| 557 | } | ||
| 558 | |||
| 559 | static void | ||
| 560 | setva(struct layer2 *l2, unsigned int nr) | ||
| 561 | { | ||
| 562 | struct sk_buff *skb; | ||
| 563 | |||
| 564 | while (l2->va != nr) { | ||
| 565 | l2->va++; | ||
| 566 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
| 567 | l2->va %= 128; | ||
| 568 | else | ||
| 569 | l2->va %= 8; | ||
| 570 | if (l2->windowar[l2->sow]) { | ||
| 571 | skb_trim(l2->windowar[l2->sow], 0); | ||
| 572 | skb_queue_tail(&l2->tmp_queue, l2->windowar[l2->sow]); | ||
| 573 | l2->windowar[l2->sow] = NULL; | ||
| 574 | } | ||
| 575 | l2->sow = (l2->sow + 1) % l2->window; | ||
| 576 | } | ||
| 577 | skb = skb_dequeue(&l2->tmp_queue); | ||
| 578 | while (skb) { | ||
| 579 | dev_kfree_skb(skb); | ||
| 580 | skb = skb_dequeue(&l2->tmp_queue); | ||
| 581 | } | ||
| 582 | } | ||
| 583 | |||
| 584 | static void | ||
| 585 | send_uframe(struct layer2 *l2, struct sk_buff *skb, u_char cmd, u_char cr) | ||
| 586 | { | ||
| 587 | u_char tmp[MAX_L2HEADER_LEN]; | ||
| 588 | int i; | ||
| 589 | |||
| 590 | i = sethdraddr(l2, tmp, cr); | ||
| 591 | tmp[i++] = cmd; | ||
| 592 | if (skb) | ||
| 593 | skb_trim(skb, 0); | ||
| 594 | else { | ||
| 595 | skb = mI_alloc_skb(i, GFP_ATOMIC); | ||
| 596 | if (!skb) { | ||
| 597 | printk(KERN_WARNING "%s: can't alloc skbuff\n", | ||
| 598 | __func__); | ||
| 599 | return; | ||
| 600 | } | ||
| 601 | } | ||
| 602 | memcpy(skb_put(skb, i), tmp, i); | ||
| 603 | enqueue_super(l2, skb); | ||
| 604 | } | ||
| 605 | |||
| 606 | |||
| 607 | inline u_char | ||
| 608 | get_PollFlag(struct layer2 *l2, struct sk_buff *skb) | ||
| 609 | { | ||
| 610 | return skb->data[l2addrsize(l2)] & 0x10; | ||
| 611 | } | ||
| 612 | |||
| 613 | inline u_char | ||
| 614 | get_PollFlagFree(struct layer2 *l2, struct sk_buff *skb) | ||
| 615 | { | ||
| 616 | u_char PF; | ||
| 617 | |||
| 618 | PF = get_PollFlag(l2, skb); | ||
| 619 | dev_kfree_skb(skb); | ||
| 620 | return PF; | ||
| 621 | } | ||
| 622 | |||
| 623 | inline void | ||
| 624 | start_t200(struct layer2 *l2, int i) | ||
| 625 | { | ||
| 626 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i); | ||
| 627 | test_and_set_bit(FLG_T200_RUN, &l2->flag); | ||
| 628 | } | ||
| 629 | |||
| 630 | inline void | ||
| 631 | restart_t200(struct layer2 *l2, int i) | ||
| 632 | { | ||
| 633 | mISDN_FsmRestartTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, i); | ||
| 634 | test_and_set_bit(FLG_T200_RUN, &l2->flag); | ||
| 635 | } | ||
| 636 | |||
| 637 | inline void | ||
| 638 | stop_t200(struct layer2 *l2, int i) | ||
| 639 | { | ||
| 640 | if (test_and_clear_bit(FLG_T200_RUN, &l2->flag)) | ||
| 641 | mISDN_FsmDelTimer(&l2->t200, i); | ||
| 642 | } | ||
| 643 | |||
| 644 | inline void | ||
| 645 | st5_dl_release_l2l3(struct layer2 *l2) | ||
| 646 | { | ||
| 647 | int pr; | ||
| 648 | |||
| 649 | if (test_and_clear_bit(FLG_PEND_REL, &l2->flag)) | ||
| 650 | pr = DL_RELEASE_CNF; | ||
| 651 | else | ||
| 652 | pr = DL_RELEASE_IND; | ||
| 653 | l2up_create(l2, pr, 0, NULL); | ||
| 654 | } | ||
| 655 | |||
| 656 | inline void | ||
| 657 | lapb_dl_release_l2l3(struct layer2 *l2, int f) | ||
| 658 | { | ||
| 659 | if (test_bit(FLG_LAPB, &l2->flag)) | ||
| 660 | l2down_create(l2, PH_DEACTIVATE_REQ, l2_newid(l2), 0, NULL); | ||
| 661 | l2up_create(l2, f, 0, NULL); | ||
| 662 | } | ||
| 663 | |||
| 664 | static void | ||
| 665 | establishlink(struct FsmInst *fi) | ||
| 666 | { | ||
| 667 | struct layer2 *l2 = fi->userdata; | ||
| 668 | u_char cmd; | ||
| 669 | |||
| 670 | clear_exception(l2); | ||
| 671 | l2->rc = 0; | ||
| 672 | cmd = (test_bit(FLG_MOD128, &l2->flag) ? SABME : SABM) | 0x10; | ||
| 673 | send_uframe(l2, NULL, cmd, CMD); | ||
| 674 | mISDN_FsmDelTimer(&l2->t203, 1); | ||
| 675 | restart_t200(l2, 1); | ||
| 676 | test_and_clear_bit(FLG_PEND_REL, &l2->flag); | ||
| 677 | freewin(l2); | ||
| 678 | mISDN_FsmChangeState(fi, ST_L2_5); | ||
| 679 | } | ||
| 680 | |||
| 681 | static void | ||
| 682 | l2_mdl_error_ua(struct FsmInst *fi, int event, void *arg) | ||
| 683 | { | ||
| 684 | struct sk_buff *skb = arg; | ||
| 685 | struct layer2 *l2 = fi->userdata; | ||
| 686 | |||
| 687 | if (get_PollFlagFree(l2, skb)) | ||
| 688 | l2mgr(l2, MDL_ERROR_IND, (void *) 'C'); | ||
| 689 | else | ||
| 690 | l2mgr(l2, MDL_ERROR_IND, (void *) 'D'); | ||
| 691 | |||
| 692 | } | ||
| 693 | |||
| 694 | static void | ||
| 695 | l2_mdl_error_dm(struct FsmInst *fi, int event, void *arg) | ||
| 696 | { | ||
| 697 | struct sk_buff *skb = arg; | ||
| 698 | struct layer2 *l2 = fi->userdata; | ||
| 699 | |||
| 700 | if (get_PollFlagFree(l2, skb)) | ||
| 701 | l2mgr(l2, MDL_ERROR_IND, (void *) 'B'); | ||
| 702 | else { | ||
| 703 | l2mgr(l2, MDL_ERROR_IND, (void *) 'E'); | ||
| 704 | establishlink(fi); | ||
| 705 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
| 706 | } | ||
| 707 | } | ||
| 708 | |||
| 709 | static void | ||
| 710 | l2_st8_mdl_error_dm(struct FsmInst *fi, int event, void *arg) | ||
| 711 | { | ||
| 712 | struct sk_buff *skb = arg; | ||
| 713 | struct layer2 *l2 = fi->userdata; | ||
| 714 | |||
| 715 | if (get_PollFlagFree(l2, skb)) | ||
| 716 | l2mgr(l2, MDL_ERROR_IND, (void *) 'B'); | ||
| 717 | else | ||
| 718 | l2mgr(l2, MDL_ERROR_IND, (void *) 'E'); | ||
| 719 | establishlink(fi); | ||
| 720 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
| 721 | } | ||
| 722 | |||
| 723 | static void | ||
| 724 | l2_go_st3(struct FsmInst *fi, int event, void *arg) | ||
| 725 | { | ||
| 726 | dev_kfree_skb((struct sk_buff *)arg); | ||
| 727 | mISDN_FsmChangeState(fi, ST_L2_3); | ||
| 728 | } | ||
| 729 | |||
| 730 | static void | ||
| 731 | l2_mdl_assign(struct FsmInst *fi, int event, void *arg) | ||
| 732 | { | ||
| 733 | struct layer2 *l2 = fi->userdata; | ||
| 734 | |||
| 735 | mISDN_FsmChangeState(fi, ST_L2_3); | ||
| 736 | dev_kfree_skb((struct sk_buff *)arg); | ||
| 737 | l2_tei(l2, MDL_ASSIGN_IND, 0); | ||
| 738 | } | ||
| 739 | |||
| 740 | static void | ||
| 741 | l2_queue_ui_assign(struct FsmInst *fi, int event, void *arg) | ||
| 742 | { | ||
| 743 | struct layer2 *l2 = fi->userdata; | ||
| 744 | struct sk_buff *skb = arg; | ||
| 745 | |||
| 746 | skb_queue_tail(&l2->ui_queue, skb); | ||
| 747 | mISDN_FsmChangeState(fi, ST_L2_2); | ||
| 748 | l2_tei(l2, MDL_ASSIGN_IND, 0); | ||
| 749 | } | ||
| 750 | |||
| 751 | static void | ||
| 752 | l2_queue_ui(struct FsmInst *fi, int event, void *arg) | ||
| 753 | { | ||
| 754 | struct layer2 *l2 = fi->userdata; | ||
| 755 | struct sk_buff *skb = arg; | ||
| 756 | |||
| 757 | skb_queue_tail(&l2->ui_queue, skb); | ||
| 758 | } | ||
| 759 | |||
| 760 | static void | ||
| 761 | tx_ui(struct layer2 *l2) | ||
| 762 | { | ||
| 763 | struct sk_buff *skb; | ||
| 764 | u_char header[MAX_L2HEADER_LEN]; | ||
| 765 | int i; | ||
| 766 | |||
| 767 | i = sethdraddr(l2, header, CMD); | ||
| 768 | if (test_bit(FLG_LAPD_NET, &l2->flag)) | ||
| 769 | header[1] = 0xff; /* tei 127 */ | ||
| 770 | header[i++] = UI; | ||
| 771 | while ((skb = skb_dequeue(&l2->ui_queue))) { | ||
| 772 | memcpy(skb_push(skb, i), header, i); | ||
| 773 | enqueue_ui(l2, skb); | ||
| 774 | } | ||
| 775 | } | ||
| 776 | |||
| 777 | static void | ||
| 778 | l2_send_ui(struct FsmInst *fi, int event, void *arg) | ||
| 779 | { | ||
| 780 | struct layer2 *l2 = fi->userdata; | ||
| 781 | struct sk_buff *skb = arg; | ||
| 782 | |||
| 783 | skb_queue_tail(&l2->ui_queue, skb); | ||
| 784 | tx_ui(l2); | ||
| 785 | } | ||
| 786 | |||
| 787 | static void | ||
| 788 | l2_got_ui(struct FsmInst *fi, int event, void *arg) | ||
| 789 | { | ||
| 790 | struct layer2 *l2 = fi->userdata; | ||
| 791 | struct sk_buff *skb = arg; | ||
| 792 | |||
| 793 | skb_pull(skb, l2headersize(l2, 1)); | ||
| 794 | /* | ||
| 795 | * in states 1-3 for broadcast | ||
| 796 | */ | ||
| 797 | |||
| 798 | if (l2->tm) | ||
| 799 | l2_tei(l2, MDL_STATUS_UI_IND, 0); | ||
| 800 | l2up(l2, DL_UNITDATA_IND, skb); | ||
| 801 | } | ||
| 802 | |||
| 803 | static void | ||
| 804 | l2_establish(struct FsmInst *fi, int event, void *arg) | ||
| 805 | { | ||
| 806 | struct sk_buff *skb = arg; | ||
| 807 | struct layer2 *l2 = fi->userdata; | ||
| 808 | |||
| 809 | establishlink(fi); | ||
| 810 | test_and_set_bit(FLG_L3_INIT, &l2->flag); | ||
| 811 | dev_kfree_skb(skb); | ||
| 812 | } | ||
| 813 | |||
| 814 | static void | ||
| 815 | l2_discard_i_setl3(struct FsmInst *fi, int event, void *arg) | ||
| 816 | { | ||
| 817 | struct sk_buff *skb = arg; | ||
| 818 | struct layer2 *l2 = fi->userdata; | ||
| 819 | |||
| 820 | skb_queue_purge(&l2->i_queue); | ||
| 821 | test_and_set_bit(FLG_L3_INIT, &l2->flag); | ||
| 822 | test_and_clear_bit(FLG_PEND_REL, &l2->flag); | ||
| 823 | dev_kfree_skb(skb); | ||
| 824 | } | ||
| 825 | |||
| 826 | static void | ||
| 827 | l2_l3_reestablish(struct FsmInst *fi, int event, void *arg) | ||
| 828 | { | ||
| 829 | struct sk_buff *skb = arg; | ||
| 830 | struct layer2 *l2 = fi->userdata; | ||
| 831 | |||
| 832 | skb_queue_purge(&l2->i_queue); | ||
| 833 | establishlink(fi); | ||
| 834 | test_and_set_bit(FLG_L3_INIT, &l2->flag); | ||
| 835 | dev_kfree_skb(skb); | ||
| 836 | } | ||
| 837 | |||
| 838 | static void | ||
| 839 | l2_release(struct FsmInst *fi, int event, void *arg) | ||
| 840 | { | ||
| 841 | struct layer2 *l2 = fi->userdata; | ||
| 842 | struct sk_buff *skb = arg; | ||
| 843 | |||
| 844 | skb_trim(skb, 0); | ||
| 845 | l2up(l2, DL_RELEASE_CNF, skb); | ||
| 846 | } | ||
| 847 | |||
| 848 | static void | ||
| 849 | l2_pend_rel(struct FsmInst *fi, int event, void *arg) | ||
| 850 | { | ||
| 851 | struct sk_buff *skb = arg; | ||
| 852 | struct layer2 *l2 = fi->userdata; | ||
| 853 | |||
| 854 | test_and_set_bit(FLG_PEND_REL, &l2->flag); | ||
| 855 | dev_kfree_skb(skb); | ||
| 856 | } | ||
| 857 | |||
| 858 | static void | ||
| 859 | l2_disconnect(struct FsmInst *fi, int event, void *arg) | ||
| 860 | { | ||
| 861 | struct layer2 *l2 = fi->userdata; | ||
| 862 | struct sk_buff *skb = arg; | ||
| 863 | |||
| 864 | skb_queue_purge(&l2->i_queue); | ||
| 865 | freewin(l2); | ||
| 866 | mISDN_FsmChangeState(fi, ST_L2_6); | ||
| 867 | l2->rc = 0; | ||
| 868 | send_uframe(l2, NULL, DISC | 0x10, CMD); | ||
| 869 | mISDN_FsmDelTimer(&l2->t203, 1); | ||
| 870 | restart_t200(l2, 2); | ||
| 871 | if (skb) | ||
| 872 | dev_kfree_skb(skb); | ||
| 873 | } | ||
| 874 | |||
| 875 | static void | ||
| 876 | l2_start_multi(struct FsmInst *fi, int event, void *arg) | ||
| 877 | { | ||
| 878 | struct layer2 *l2 = fi->userdata; | ||
| 879 | struct sk_buff *skb = arg; | ||
| 880 | |||
| 881 | l2->vs = 0; | ||
| 882 | l2->va = 0; | ||
| 883 | l2->vr = 0; | ||
| 884 | l2->sow = 0; | ||
| 885 | clear_exception(l2); | ||
| 886 | send_uframe(l2, NULL, UA | get_PollFlag(l2, skb), RSP); | ||
| 887 | mISDN_FsmChangeState(fi, ST_L2_7); | ||
| 888 | mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3); | ||
| 889 | skb_trim(skb, 0); | ||
| 890 | l2up(l2, DL_ESTABLISH_IND, skb); | ||
| 891 | if (l2->tm) | ||
| 892 | l2_tei(l2, MDL_STATUS_UP_IND, 0); | ||
| 893 | } | ||
| 894 | |||
| 895 | static void | ||
| 896 | l2_send_UA(struct FsmInst *fi, int event, void *arg) | ||
| 897 | { | ||
| 898 | struct layer2 *l2 = fi->userdata; | ||
| 899 | struct sk_buff *skb = arg; | ||
| 900 | |||
| 901 | send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP); | ||
| 902 | } | ||
| 903 | |||
| 904 | static void | ||
| 905 | l2_send_DM(struct FsmInst *fi, int event, void *arg) | ||
| 906 | { | ||
| 907 | struct layer2 *l2 = fi->userdata; | ||
| 908 | struct sk_buff *skb = arg; | ||
| 909 | |||
| 910 | send_uframe(l2, skb, DM | get_PollFlag(l2, skb), RSP); | ||
| 911 | } | ||
| 912 | |||
| 913 | static void | ||
| 914 | l2_restart_multi(struct FsmInst *fi, int event, void *arg) | ||
| 915 | { | ||
| 916 | struct layer2 *l2 = fi->userdata; | ||
| 917 | struct sk_buff *skb = arg; | ||
| 918 | int est = 0; | ||
| 919 | |||
| 920 | send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP); | ||
| 921 | |||
| 922 | l2mgr(l2, MDL_ERROR_IND, (void *) 'F'); | ||
| 923 | |||
| 924 | if (l2->vs != l2->va) { | ||
| 925 | skb_queue_purge(&l2->i_queue); | ||
| 926 | est = 1; | ||
| 927 | } | ||
| 928 | |||
| 929 | clear_exception(l2); | ||
| 930 | l2->vs = 0; | ||
| 931 | l2->va = 0; | ||
| 932 | l2->vr = 0; | ||
| 933 | l2->sow = 0; | ||
| 934 | mISDN_FsmChangeState(fi, ST_L2_7); | ||
| 935 | stop_t200(l2, 3); | ||
| 936 | mISDN_FsmRestartTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3); | ||
| 937 | |||
| 938 | if (est) | ||
| 939 | l2up_create(l2, DL_ESTABLISH_IND, 0, NULL); | ||
| 940 | /* mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST, | ||
| 941 | * MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_ESTABLISHED, | ||
| 942 | * 0, NULL, 0); | ||
| 943 | */ | ||
| 944 | if (skb_queue_len(&l2->i_queue) && cansend(l2)) | ||
| 945 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
| 946 | } | ||
| 947 | |||
| 948 | static void | ||
| 949 | l2_stop_multi(struct FsmInst *fi, int event, void *arg) | ||
| 950 | { | ||
| 951 | struct layer2 *l2 = fi->userdata; | ||
| 952 | struct sk_buff *skb = arg; | ||
| 953 | |||
| 954 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
| 955 | mISDN_FsmDelTimer(&l2->t203, 3); | ||
| 956 | stop_t200(l2, 4); | ||
| 957 | |||
| 958 | send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP); | ||
| 959 | skb_queue_purge(&l2->i_queue); | ||
| 960 | freewin(l2); | ||
| 961 | lapb_dl_release_l2l3(l2, DL_RELEASE_IND); | ||
| 962 | if (l2->tm) | ||
| 963 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
| 964 | } | ||
| 965 | |||
| 966 | static void | ||
| 967 | l2_connected(struct FsmInst *fi, int event, void *arg) | ||
| 968 | { | ||
| 969 | struct layer2 *l2 = fi->userdata; | ||
| 970 | struct sk_buff *skb = arg; | ||
| 971 | int pr = -1; | ||
| 972 | |||
| 973 | if (!get_PollFlag(l2, skb)) { | ||
| 974 | l2_mdl_error_ua(fi, event, arg); | ||
| 975 | return; | ||
| 976 | } | ||
| 977 | dev_kfree_skb(skb); | ||
| 978 | if (test_and_clear_bit(FLG_PEND_REL, &l2->flag)) | ||
| 979 | l2_disconnect(fi, event, NULL); | ||
| 980 | if (test_and_clear_bit(FLG_L3_INIT, &l2->flag)) { | ||
| 981 | pr = DL_ESTABLISH_CNF; | ||
| 982 | } else if (l2->vs != l2->va) { | ||
| 983 | skb_queue_purge(&l2->i_queue); | ||
| 984 | pr = DL_ESTABLISH_IND; | ||
| 985 | } | ||
| 986 | stop_t200(l2, 5); | ||
| 987 | l2->vr = 0; | ||
| 988 | l2->vs = 0; | ||
| 989 | l2->va = 0; | ||
| 990 | l2->sow = 0; | ||
| 991 | mISDN_FsmChangeState(fi, ST_L2_7); | ||
| 992 | mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 4); | ||
| 993 | if (pr != -1) | ||
| 994 | l2up_create(l2, pr, 0, NULL); | ||
| 995 | |||
| 996 | if (skb_queue_len(&l2->i_queue) && cansend(l2)) | ||
| 997 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
| 998 | |||
| 999 | if (l2->tm) | ||
| 1000 | l2_tei(l2, MDL_STATUS_UP_IND, 0); | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | static void | ||
| 1004 | l2_released(struct FsmInst *fi, int event, void *arg) | ||
| 1005 | { | ||
| 1006 | struct layer2 *l2 = fi->userdata; | ||
| 1007 | struct sk_buff *skb = arg; | ||
| 1008 | |||
| 1009 | if (!get_PollFlag(l2, skb)) { | ||
| 1010 | l2_mdl_error_ua(fi, event, arg); | ||
| 1011 | return; | ||
| 1012 | } | ||
| 1013 | dev_kfree_skb(skb); | ||
| 1014 | stop_t200(l2, 6); | ||
| 1015 | lapb_dl_release_l2l3(l2, DL_RELEASE_CNF); | ||
| 1016 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
| 1017 | if (l2->tm) | ||
| 1018 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | static void | ||
| 1022 | l2_reestablish(struct FsmInst *fi, int event, void *arg) | ||
| 1023 | { | ||
| 1024 | struct layer2 *l2 = fi->userdata; | ||
| 1025 | struct sk_buff *skb = arg; | ||
| 1026 | |||
| 1027 | if (!get_PollFlagFree(l2, skb)) { | ||
| 1028 | establishlink(fi); | ||
| 1029 | test_and_set_bit(FLG_L3_INIT, &l2->flag); | ||
| 1030 | } | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | static void | ||
| 1034 | l2_st5_dm_release(struct FsmInst *fi, int event, void *arg) | ||
| 1035 | { | ||
| 1036 | struct layer2 *l2 = fi->userdata; | ||
| 1037 | struct sk_buff *skb = arg; | ||
| 1038 | |||
| 1039 | if (get_PollFlagFree(l2, skb)) { | ||
| 1040 | stop_t200(l2, 7); | ||
| 1041 | if (!test_bit(FLG_L3_INIT, &l2->flag)) | ||
| 1042 | skb_queue_purge(&l2->i_queue); | ||
| 1043 | if (test_bit(FLG_LAPB, &l2->flag)) | ||
| 1044 | l2down_create(l2, PH_DEACTIVATE_REQ, | ||
| 1045 | l2_newid(l2), 0, NULL); | ||
| 1046 | st5_dl_release_l2l3(l2); | ||
| 1047 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
| 1048 | if (l2->tm) | ||
| 1049 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
| 1050 | } | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | static void | ||
| 1054 | l2_st6_dm_release(struct FsmInst *fi, int event, void *arg) | ||
| 1055 | { | ||
| 1056 | struct layer2 *l2 = fi->userdata; | ||
| 1057 | struct sk_buff *skb = arg; | ||
| 1058 | |||
| 1059 | if (get_PollFlagFree(l2, skb)) { | ||
| 1060 | stop_t200(l2, 8); | ||
| 1061 | lapb_dl_release_l2l3(l2, DL_RELEASE_CNF); | ||
| 1062 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
| 1063 | if (l2->tm) | ||
| 1064 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
| 1065 | } | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | void | ||
| 1069 | enquiry_cr(struct layer2 *l2, u_char typ, u_char cr, u_char pf) | ||
| 1070 | { | ||
| 1071 | struct sk_buff *skb; | ||
| 1072 | u_char tmp[MAX_L2HEADER_LEN]; | ||
| 1073 | int i; | ||
| 1074 | |||
| 1075 | i = sethdraddr(l2, tmp, cr); | ||
| 1076 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
| 1077 | tmp[i++] = typ; | ||
| 1078 | tmp[i++] = (l2->vr << 1) | (pf ? 1 : 0); | ||
| 1079 | } else | ||
| 1080 | tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0); | ||
| 1081 | skb = mI_alloc_skb(i, GFP_ATOMIC); | ||
| 1082 | if (!skb) { | ||
| 1083 | printk(KERN_WARNING | ||
| 1084 | "isdnl2 can't alloc sbbuff for enquiry_cr\n"); | ||
| 1085 | return; | ||
| 1086 | } | ||
| 1087 | memcpy(skb_put(skb, i), tmp, i); | ||
| 1088 | enqueue_super(l2, skb); | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | inline void | ||
| 1092 | enquiry_response(struct layer2 *l2) | ||
| 1093 | { | ||
| 1094 | if (test_bit(FLG_OWN_BUSY, &l2->flag)) | ||
| 1095 | enquiry_cr(l2, RNR, RSP, 1); | ||
| 1096 | else | ||
| 1097 | enquiry_cr(l2, RR, RSP, 1); | ||
| 1098 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
| 1099 | } | ||
| 1100 | |||
| 1101 | inline void | ||
| 1102 | transmit_enquiry(struct layer2 *l2) | ||
| 1103 | { | ||
| 1104 | if (test_bit(FLG_OWN_BUSY, &l2->flag)) | ||
| 1105 | enquiry_cr(l2, RNR, CMD, 1); | ||
| 1106 | else | ||
| 1107 | enquiry_cr(l2, RR, CMD, 1); | ||
| 1108 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
| 1109 | start_t200(l2, 9); | ||
| 1110 | } | ||
| 1111 | |||
| 1112 | |||
| 1113 | static void | ||
| 1114 | nrerrorrecovery(struct FsmInst *fi) | ||
| 1115 | { | ||
| 1116 | struct layer2 *l2 = fi->userdata; | ||
| 1117 | |||
| 1118 | l2mgr(l2, MDL_ERROR_IND, (void *) 'J'); | ||
| 1119 | establishlink(fi); | ||
| 1120 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
| 1121 | } | ||
| 1122 | |||
| 1123 | static void | ||
| 1124 | invoke_retransmission(struct layer2 *l2, unsigned int nr) | ||
| 1125 | { | ||
| 1126 | u_int p1; | ||
| 1127 | |||
| 1128 | if (l2->vs != nr) { | ||
| 1129 | while (l2->vs != nr) { | ||
| 1130 | (l2->vs)--; | ||
| 1131 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
| 1132 | l2->vs %= 128; | ||
| 1133 | p1 = (l2->vs - l2->va) % 128; | ||
| 1134 | } else { | ||
| 1135 | l2->vs %= 8; | ||
| 1136 | p1 = (l2->vs - l2->va) % 8; | ||
| 1137 | } | ||
| 1138 | p1 = (p1 + l2->sow) % l2->window; | ||
| 1139 | if (l2->windowar[p1]) | ||
| 1140 | skb_queue_head(&l2->i_queue, l2->windowar[p1]); | ||
| 1141 | else | ||
| 1142 | printk(KERN_WARNING | ||
| 1143 | "%s: windowar[%d] is NULL\n", | ||
| 1144 | __func__, p1); | ||
| 1145 | l2->windowar[p1] = NULL; | ||
| 1146 | } | ||
| 1147 | mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL); | ||
| 1148 | } | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | static void | ||
| 1152 | l2_st7_got_super(struct FsmInst *fi, int event, void *arg) | ||
| 1153 | { | ||
| 1154 | struct layer2 *l2 = fi->userdata; | ||
| 1155 | struct sk_buff *skb = arg; | ||
| 1156 | int PollFlag, rsp, typ = RR; | ||
| 1157 | unsigned int nr; | ||
| 1158 | |||
| 1159 | rsp = *skb->data & 0x2; | ||
| 1160 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
| 1161 | rsp = !rsp; | ||
| 1162 | |||
| 1163 | skb_pull(skb, l2addrsize(l2)); | ||
| 1164 | if (IsRNR(skb->data, l2)) { | ||
| 1165 | set_peer_busy(l2); | ||
| 1166 | typ = RNR; | ||
| 1167 | } else | ||
| 1168 | clear_peer_busy(l2); | ||
| 1169 | if (IsREJ(skb->data, l2)) | ||
| 1170 | typ = REJ; | ||
| 1171 | |||
| 1172 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
| 1173 | PollFlag = (skb->data[1] & 0x1) == 0x1; | ||
| 1174 | nr = skb->data[1] >> 1; | ||
| 1175 | } else { | ||
| 1176 | PollFlag = (skb->data[0] & 0x10); | ||
| 1177 | nr = (skb->data[0] >> 5) & 0x7; | ||
| 1178 | } | ||
| 1179 | dev_kfree_skb(skb); | ||
| 1180 | |||
| 1181 | if (PollFlag) { | ||
| 1182 | if (rsp) | ||
| 1183 | l2mgr(l2, MDL_ERROR_IND, (void *) 'A'); | ||
| 1184 | else | ||
| 1185 | enquiry_response(l2); | ||
| 1186 | } | ||
| 1187 | if (legalnr(l2, nr)) { | ||
| 1188 | if (typ == REJ) { | ||
| 1189 | setva(l2, nr); | ||
| 1190 | invoke_retransmission(l2, nr); | ||
| 1191 | stop_t200(l2, 10); | ||
| 1192 | if (mISDN_FsmAddTimer(&l2->t203, l2->T203, | ||
| 1193 | EV_L2_T203, NULL, 6)) | ||
| 1194 | l2m_debug(&l2->l2m, "Restart T203 ST7 REJ"); | ||
| 1195 | } else if ((nr == l2->vs) && (typ == RR)) { | ||
| 1196 | setva(l2, nr); | ||
| 1197 | stop_t200(l2, 11); | ||
| 1198 | mISDN_FsmRestartTimer(&l2->t203, l2->T203, | ||
| 1199 | EV_L2_T203, NULL, 7); | ||
| 1200 | } else if ((l2->va != nr) || (typ == RNR)) { | ||
| 1201 | setva(l2, nr); | ||
| 1202 | if (typ != RR) | ||
| 1203 | mISDN_FsmDelTimer(&l2->t203, 9); | ||
| 1204 | restart_t200(l2, 12); | ||
| 1205 | } | ||
| 1206 | if (skb_queue_len(&l2->i_queue) && (typ == RR)) | ||
| 1207 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
| 1208 | } else | ||
| 1209 | nrerrorrecovery(fi); | ||
| 1210 | } | ||
| 1211 | |||
| 1212 | static void | ||
| 1213 | l2_feed_i_if_reest(struct FsmInst *fi, int event, void *arg) | ||
| 1214 | { | ||
| 1215 | struct layer2 *l2 = fi->userdata; | ||
| 1216 | struct sk_buff *skb = arg; | ||
| 1217 | |||
| 1218 | if (!test_bit(FLG_L3_INIT, &l2->flag)) | ||
| 1219 | skb_queue_tail(&l2->i_queue, skb); | ||
| 1220 | else | ||
| 1221 | dev_kfree_skb(skb); | ||
| 1222 | } | ||
| 1223 | |||
| 1224 | static void | ||
| 1225 | l2_feed_i_pull(struct FsmInst *fi, int event, void *arg) | ||
| 1226 | { | ||
| 1227 | struct layer2 *l2 = fi->userdata; | ||
| 1228 | struct sk_buff *skb = arg; | ||
| 1229 | |||
| 1230 | skb_queue_tail(&l2->i_queue, skb); | ||
| 1231 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
| 1232 | } | ||
| 1233 | |||
| 1234 | static void | ||
| 1235 | l2_feed_iqueue(struct FsmInst *fi, int event, void *arg) | ||
| 1236 | { | ||
| 1237 | struct layer2 *l2 = fi->userdata; | ||
| 1238 | struct sk_buff *skb = arg; | ||
| 1239 | |||
| 1240 | skb_queue_tail(&l2->i_queue, skb); | ||
| 1241 | } | ||
| 1242 | |||
| 1243 | static void | ||
| 1244 | l2_got_iframe(struct FsmInst *fi, int event, void *arg) | ||
| 1245 | { | ||
| 1246 | struct layer2 *l2 = fi->userdata; | ||
| 1247 | struct sk_buff *skb = arg; | ||
| 1248 | int PollFlag, i; | ||
| 1249 | u_int ns, nr; | ||
| 1250 | |||
| 1251 | i = l2addrsize(l2); | ||
| 1252 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
| 1253 | PollFlag = ((skb->data[i + 1] & 0x1) == 0x1); | ||
| 1254 | ns = skb->data[i] >> 1; | ||
| 1255 | nr = (skb->data[i + 1] >> 1) & 0x7f; | ||
| 1256 | } else { | ||
| 1257 | PollFlag = (skb->data[i] & 0x10); | ||
| 1258 | ns = (skb->data[i] >> 1) & 0x7; | ||
| 1259 | nr = (skb->data[i] >> 5) & 0x7; | ||
| 1260 | } | ||
| 1261 | if (test_bit(FLG_OWN_BUSY, &l2->flag)) { | ||
| 1262 | dev_kfree_skb(skb); | ||
| 1263 | if (PollFlag) | ||
| 1264 | enquiry_response(l2); | ||
| 1265 | } else { | ||
| 1266 | if (l2->vr == ns) { | ||
| 1267 | l2->vr++; | ||
| 1268 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
| 1269 | l2->vr %= 128; | ||
| 1270 | else | ||
| 1271 | l2->vr %= 8; | ||
| 1272 | test_and_clear_bit(FLG_REJEXC, &l2->flag); | ||
| 1273 | if (PollFlag) | ||
| 1274 | enquiry_response(l2); | ||
| 1275 | else | ||
| 1276 | test_and_set_bit(FLG_ACK_PEND, &l2->flag); | ||
| 1277 | skb_pull(skb, l2headersize(l2, 0)); | ||
| 1278 | l2up(l2, DL_DATA_IND, skb); | ||
| 1279 | } else { | ||
| 1280 | /* n(s)!=v(r) */ | ||
| 1281 | dev_kfree_skb(skb); | ||
| 1282 | if (test_and_set_bit(FLG_REJEXC, &l2->flag)) { | ||
| 1283 | if (PollFlag) | ||
| 1284 | enquiry_response(l2); | ||
| 1285 | } else { | ||
| 1286 | enquiry_cr(l2, REJ, RSP, PollFlag); | ||
| 1287 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
| 1288 | } | ||
| 1289 | } | ||
| 1290 | } | ||
| 1291 | if (legalnr(l2, nr)) { | ||
| 1292 | if (!test_bit(FLG_PEER_BUSY, &l2->flag) && | ||
| 1293 | (fi->state == ST_L2_7)) { | ||
| 1294 | if (nr == l2->vs) { | ||
| 1295 | stop_t200(l2, 13); | ||
| 1296 | mISDN_FsmRestartTimer(&l2->t203, l2->T203, | ||
| 1297 | EV_L2_T203, NULL, 7); | ||
| 1298 | } else if (nr != l2->va) | ||
| 1299 | restart_t200(l2, 14); | ||
| 1300 | } | ||
| 1301 | setva(l2, nr); | ||
| 1302 | } else { | ||
| 1303 | nrerrorrecovery(fi); | ||
| 1304 | return; | ||
| 1305 | } | ||
| 1306 | if (skb_queue_len(&l2->i_queue) && (fi->state == ST_L2_7)) | ||
| 1307 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
| 1308 | if (test_and_clear_bit(FLG_ACK_PEND, &l2->flag)) | ||
| 1309 | enquiry_cr(l2, RR, RSP, 0); | ||
| 1310 | } | ||
| 1311 | |||
| 1312 | static void | ||
| 1313 | l2_got_tei(struct FsmInst *fi, int event, void *arg) | ||
| 1314 | { | ||
| 1315 | struct layer2 *l2 = fi->userdata; | ||
| 1316 | u_int info; | ||
| 1317 | |||
| 1318 | l2->tei = (signed char)(long)arg; | ||
| 1319 | set_channel_address(&l2->ch, l2->sapi, l2->tei); | ||
| 1320 | info = DL_INFO_L2_CONNECT; | ||
| 1321 | l2up_create(l2, DL_INFORMATION_IND, sizeof(info), &info); | ||
| 1322 | if (fi->state == ST_L2_3) { | ||
| 1323 | establishlink(fi); | ||
| 1324 | test_and_set_bit(FLG_L3_INIT, &l2->flag); | ||
| 1325 | } else | ||
| 1326 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
| 1327 | if (skb_queue_len(&l2->ui_queue)) | ||
| 1328 | tx_ui(l2); | ||
| 1329 | } | ||
| 1330 | |||
| 1331 | static void | ||
| 1332 | l2_st5_tout_200(struct FsmInst *fi, int event, void *arg) | ||
| 1333 | { | ||
| 1334 | struct layer2 *l2 = fi->userdata; | ||
| 1335 | |||
| 1336 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
| 1337 | test_bit(FLG_DCHAN_BUSY, &l2->flag)) { | ||
| 1338 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); | ||
| 1339 | } else if (l2->rc == l2->N200) { | ||
| 1340 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
| 1341 | test_and_clear_bit(FLG_T200_RUN, &l2->flag); | ||
| 1342 | skb_queue_purge(&l2->i_queue); | ||
| 1343 | l2mgr(l2, MDL_ERROR_IND, (void *) 'G'); | ||
| 1344 | if (test_bit(FLG_LAPB, &l2->flag)) | ||
| 1345 | l2down_create(l2, PH_DEACTIVATE_REQ, | ||
| 1346 | l2_newid(l2), 0, NULL); | ||
| 1347 | st5_dl_release_l2l3(l2); | ||
| 1348 | if (l2->tm) | ||
| 1349 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
| 1350 | } else { | ||
| 1351 | l2->rc++; | ||
| 1352 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); | ||
| 1353 | send_uframe(l2, NULL, (test_bit(FLG_MOD128, &l2->flag) ? | ||
| 1354 | SABME : SABM) | 0x10, CMD); | ||
| 1355 | } | ||
| 1356 | } | ||
| 1357 | |||
| 1358 | static void | ||
| 1359 | l2_st6_tout_200(struct FsmInst *fi, int event, void *arg) | ||
| 1360 | { | ||
| 1361 | struct layer2 *l2 = fi->userdata; | ||
| 1362 | |||
| 1363 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
| 1364 | test_bit(FLG_DCHAN_BUSY, &l2->flag)) { | ||
| 1365 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); | ||
| 1366 | } else if (l2->rc == l2->N200) { | ||
| 1367 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
| 1368 | test_and_clear_bit(FLG_T200_RUN, &l2->flag); | ||
| 1369 | l2mgr(l2, MDL_ERROR_IND, (void *) 'H'); | ||
| 1370 | lapb_dl_release_l2l3(l2, DL_RELEASE_CNF); | ||
| 1371 | if (l2->tm) | ||
| 1372 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
| 1373 | } else { | ||
| 1374 | l2->rc++; | ||
| 1375 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, | ||
| 1376 | NULL, 9); | ||
| 1377 | send_uframe(l2, NULL, DISC | 0x10, CMD); | ||
| 1378 | } | ||
| 1379 | } | ||
| 1380 | |||
| 1381 | static void | ||
| 1382 | l2_st7_tout_200(struct FsmInst *fi, int event, void *arg) | ||
| 1383 | { | ||
| 1384 | struct layer2 *l2 = fi->userdata; | ||
| 1385 | |||
| 1386 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
| 1387 | test_bit(FLG_DCHAN_BUSY, &l2->flag)) { | ||
| 1388 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); | ||
| 1389 | return; | ||
| 1390 | } | ||
| 1391 | test_and_clear_bit(FLG_T200_RUN, &l2->flag); | ||
| 1392 | l2->rc = 0; | ||
| 1393 | mISDN_FsmChangeState(fi, ST_L2_8); | ||
| 1394 | transmit_enquiry(l2); | ||
| 1395 | l2->rc++; | ||
| 1396 | } | ||
| 1397 | |||
| 1398 | static void | ||
| 1399 | l2_st8_tout_200(struct FsmInst *fi, int event, void *arg) | ||
| 1400 | { | ||
| 1401 | struct layer2 *l2 = fi->userdata; | ||
| 1402 | |||
| 1403 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
| 1404 | test_bit(FLG_DCHAN_BUSY, &l2->flag)) { | ||
| 1405 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); | ||
| 1406 | return; | ||
| 1407 | } | ||
| 1408 | test_and_clear_bit(FLG_T200_RUN, &l2->flag); | ||
| 1409 | if (l2->rc == l2->N200) { | ||
| 1410 | l2mgr(l2, MDL_ERROR_IND, (void *) 'I'); | ||
| 1411 | establishlink(fi); | ||
| 1412 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
| 1413 | } else { | ||
| 1414 | transmit_enquiry(l2); | ||
| 1415 | l2->rc++; | ||
| 1416 | } | ||
| 1417 | } | ||
| 1418 | |||
| 1419 | static void | ||
| 1420 | l2_st7_tout_203(struct FsmInst *fi, int event, void *arg) | ||
| 1421 | { | ||
| 1422 | struct layer2 *l2 = fi->userdata; | ||
| 1423 | |||
| 1424 | if (test_bit(FLG_LAPD, &l2->flag) && | ||
| 1425 | test_bit(FLG_DCHAN_BUSY, &l2->flag)) { | ||
| 1426 | mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 9); | ||
| 1427 | return; | ||
| 1428 | } | ||
| 1429 | mISDN_FsmChangeState(fi, ST_L2_8); | ||
| 1430 | transmit_enquiry(l2); | ||
| 1431 | l2->rc = 0; | ||
| 1432 | } | ||
| 1433 | |||
| 1434 | static void | ||
| 1435 | l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) | ||
| 1436 | { | ||
| 1437 | struct layer2 *l2 = fi->userdata; | ||
| 1438 | struct sk_buff *skb, *nskb, *oskb; | ||
| 1439 | u_char header[MAX_L2HEADER_LEN]; | ||
| 1440 | u_int i, p1; | ||
| 1441 | |||
| 1442 | if (!cansend(l2)) | ||
| 1443 | return; | ||
| 1444 | |||
| 1445 | skb = skb_dequeue(&l2->i_queue); | ||
| 1446 | if (!skb) | ||
| 1447 | return; | ||
| 1448 | |||
| 1449 | if (test_bit(FLG_MOD128, &l2->flag)) | ||
| 1450 | p1 = (l2->vs - l2->va) % 128; | ||
| 1451 | else | ||
| 1452 | p1 = (l2->vs - l2->va) % 8; | ||
| 1453 | p1 = (p1 + l2->sow) % l2->window; | ||
| 1454 | if (l2->windowar[p1]) { | ||
| 1455 | printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n", | ||
| 1456 | p1); | ||
| 1457 | dev_kfree_skb(l2->windowar[p1]); | ||
| 1458 | } | ||
| 1459 | l2->windowar[p1] = skb; | ||
| 1460 | i = sethdraddr(l2, header, CMD); | ||
| 1461 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
| 1462 | header[i++] = l2->vs << 1; | ||
| 1463 | header[i++] = l2->vr << 1; | ||
| 1464 | l2->vs = (l2->vs + 1) % 128; | ||
| 1465 | } else { | ||
| 1466 | header[i++] = (l2->vr << 5) | (l2->vs << 1); | ||
| 1467 | l2->vs = (l2->vs + 1) % 8; | ||
| 1468 | } | ||
| 1469 | |||
| 1470 | nskb = skb_clone(skb, GFP_ATOMIC); | ||
| 1471 | p1 = skb_headroom(nskb); | ||
| 1472 | if (p1 >= i) | ||
| 1473 | memcpy(skb_push(nskb, i), header, i); | ||
| 1474 | else { | ||
| 1475 | printk(KERN_WARNING | ||
| 1476 | "isdnl2 pull_iqueue skb header(%d/%d) too short\n", i, p1); | ||
| 1477 | oskb = nskb; | ||
| 1478 | nskb = mI_alloc_skb(oskb->len + i, GFP_ATOMIC); | ||
| 1479 | if (!nskb) { | ||
| 1480 | dev_kfree_skb(oskb); | ||
| 1481 | printk(KERN_WARNING "%s: no skb mem\n", __func__); | ||
| 1482 | return; | ||
| 1483 | } | ||
| 1484 | memcpy(skb_put(nskb, i), header, i); | ||
| 1485 | memcpy(skb_put(nskb, oskb->len), oskb->data, oskb->len); | ||
| 1486 | dev_kfree_skb(oskb); | ||
| 1487 | } | ||
| 1488 | l2down(l2, PH_DATA_REQ, l2_newid(l2), nskb); | ||
| 1489 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
| 1490 | if (!test_and_set_bit(FLG_T200_RUN, &l2->flag)) { | ||
| 1491 | mISDN_FsmDelTimer(&l2->t203, 13); | ||
| 1492 | mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 11); | ||
| 1493 | } | ||
| 1494 | } | ||
| 1495 | |||
| 1496 | static void | ||
| 1497 | l2_st8_got_super(struct FsmInst *fi, int event, void *arg) | ||
| 1498 | { | ||
| 1499 | struct layer2 *l2 = fi->userdata; | ||
| 1500 | struct sk_buff *skb = arg; | ||
| 1501 | int PollFlag, rsp, rnr = 0; | ||
| 1502 | unsigned int nr; | ||
| 1503 | |||
| 1504 | rsp = *skb->data & 0x2; | ||
| 1505 | if (test_bit(FLG_ORIG, &l2->flag)) | ||
| 1506 | rsp = !rsp; | ||
| 1507 | |||
| 1508 | skb_pull(skb, l2addrsize(l2)); | ||
| 1509 | |||
| 1510 | if (IsRNR(skb->data, l2)) { | ||
| 1511 | set_peer_busy(l2); | ||
| 1512 | rnr = 1; | ||
| 1513 | } else | ||
| 1514 | clear_peer_busy(l2); | ||
| 1515 | |||
| 1516 | if (test_bit(FLG_MOD128, &l2->flag)) { | ||
| 1517 | PollFlag = (skb->data[1] & 0x1) == 0x1; | ||
| 1518 | nr = skb->data[1] >> 1; | ||
| 1519 | } else { | ||
| 1520 | PollFlag = (skb->data[0] & 0x10); | ||
| 1521 | nr = (skb->data[0] >> 5) & 0x7; | ||
| 1522 | } | ||
| 1523 | dev_kfree_skb(skb); | ||
| 1524 | if (rsp && PollFlag) { | ||
| 1525 | if (legalnr(l2, nr)) { | ||
| 1526 | if (rnr) { | ||
| 1527 | restart_t200(l2, 15); | ||
| 1528 | } else { | ||
| 1529 | stop_t200(l2, 16); | ||
| 1530 | mISDN_FsmAddTimer(&l2->t203, l2->T203, | ||
| 1531 | EV_L2_T203, NULL, 5); | ||
| 1532 | setva(l2, nr); | ||
| 1533 | } | ||
| 1534 | invoke_retransmission(l2, nr); | ||
| 1535 | mISDN_FsmChangeState(fi, ST_L2_7); | ||
| 1536 | if (skb_queue_len(&l2->i_queue) && cansend(l2)) | ||
| 1537 | mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL); | ||
| 1538 | } else | ||
| 1539 | nrerrorrecovery(fi); | ||
| 1540 | } else { | ||
| 1541 | if (!rsp && PollFlag) | ||
| 1542 | enquiry_response(l2); | ||
| 1543 | if (legalnr(l2, nr)) | ||
| 1544 | setva(l2, nr); | ||
| 1545 | else | ||
| 1546 | nrerrorrecovery(fi); | ||
| 1547 | } | ||
| 1548 | } | ||
| 1549 | |||
| 1550 | static void | ||
| 1551 | l2_got_FRMR(struct FsmInst *fi, int event, void *arg) | ||
| 1552 | { | ||
| 1553 | struct layer2 *l2 = fi->userdata; | ||
| 1554 | struct sk_buff *skb = arg; | ||
| 1555 | |||
| 1556 | skb_pull(skb, l2addrsize(l2) + 1); | ||
| 1557 | |||
| 1558 | if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) || /* I or S */ | ||
| 1559 | (IsUA(skb->data) && (fi->state == ST_L2_7))) { | ||
| 1560 | l2mgr(l2, MDL_ERROR_IND, (void *) 'K'); | ||
| 1561 | establishlink(fi); | ||
| 1562 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
| 1563 | } | ||
| 1564 | dev_kfree_skb(skb); | ||
| 1565 | } | ||
| 1566 | |||
| 1567 | static void | ||
| 1568 | l2_st24_tei_remove(struct FsmInst *fi, int event, void *arg) | ||
| 1569 | { | ||
| 1570 | struct layer2 *l2 = fi->userdata; | ||
| 1571 | |||
| 1572 | skb_queue_purge(&l2->ui_queue); | ||
| 1573 | l2->tei = GROUP_TEI; | ||
| 1574 | mISDN_FsmChangeState(fi, ST_L2_1); | ||
| 1575 | } | ||
| 1576 | |||
| 1577 | static void | ||
| 1578 | l2_st3_tei_remove(struct FsmInst *fi, int event, void *arg) | ||
| 1579 | { | ||
| 1580 | struct layer2 *l2 = fi->userdata; | ||
| 1581 | |||
| 1582 | skb_queue_purge(&l2->ui_queue); | ||
| 1583 | l2->tei = GROUP_TEI; | ||
| 1584 | l2up_create(l2, DL_RELEASE_IND, 0, NULL); | ||
| 1585 | mISDN_FsmChangeState(fi, ST_L2_1); | ||
| 1586 | } | ||
| 1587 | |||
| 1588 | static void | ||
| 1589 | l2_st5_tei_remove(struct FsmInst *fi, int event, void *arg) | ||
| 1590 | { | ||
| 1591 | struct layer2 *l2 = fi->userdata; | ||
| 1592 | |||
| 1593 | skb_queue_purge(&l2->i_queue); | ||
| 1594 | skb_queue_purge(&l2->ui_queue); | ||
| 1595 | freewin(l2); | ||
| 1596 | l2->tei = GROUP_TEI; | ||
| 1597 | stop_t200(l2, 17); | ||
| 1598 | st5_dl_release_l2l3(l2); | ||
| 1599 | mISDN_FsmChangeState(fi, ST_L2_1); | ||
| 1600 | } | ||
| 1601 | |||
| 1602 | static void | ||
| 1603 | l2_st6_tei_remove(struct FsmInst *fi, int event, void *arg) | ||
| 1604 | { | ||
| 1605 | struct layer2 *l2 = fi->userdata; | ||
| 1606 | |||
| 1607 | skb_queue_purge(&l2->ui_queue); | ||
| 1608 | l2->tei = GROUP_TEI; | ||
| 1609 | stop_t200(l2, 18); | ||
| 1610 | l2up_create(l2, DL_RELEASE_IND, 0, NULL); | ||
| 1611 | mISDN_FsmChangeState(fi, ST_L2_1); | ||
| 1612 | } | ||
| 1613 | |||
| 1614 | static void | ||
| 1615 | l2_tei_remove(struct FsmInst *fi, int event, void *arg) | ||
| 1616 | { | ||
| 1617 | struct layer2 *l2 = fi->userdata; | ||
| 1618 | |||
| 1619 | skb_queue_purge(&l2->i_queue); | ||
| 1620 | skb_queue_purge(&l2->ui_queue); | ||
| 1621 | freewin(l2); | ||
| 1622 | l2->tei = GROUP_TEI; | ||
| 1623 | stop_t200(l2, 17); | ||
| 1624 | mISDN_FsmDelTimer(&l2->t203, 19); | ||
| 1625 | l2up_create(l2, DL_RELEASE_IND, 0, NULL); | ||
| 1626 | /* mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST, | ||
| 1627 | * MGR_SHORTSTATUS_IND, SSTATUS_L2_RELEASED, | ||
| 1628 | * 0, NULL, 0); | ||
| 1629 | */ | ||
| 1630 | mISDN_FsmChangeState(fi, ST_L2_1); | ||
| 1631 | } | ||
| 1632 | |||
| 1633 | static void | ||
| 1634 | l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg) | ||
| 1635 | { | ||
| 1636 | struct layer2 *l2 = fi->userdata; | ||
| 1637 | struct sk_buff *skb = arg; | ||
| 1638 | |||
| 1639 | skb_queue_purge(&l2->i_queue); | ||
| 1640 | skb_queue_purge(&l2->ui_queue); | ||
| 1641 | if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag)) | ||
| 1642 | l2up(l2, DL_RELEASE_IND, skb); | ||
| 1643 | else | ||
| 1644 | dev_kfree_skb(skb); | ||
| 1645 | } | ||
| 1646 | |||
| 1647 | static void | ||
| 1648 | l2_st5_persistant_da(struct FsmInst *fi, int event, void *arg) | ||
| 1649 | { | ||
| 1650 | struct layer2 *l2 = fi->userdata; | ||
| 1651 | struct sk_buff *skb = arg; | ||
| 1652 | |||
| 1653 | skb_queue_purge(&l2->i_queue); | ||
| 1654 | skb_queue_purge(&l2->ui_queue); | ||
| 1655 | freewin(l2); | ||
| 1656 | stop_t200(l2, 19); | ||
| 1657 | st5_dl_release_l2l3(l2); | ||
| 1658 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
| 1659 | if (l2->tm) | ||
| 1660 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
| 1661 | dev_kfree_skb(skb); | ||
| 1662 | } | ||
| 1663 | |||
| 1664 | static void | ||
| 1665 | l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg) | ||
| 1666 | { | ||
| 1667 | struct layer2 *l2 = fi->userdata; | ||
| 1668 | struct sk_buff *skb = arg; | ||
| 1669 | |||
| 1670 | skb_queue_purge(&l2->ui_queue); | ||
| 1671 | stop_t200(l2, 20); | ||
| 1672 | l2up(l2, DL_RELEASE_CNF, skb); | ||
| 1673 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
| 1674 | if (l2->tm) | ||
| 1675 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
| 1676 | } | ||
| 1677 | |||
| 1678 | static void | ||
| 1679 | l2_persistant_da(struct FsmInst *fi, int event, void *arg) | ||
| 1680 | { | ||
| 1681 | struct layer2 *l2 = fi->userdata; | ||
| 1682 | struct sk_buff *skb = arg; | ||
| 1683 | |||
| 1684 | skb_queue_purge(&l2->i_queue); | ||
| 1685 | skb_queue_purge(&l2->ui_queue); | ||
| 1686 | freewin(l2); | ||
| 1687 | stop_t200(l2, 19); | ||
| 1688 | mISDN_FsmDelTimer(&l2->t203, 19); | ||
| 1689 | l2up(l2, DL_RELEASE_IND, skb); | ||
| 1690 | mISDN_FsmChangeState(fi, ST_L2_4); | ||
| 1691 | if (l2->tm) | ||
| 1692 | l2_tei(l2, MDL_STATUS_DOWN_IND, 0); | ||
| 1693 | } | ||
| 1694 | |||
| 1695 | static void | ||
| 1696 | l2_set_own_busy(struct FsmInst *fi, int event, void *arg) | ||
| 1697 | { | ||
| 1698 | struct layer2 *l2 = fi->userdata; | ||
| 1699 | struct sk_buff *skb = arg; | ||
| 1700 | |||
| 1701 | if (!test_and_set_bit(FLG_OWN_BUSY, &l2->flag)) { | ||
| 1702 | enquiry_cr(l2, RNR, RSP, 0); | ||
| 1703 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
| 1704 | } | ||
| 1705 | if (skb) | ||
| 1706 | dev_kfree_skb(skb); | ||
| 1707 | } | ||
| 1708 | |||
| 1709 | static void | ||
| 1710 | l2_clear_own_busy(struct FsmInst *fi, int event, void *arg) | ||
| 1711 | { | ||
| 1712 | struct layer2 *l2 = fi->userdata; | ||
| 1713 | struct sk_buff *skb = arg; | ||
| 1714 | |||
| 1715 | if (!test_and_clear_bit(FLG_OWN_BUSY, &l2->flag)) { | ||
| 1716 | enquiry_cr(l2, RR, RSP, 0); | ||
| 1717 | test_and_clear_bit(FLG_ACK_PEND, &l2->flag); | ||
| 1718 | } | ||
| 1719 | if (skb) | ||
| 1720 | dev_kfree_skb(skb); | ||
| 1721 | } | ||
| 1722 | |||
| 1723 | static void | ||
| 1724 | l2_frame_error(struct FsmInst *fi, int event, void *arg) | ||
| 1725 | { | ||
| 1726 | struct layer2 *l2 = fi->userdata; | ||
| 1727 | |||
| 1728 | l2mgr(l2, MDL_ERROR_IND, arg); | ||
| 1729 | } | ||
| 1730 | |||
| 1731 | static void | ||
| 1732 | l2_frame_error_reest(struct FsmInst *fi, int event, void *arg) | ||
| 1733 | { | ||
| 1734 | struct layer2 *l2 = fi->userdata; | ||
| 1735 | |||
| 1736 | l2mgr(l2, MDL_ERROR_IND, arg); | ||
| 1737 | establishlink(fi); | ||
| 1738 | test_and_clear_bit(FLG_L3_INIT, &l2->flag); | ||
| 1739 | } | ||
| 1740 | |||
| 1741 | static struct FsmNode L2FnList[] = | ||
| 1742 | { | ||
| 1743 | {ST_L2_1, EV_L2_DL_ESTABLISH_REQ, l2_mdl_assign}, | ||
| 1744 | {ST_L2_2, EV_L2_DL_ESTABLISH_REQ, l2_go_st3}, | ||
| 1745 | {ST_L2_4, EV_L2_DL_ESTABLISH_REQ, l2_establish}, | ||
| 1746 | {ST_L2_5, EV_L2_DL_ESTABLISH_REQ, l2_discard_i_setl3}, | ||
| 1747 | {ST_L2_7, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish}, | ||
| 1748 | {ST_L2_8, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish}, | ||
| 1749 | {ST_L2_4, EV_L2_DL_RELEASE_REQ, l2_release}, | ||
| 1750 | {ST_L2_5, EV_L2_DL_RELEASE_REQ, l2_pend_rel}, | ||
| 1751 | {ST_L2_7, EV_L2_DL_RELEASE_REQ, l2_disconnect}, | ||
| 1752 | {ST_L2_8, EV_L2_DL_RELEASE_REQ, l2_disconnect}, | ||
| 1753 | {ST_L2_5, EV_L2_DL_DATA, l2_feed_i_if_reest}, | ||
| 1754 | {ST_L2_7, EV_L2_DL_DATA, l2_feed_i_pull}, | ||
| 1755 | {ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue}, | ||
| 1756 | {ST_L2_1, EV_L2_DL_UNITDATA, l2_queue_ui_assign}, | ||
| 1757 | {ST_L2_2, EV_L2_DL_UNITDATA, l2_queue_ui}, | ||
| 1758 | {ST_L2_3, EV_L2_DL_UNITDATA, l2_queue_ui}, | ||
| 1759 | {ST_L2_4, EV_L2_DL_UNITDATA, l2_send_ui}, | ||
| 1760 | {ST_L2_5, EV_L2_DL_UNITDATA, l2_send_ui}, | ||
| 1761 | {ST_L2_6, EV_L2_DL_UNITDATA, l2_send_ui}, | ||
| 1762 | {ST_L2_7, EV_L2_DL_UNITDATA, l2_send_ui}, | ||
| 1763 | {ST_L2_8, EV_L2_DL_UNITDATA, l2_send_ui}, | ||
| 1764 | {ST_L2_1, EV_L2_MDL_ASSIGN, l2_got_tei}, | ||
| 1765 | {ST_L2_2, EV_L2_MDL_ASSIGN, l2_got_tei}, | ||
| 1766 | {ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei}, | ||
| 1767 | {ST_L2_2, EV_L2_MDL_ERROR, l2_st24_tei_remove}, | ||
| 1768 | {ST_L2_3, EV_L2_MDL_ERROR, l2_st3_tei_remove}, | ||
| 1769 | {ST_L2_4, EV_L2_MDL_REMOVE, l2_st24_tei_remove}, | ||
| 1770 | {ST_L2_5, EV_L2_MDL_REMOVE, l2_st5_tei_remove}, | ||
| 1771 | {ST_L2_6, EV_L2_MDL_REMOVE, l2_st6_tei_remove}, | ||
| 1772 | {ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove}, | ||
| 1773 | {ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove}, | ||
| 1774 | {ST_L2_4, EV_L2_SABME, l2_start_multi}, | ||
| 1775 | {ST_L2_5, EV_L2_SABME, l2_send_UA}, | ||
| 1776 | {ST_L2_6, EV_L2_SABME, l2_send_DM}, | ||
| 1777 | {ST_L2_7, EV_L2_SABME, l2_restart_multi}, | ||
| 1778 | {ST_L2_8, EV_L2_SABME, l2_restart_multi}, | ||
| 1779 | {ST_L2_4, EV_L2_DISC, l2_send_DM}, | ||
| 1780 | {ST_L2_5, EV_L2_DISC, l2_send_DM}, | ||
| 1781 | {ST_L2_6, EV_L2_DISC, l2_send_UA}, | ||
| 1782 | {ST_L2_7, EV_L2_DISC, l2_stop_multi}, | ||
| 1783 | {ST_L2_8, EV_L2_DISC, l2_stop_multi}, | ||
| 1784 | {ST_L2_4, EV_L2_UA, l2_mdl_error_ua}, | ||
| 1785 | {ST_L2_5, EV_L2_UA, l2_connected}, | ||
| 1786 | {ST_L2_6, EV_L2_UA, l2_released}, | ||
| 1787 | {ST_L2_7, EV_L2_UA, l2_mdl_error_ua}, | ||
| 1788 | {ST_L2_8, EV_L2_UA, l2_mdl_error_ua}, | ||
| 1789 | {ST_L2_4, EV_L2_DM, l2_reestablish}, | ||
| 1790 | {ST_L2_5, EV_L2_DM, l2_st5_dm_release}, | ||
| 1791 | {ST_L2_6, EV_L2_DM, l2_st6_dm_release}, | ||
| 1792 | {ST_L2_7, EV_L2_DM, l2_mdl_error_dm}, | ||
| 1793 | {ST_L2_8, EV_L2_DM, l2_st8_mdl_error_dm}, | ||
| 1794 | {ST_L2_1, EV_L2_UI, l2_got_ui}, | ||
| 1795 | {ST_L2_2, EV_L2_UI, l2_got_ui}, | ||
| 1796 | {ST_L2_3, EV_L2_UI, l2_got_ui}, | ||
| 1797 | {ST_L2_4, EV_L2_UI, l2_got_ui}, | ||
| 1798 | {ST_L2_5, EV_L2_UI, l2_got_ui}, | ||
| 1799 | {ST_L2_6, EV_L2_UI, l2_got_ui}, | ||
| 1800 | {ST_L2_7, EV_L2_UI, l2_got_ui}, | ||
| 1801 | {ST_L2_8, EV_L2_UI, l2_got_ui}, | ||
| 1802 | {ST_L2_7, EV_L2_FRMR, l2_got_FRMR}, | ||
| 1803 | {ST_L2_8, EV_L2_FRMR, l2_got_FRMR}, | ||
| 1804 | {ST_L2_7, EV_L2_SUPER, l2_st7_got_super}, | ||
| 1805 | {ST_L2_8, EV_L2_SUPER, l2_st8_got_super}, | ||
| 1806 | {ST_L2_7, EV_L2_I, l2_got_iframe}, | ||
| 1807 | {ST_L2_8, EV_L2_I, l2_got_iframe}, | ||
| 1808 | {ST_L2_5, EV_L2_T200, l2_st5_tout_200}, | ||
| 1809 | {ST_L2_6, EV_L2_T200, l2_st6_tout_200}, | ||
| 1810 | {ST_L2_7, EV_L2_T200, l2_st7_tout_200}, | ||
| 1811 | {ST_L2_8, EV_L2_T200, l2_st8_tout_200}, | ||
| 1812 | {ST_L2_7, EV_L2_T203, l2_st7_tout_203}, | ||
| 1813 | {ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue}, | ||
| 1814 | {ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, | ||
| 1815 | {ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, | ||
| 1816 | {ST_L2_7, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy}, | ||
| 1817 | {ST_L2_8, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy}, | ||
| 1818 | {ST_L2_4, EV_L2_FRAME_ERROR, l2_frame_error}, | ||
| 1819 | {ST_L2_5, EV_L2_FRAME_ERROR, l2_frame_error}, | ||
| 1820 | {ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error}, | ||
| 1821 | {ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest}, | ||
| 1822 | {ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest}, | ||
| 1823 | {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistant_da}, | ||
| 1824 | {ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove}, | ||
| 1825 | {ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove}, | ||
| 1826 | {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistant_da}, | ||
| 1827 | {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistant_da}, | ||
| 1828 | {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistant_da}, | ||
| 1829 | {ST_L2_7, EV_L1_DEACTIVATE, l2_persistant_da}, | ||
| 1830 | {ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da}, | ||
| 1831 | }; | ||
| 1832 | |||
| 1833 | #define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode)) | ||
| 1834 | |||
| 1835 | static int | ||
| 1836 | ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) | ||
| 1837 | { | ||
| 1838 | u_char *datap = skb->data; | ||
| 1839 | int ret = -EINVAL; | ||
| 1840 | int psapi, ptei; | ||
| 1841 | u_int l; | ||
| 1842 | int c = 0; | ||
| 1843 | |||
| 1844 | l = l2addrsize(l2); | ||
| 1845 | if (skb->len <= l) { | ||
| 1846 | mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *) 'N'); | ||
| 1847 | return ret; | ||
| 1848 | } | ||
| 1849 | if (test_bit(FLG_LAPD, &l2->flag)) { /* Maybe not needed */ | ||
| 1850 | psapi = *datap++; | ||
| 1851 | ptei = *datap++; | ||
| 1852 | if ((psapi & 1) || !(ptei & 1)) { | ||
| 1853 | printk(KERN_WARNING | ||
| 1854 | "l2 D-channel frame wrong EA0/EA1\n"); | ||
| 1855 | return ret; | ||
| 1856 | } | ||
| 1857 | psapi >>= 2; | ||
| 1858 | ptei >>= 1; | ||
| 1859 | if (psapi != l2->sapi) { | ||
| 1860 | /* not our bussiness | ||
| 1861 | * printk(KERN_DEBUG "%s: sapi %d/%d sapi mismatch\n", | ||
| 1862 | * __func__, | ||
| 1863 | * psapi, l2->sapi); | ||
| 1864 | */ | ||
| 1865 | dev_kfree_skb(skb); | ||
| 1866 | return 0; | ||
| 1867 | } | ||
| 1868 | if ((ptei != l2->tei) && (ptei != GROUP_TEI)) { | ||
| 1869 | /* not our bussiness | ||
| 1870 | * printk(KERN_DEBUG "%s: tei %d/%d sapi %d mismatch\n", | ||
| 1871 | * __func__, | ||
| 1872 | * ptei, l2->tei, psapi); | ||
| 1873 | */ | ||
| 1874 | dev_kfree_skb(skb); | ||
| 1875 | return 0; | ||
| 1876 | } | ||
| 1877 | } else | ||
| 1878 | datap += l; | ||
| 1879 | if (!(*datap & 1)) { /* I-Frame */ | ||
| 1880 | c = iframe_error(l2, skb); | ||
| 1881 | if (!c) | ||
| 1882 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_I, skb); | ||
| 1883 | } else if (IsSFrame(datap, l2)) { /* S-Frame */ | ||
| 1884 | c = super_error(l2, skb); | ||
| 1885 | if (!c) | ||
| 1886 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_SUPER, skb); | ||
| 1887 | } else if (IsUI(datap)) { | ||
| 1888 | c = UI_error(l2, skb); | ||
| 1889 | if (!c) | ||
| 1890 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_UI, skb); | ||
| 1891 | } else if (IsSABME(datap, l2)) { | ||
| 1892 | c = unnum_error(l2, skb, CMD); | ||
| 1893 | if (!c) | ||
| 1894 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_SABME, skb); | ||
| 1895 | } else if (IsUA(datap)) { | ||
| 1896 | c = unnum_error(l2, skb, RSP); | ||
| 1897 | if (!c) | ||
| 1898 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_UA, skb); | ||
| 1899 | } else if (IsDISC(datap)) { | ||
| 1900 | c = unnum_error(l2, skb, CMD); | ||
| 1901 | if (!c) | ||
| 1902 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DISC, skb); | ||
| 1903 | } else if (IsDM(datap)) { | ||
| 1904 | c = unnum_error(l2, skb, RSP); | ||
| 1905 | if (!c) | ||
| 1906 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DM, skb); | ||
| 1907 | } else if (IsFRMR(datap)) { | ||
| 1908 | c = FRMR_error(l2, skb); | ||
| 1909 | if (!c) | ||
| 1910 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_FRMR, skb); | ||
| 1911 | } else | ||
| 1912 | c = 'L'; | ||
| 1913 | if (c) { | ||
| 1914 | printk(KERN_WARNING "l2 D-channel frame error %c\n", c); | ||
| 1915 | mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *)(long)c); | ||
| 1916 | } | ||
| 1917 | return ret; | ||
| 1918 | } | ||
| 1919 | |||
| 1920 | static int | ||
| 1921 | l2_send(struct mISDNchannel *ch, struct sk_buff *skb) | ||
| 1922 | { | ||
| 1923 | struct layer2 *l2 = container_of(ch, struct layer2, ch); | ||
| 1924 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
| 1925 | int ret = -EINVAL; | ||
| 1926 | |||
| 1927 | if (*debug & DEBUG_L2_RECV) | ||
| 1928 | printk(KERN_DEBUG "%s: prim(%x) id(%x) tei(%d)\n", | ||
| 1929 | __func__, hh->prim, hh->id, l2->tei); | ||
| 1930 | switch (hh->prim) { | ||
| 1931 | case PH_DATA_IND: | ||
| 1932 | ret = ph_data_indication(l2, hh, skb); | ||
| 1933 | break; | ||
| 1934 | case PH_DATA_CNF: | ||
| 1935 | ret = ph_data_confirm(l2, hh, skb); | ||
| 1936 | break; | ||
| 1937 | case PH_ACTIVATE_IND: | ||
| 1938 | test_and_set_bit(FLG_L1_ACTIV, &l2->flag); | ||
| 1939 | l2up_create(l2, MPH_ACTIVATE_IND, 0, NULL); | ||
| 1940 | if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag)) | ||
| 1941 | ret = mISDN_FsmEvent(&l2->l2m, | ||
| 1942 | EV_L2_DL_ESTABLISH_REQ, skb); | ||
| 1943 | break; | ||
| 1944 | case PH_DEACTIVATE_IND: | ||
| 1945 | test_and_clear_bit(FLG_L1_ACTIV, &l2->flag); | ||
| 1946 | l2up_create(l2, MPH_DEACTIVATE_IND, 0, NULL); | ||
| 1947 | ret = mISDN_FsmEvent(&l2->l2m, EV_L1_DEACTIVATE, skb); | ||
| 1948 | break; | ||
| 1949 | case MPH_INFORMATION_IND: | ||
| 1950 | if (!l2->up) | ||
| 1951 | break; | ||
| 1952 | ret = l2->up->send(l2->up, skb); | ||
| 1953 | break; | ||
| 1954 | case DL_DATA_REQ: | ||
| 1955 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_DATA, skb); | ||
| 1956 | break; | ||
| 1957 | case DL_UNITDATA_REQ: | ||
| 1958 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_UNITDATA, skb); | ||
| 1959 | break; | ||
| 1960 | case DL_ESTABLISH_REQ: | ||
| 1961 | if (test_bit(FLG_LAPB, &l2->flag)) | ||
| 1962 | test_and_set_bit(FLG_ORIG, &l2->flag); | ||
| 1963 | if (test_bit(FLG_L1_ACTIV, &l2->flag)) { | ||
| 1964 | if (test_bit(FLG_LAPD, &l2->flag) || | ||
| 1965 | test_bit(FLG_ORIG, &l2->flag)) | ||
| 1966 | ret = mISDN_FsmEvent(&l2->l2m, | ||
| 1967 | EV_L2_DL_ESTABLISH_REQ, skb); | ||
| 1968 | } else { | ||
| 1969 | if (test_bit(FLG_LAPD, &l2->flag) || | ||
| 1970 | test_bit(FLG_ORIG, &l2->flag)) { | ||
| 1971 | test_and_set_bit(FLG_ESTAB_PEND, | ||
| 1972 | &l2->flag); | ||
| 1973 | } | ||
| 1974 | ret = l2down(l2, PH_ACTIVATE_REQ, l2_newid(l2), | ||
| 1975 | skb); | ||
| 1976 | } | ||
| 1977 | break; | ||
| 1978 | case DL_RELEASE_REQ: | ||
| 1979 | if (test_bit(FLG_LAPB, &l2->flag)) | ||
| 1980 | l2down_create(l2, PH_DEACTIVATE_REQ, | ||
| 1981 | l2_newid(l2), 0, NULL); | ||
| 1982 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_RELEASE_REQ, | ||
| 1983 | skb); | ||
| 1984 | break; | ||
| 1985 | default: | ||
| 1986 | if (*debug & DEBUG_L2) | ||
| 1987 | l2m_debug(&l2->l2m, "l2 unknown pr %04x", | ||
| 1988 | hh->prim); | ||
| 1989 | } | ||
| 1990 | if (ret) { | ||
| 1991 | dev_kfree_skb(skb); | ||
| 1992 | ret = 0; | ||
| 1993 | } | ||
| 1994 | return ret; | ||
| 1995 | } | ||
| 1996 | |||
| 1997 | int | ||
| 1998 | tei_l2(struct layer2 *l2, u_int cmd, u_long arg) | ||
| 1999 | { | ||
| 2000 | int ret = -EINVAL; | ||
| 2001 | |||
| 2002 | if (*debug & DEBUG_L2_TEI) | ||
| 2003 | printk(KERN_DEBUG "%s: cmd(%x)\n", __func__, cmd); | ||
| 2004 | switch (cmd) { | ||
| 2005 | case (MDL_ASSIGN_REQ): | ||
| 2006 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ASSIGN, (void *)arg); | ||
| 2007 | break; | ||
| 2008 | case (MDL_REMOVE_REQ): | ||
| 2009 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_REMOVE, NULL); | ||
| 2010 | break; | ||
| 2011 | case (MDL_ERROR_IND): | ||
| 2012 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL); | ||
| 2013 | break; | ||
| 2014 | case (MDL_ERROR_RSP): | ||
| 2015 | /* ETS 300-125 5.3.2.1 Test: TC13010 */ | ||
| 2016 | printk(KERN_NOTICE "MDL_ERROR|REQ (tei_l2)\n"); | ||
| 2017 | ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL); | ||
| 2018 | break; | ||
| 2019 | } | ||
| 2020 | return ret; | ||
| 2021 | } | ||
| 2022 | |||
| 2023 | static void | ||
| 2024 | release_l2(struct layer2 *l2) | ||
| 2025 | { | ||
| 2026 | mISDN_FsmDelTimer(&l2->t200, 21); | ||
| 2027 | mISDN_FsmDelTimer(&l2->t203, 16); | ||
| 2028 | skb_queue_purge(&l2->i_queue); | ||
| 2029 | skb_queue_purge(&l2->ui_queue); | ||
| 2030 | skb_queue_purge(&l2->down_queue); | ||
| 2031 | ReleaseWin(l2); | ||
| 2032 | if (test_bit(FLG_LAPD, &l2->flag)) { | ||
| 2033 | TEIrelease(l2); | ||
| 2034 | if (l2->ch.st) | ||
| 2035 | l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, | ||
| 2036 | CLOSE_CHANNEL, NULL); | ||
| 2037 | } | ||
| 2038 | kfree(l2); | ||
| 2039 | } | ||
| 2040 | |||
| 2041 | static int | ||
| 2042 | l2_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
| 2043 | { | ||
| 2044 | struct layer2 *l2 = container_of(ch, struct layer2, ch); | ||
| 2045 | u_int info; | ||
| 2046 | |||
| 2047 | if (*debug & DEBUG_L2_CTRL) | ||
| 2048 | printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd); | ||
| 2049 | |||
| 2050 | switch (cmd) { | ||
| 2051 | case OPEN_CHANNEL: | ||
| 2052 | if (test_bit(FLG_LAPD, &l2->flag)) { | ||
| 2053 | set_channel_address(&l2->ch, l2->sapi, l2->tei); | ||
| 2054 | info = DL_INFO_L2_CONNECT; | ||
| 2055 | l2up_create(l2, DL_INFORMATION_IND, | ||
| 2056 | sizeof(info), &info); | ||
| 2057 | } | ||
| 2058 | break; | ||
| 2059 | case CLOSE_CHANNEL: | ||
| 2060 | if (l2->ch.peer) | ||
| 2061 | l2->ch.peer->ctrl(l2->ch.peer, CLOSE_CHANNEL, NULL); | ||
| 2062 | release_l2(l2); | ||
| 2063 | break; | ||
| 2064 | } | ||
| 2065 | return 0; | ||
| 2066 | } | ||
| 2067 | |||
| 2068 | struct layer2 * | ||
| 2069 | create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) | ||
| 2070 | { | ||
| 2071 | struct layer2 *l2; | ||
| 2072 | struct channel_req rq; | ||
| 2073 | |||
| 2074 | l2 = kzalloc(sizeof(struct layer2), GFP_KERNEL); | ||
| 2075 | if (!l2) { | ||
| 2076 | printk(KERN_ERR "kzalloc layer2 failed\n"); | ||
| 2077 | return NULL; | ||
| 2078 | } | ||
| 2079 | l2->next_id = 1; | ||
| 2080 | l2->down_id = MISDN_ID_NONE; | ||
| 2081 | l2->up = ch; | ||
| 2082 | l2->ch.st = ch->st; | ||
| 2083 | l2->ch.send = l2_send; | ||
| 2084 | l2->ch.ctrl = l2_ctrl; | ||
| 2085 | switch (protocol) { | ||
| 2086 | case ISDN_P_LAPD_NT: | ||
| 2087 | test_and_set_bit(FLG_LAPD, &l2->flag); | ||
| 2088 | test_and_set_bit(FLG_LAPD_NET, &l2->flag); | ||
| 2089 | test_and_set_bit(FLG_MOD128, &l2->flag); | ||
| 2090 | l2->sapi = 0; | ||
| 2091 | l2->maxlen = MAX_DFRAME_LEN; | ||
| 2092 | if (test_bit(OPTION_L2_PMX, &options)) | ||
| 2093 | l2->window = 7; | ||
| 2094 | else | ||
| 2095 | l2->window = 1; | ||
| 2096 | if (test_bit(OPTION_L2_PTP, &options)) | ||
| 2097 | test_and_set_bit(FLG_PTP, &l2->flag); | ||
| 2098 | if (test_bit(OPTION_L2_FIXEDTEI, &options)) | ||
| 2099 | test_and_set_bit(FLG_FIXED_TEI, &l2->flag); | ||
| 2100 | l2->tei = (u_int)arg; | ||
| 2101 | l2->T200 = 1000; | ||
| 2102 | l2->N200 = 3; | ||
| 2103 | l2->T203 = 10000; | ||
| 2104 | if (test_bit(OPTION_L2_PMX, &options)) | ||
| 2105 | rq.protocol = ISDN_P_NT_E1; | ||
| 2106 | else | ||
| 2107 | rq.protocol = ISDN_P_NT_S0; | ||
| 2108 | rq.adr.channel = 0; | ||
| 2109 | l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, OPEN_CHANNEL, &rq); | ||
| 2110 | break; | ||
| 2111 | case ISDN_P_LAPD_TE: | ||
| 2112 | test_and_set_bit(FLG_LAPD, &l2->flag); | ||
| 2113 | test_and_set_bit(FLG_MOD128, &l2->flag); | ||
| 2114 | test_and_set_bit(FLG_ORIG, &l2->flag); | ||
| 2115 | l2->sapi = 0; | ||
| 2116 | l2->maxlen = MAX_DFRAME_LEN; | ||
| 2117 | if (test_bit(OPTION_L2_PMX, &options)) | ||
| 2118 | l2->window = 7; | ||
| 2119 | else | ||
| 2120 | l2->window = 1; | ||
| 2121 | if (test_bit(OPTION_L2_PTP, &options)) | ||
| 2122 | test_and_set_bit(FLG_PTP, &l2->flag); | ||
| 2123 | if (test_bit(OPTION_L2_FIXEDTEI, &options)) | ||
| 2124 | test_and_set_bit(FLG_FIXED_TEI, &l2->flag); | ||
| 2125 | l2->tei = (u_int)arg; | ||
| 2126 | l2->T200 = 1000; | ||
| 2127 | l2->N200 = 3; | ||
| 2128 | l2->T203 = 10000; | ||
| 2129 | if (test_bit(OPTION_L2_PMX, &options)) | ||
| 2130 | rq.protocol = ISDN_P_TE_E1; | ||
| 2131 | else | ||
| 2132 | rq.protocol = ISDN_P_TE_S0; | ||
| 2133 | rq.adr.channel = 0; | ||
| 2134 | l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, OPEN_CHANNEL, &rq); | ||
| 2135 | break; | ||
| 2136 | case ISDN_P_B_X75SLP: | ||
| 2137 | test_and_set_bit(FLG_LAPB, &l2->flag); | ||
| 2138 | l2->window = 7; | ||
| 2139 | l2->maxlen = MAX_DATA_SIZE; | ||
| 2140 | l2->T200 = 1000; | ||
| 2141 | l2->N200 = 4; | ||
| 2142 | l2->T203 = 5000; | ||
| 2143 | l2->addr.A = 3; | ||
| 2144 | l2->addr.B = 1; | ||
| 2145 | break; | ||
| 2146 | default: | ||
| 2147 | printk(KERN_ERR "layer2 create failed prt %x\n", | ||
| 2148 | protocol); | ||
| 2149 | kfree(l2); | ||
| 2150 | return NULL; | ||
| 2151 | } | ||
| 2152 | skb_queue_head_init(&l2->i_queue); | ||
| 2153 | skb_queue_head_init(&l2->ui_queue); | ||
| 2154 | skb_queue_head_init(&l2->down_queue); | ||
| 2155 | skb_queue_head_init(&l2->tmp_queue); | ||
| 2156 | InitWin(l2); | ||
| 2157 | l2->l2m.fsm = &l2fsm; | ||
| 2158 | if (test_bit(FLG_LAPB, &l2->flag) || | ||
| 2159 | test_bit(FLG_PTP, &l2->flag) || | ||
| 2160 | test_bit(FLG_LAPD_NET, &l2->flag)) | ||
| 2161 | l2->l2m.state = ST_L2_4; | ||
| 2162 | else | ||
| 2163 | l2->l2m.state = ST_L2_1; | ||
| 2164 | l2->l2m.debug = *debug; | ||
| 2165 | l2->l2m.userdata = l2; | ||
| 2166 | l2->l2m.userint = 0; | ||
| 2167 | l2->l2m.printdebug = l2m_debug; | ||
| 2168 | |||
| 2169 | mISDN_FsmInitTimer(&l2->l2m, &l2->t200); | ||
| 2170 | mISDN_FsmInitTimer(&l2->l2m, &l2->t203); | ||
| 2171 | return l2; | ||
| 2172 | } | ||
| 2173 | |||
| 2174 | static int | ||
| 2175 | x75create(struct channel_req *crq) | ||
| 2176 | { | ||
| 2177 | struct layer2 *l2; | ||
| 2178 | |||
| 2179 | if (crq->protocol != ISDN_P_B_X75SLP) | ||
| 2180 | return -EPROTONOSUPPORT; | ||
| 2181 | l2 = create_l2(crq->ch, crq->protocol, 0, 0); | ||
| 2182 | if (!l2) | ||
| 2183 | return -ENOMEM; | ||
| 2184 | crq->ch = &l2->ch; | ||
| 2185 | crq->protocol = ISDN_P_B_HDLC; | ||
| 2186 | return 0; | ||
| 2187 | } | ||
| 2188 | |||
| 2189 | static struct Bprotocol X75SLP = { | ||
| 2190 | .Bprotocols = (1 << (ISDN_P_B_X75SLP & ISDN_P_B_MASK)), | ||
| 2191 | .name = "X75SLP", | ||
| 2192 | .create = x75create | ||
| 2193 | }; | ||
| 2194 | |||
| 2195 | int | ||
| 2196 | Isdnl2_Init(u_int *deb) | ||
| 2197 | { | ||
| 2198 | debug = deb; | ||
| 2199 | mISDN_register_Bprotocol(&X75SLP); | ||
| 2200 | l2fsm.state_count = L2_STATE_COUNT; | ||
| 2201 | l2fsm.event_count = L2_EVENT_COUNT; | ||
| 2202 | l2fsm.strEvent = strL2Event; | ||
| 2203 | l2fsm.strState = strL2State; | ||
| 2204 | mISDN_FsmNew(&l2fsm, L2FnList, ARRAY_SIZE(L2FnList)); | ||
| 2205 | TEIInit(deb); | ||
| 2206 | return 0; | ||
| 2207 | } | ||
| 2208 | |||
| 2209 | void | ||
| 2210 | Isdnl2_cleanup(void) | ||
| 2211 | { | ||
| 2212 | mISDN_unregister_Bprotocol(&X75SLP); | ||
| 2213 | TEIFree(); | ||
| 2214 | mISDN_FsmFree(&l2fsm); | ||
| 2215 | } | ||
| 2216 | |||
diff --git a/drivers/isdn/mISDN/layer2.h b/drivers/isdn/mISDN/layer2.h new file mode 100644 index 000000000000..6293f80dc2d3 --- /dev/null +++ b/drivers/isdn/mISDN/layer2.h | |||
| @@ -0,0 +1,140 @@ | |||
| 1 | /* | ||
| 2 | * Layer 2 defines | ||
| 3 | * | ||
| 4 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/mISDNif.h> | ||
| 18 | #include <linux/skbuff.h> | ||
| 19 | #include "fsm.h" | ||
| 20 | |||
| 21 | #define MAX_WINDOW 8 | ||
| 22 | |||
| 23 | struct manager { | ||
| 24 | struct mISDNchannel ch; | ||
| 25 | struct mISDNchannel bcast; | ||
| 26 | u_long options; | ||
| 27 | struct list_head layer2; | ||
| 28 | rwlock_t lock; | ||
| 29 | struct FsmInst deact; | ||
| 30 | struct FsmTimer datimer; | ||
| 31 | struct sk_buff_head sendq; | ||
| 32 | struct mISDNchannel *up; | ||
| 33 | u_int nextid; | ||
| 34 | u_int lastid; | ||
| 35 | }; | ||
| 36 | |||
| 37 | struct teimgr { | ||
| 38 | int ri; | ||
| 39 | int rcnt; | ||
| 40 | struct FsmInst tei_m; | ||
| 41 | struct FsmTimer timer; | ||
| 42 | int tval, nval; | ||
| 43 | struct layer2 *l2; | ||
| 44 | struct manager *mgr; | ||
| 45 | }; | ||
| 46 | |||
| 47 | struct laddr { | ||
| 48 | u_char A; | ||
| 49 | u_char B; | ||
| 50 | }; | ||
| 51 | |||
| 52 | struct layer2 { | ||
| 53 | struct list_head list; | ||
| 54 | struct mISDNchannel ch; | ||
| 55 | u_long flag; | ||
| 56 | int id; | ||
| 57 | struct mISDNchannel *up; | ||
| 58 | signed char sapi; | ||
| 59 | signed char tei; | ||
| 60 | struct laddr addr; | ||
| 61 | u_int maxlen; | ||
| 62 | struct teimgr *tm; | ||
| 63 | u_int vs, va, vr; | ||
| 64 | int rc; | ||
| 65 | u_int window; | ||
| 66 | u_int sow; | ||
| 67 | struct FsmInst l2m; | ||
| 68 | struct FsmTimer t200, t203; | ||
| 69 | int T200, N200, T203; | ||
| 70 | u_int next_id; | ||
| 71 | u_int down_id; | ||
| 72 | struct sk_buff *windowar[MAX_WINDOW]; | ||
| 73 | struct sk_buff_head i_queue; | ||
| 74 | struct sk_buff_head ui_queue; | ||
| 75 | struct sk_buff_head down_queue; | ||
| 76 | struct sk_buff_head tmp_queue; | ||
| 77 | }; | ||
| 78 | |||
| 79 | enum { | ||
| 80 | ST_L2_1, | ||
| 81 | ST_L2_2, | ||
| 82 | ST_L2_3, | ||
| 83 | ST_L2_4, | ||
| 84 | ST_L2_5, | ||
| 85 | ST_L2_6, | ||
| 86 | ST_L2_7, | ||
| 87 | ST_L2_8, | ||
| 88 | }; | ||
| 89 | |||
| 90 | #define L2_STATE_COUNT (ST_L2_8+1) | ||
| 91 | |||
| 92 | extern struct layer2 *create_l2(struct mISDNchannel *, u_int, | ||
| 93 | u_long, u_long); | ||
| 94 | extern int tei_l2(struct layer2 *, u_int, u_long arg); | ||
| 95 | |||
| 96 | |||
| 97 | /* from tei.c */ | ||
| 98 | extern int l2_tei(struct layer2 *, u_int, u_long arg); | ||
| 99 | extern void TEIrelease(struct layer2 *); | ||
| 100 | extern int TEIInit(u_int *); | ||
| 101 | extern void TEIFree(void); | ||
| 102 | |||
| 103 | #define MAX_L2HEADER_LEN 4 | ||
| 104 | |||
| 105 | #define RR 0x01 | ||
| 106 | #define RNR 0x05 | ||
| 107 | #define REJ 0x09 | ||
| 108 | #define SABME 0x6f | ||
| 109 | #define SABM 0x2f | ||
| 110 | #define DM 0x0f | ||
| 111 | #define UI 0x03 | ||
| 112 | #define DISC 0x43 | ||
| 113 | #define UA 0x63 | ||
| 114 | #define FRMR 0x87 | ||
| 115 | #define XID 0xaf | ||
| 116 | |||
| 117 | #define CMD 0 | ||
| 118 | #define RSP 1 | ||
| 119 | |||
| 120 | #define LC_FLUSH_WAIT 1 | ||
| 121 | |||
| 122 | #define FLG_LAPB 0 | ||
| 123 | #define FLG_LAPD 1 | ||
| 124 | #define FLG_ORIG 2 | ||
| 125 | #define FLG_MOD128 3 | ||
| 126 | #define FLG_PEND_REL 4 | ||
| 127 | #define FLG_L3_INIT 5 | ||
| 128 | #define FLG_T200_RUN 6 | ||
| 129 | #define FLG_ACK_PEND 7 | ||
| 130 | #define FLG_REJEXC 8 | ||
| 131 | #define FLG_OWN_BUSY 9 | ||
| 132 | #define FLG_PEER_BUSY 10 | ||
| 133 | #define FLG_DCHAN_BUSY 11 | ||
| 134 | #define FLG_L1_ACTIV 12 | ||
| 135 | #define FLG_ESTAB_PEND 13 | ||
| 136 | #define FLG_PTP 14 | ||
| 137 | #define FLG_FIXED_TEI 15 | ||
| 138 | #define FLG_L2BLOCK 16 | ||
| 139 | #define FLG_L1_NOTREADY 17 | ||
| 140 | #define FLG_LAPD_NET 18 | ||
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c new file mode 100644 index 000000000000..4ba4cc364c9e --- /dev/null +++ b/drivers/isdn/mISDN/socket.c | |||
| @@ -0,0 +1,781 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * Author Karsten Keil <kkeil@novell.com> | ||
| 4 | * | ||
| 5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/mISDNif.h> | ||
| 19 | #include "core.h" | ||
| 20 | |||
| 21 | static int *debug; | ||
| 22 | |||
| 23 | static struct proto mISDN_proto = { | ||
| 24 | .name = "misdn", | ||
| 25 | .owner = THIS_MODULE, | ||
| 26 | .obj_size = sizeof(struct mISDN_sock) | ||
| 27 | }; | ||
| 28 | |||
| 29 | #define _pms(sk) ((struct mISDN_sock *)sk) | ||
| 30 | |||
| 31 | static struct mISDN_sock_list data_sockets = { | ||
| 32 | .lock = __RW_LOCK_UNLOCKED(data_sockets.lock) | ||
| 33 | }; | ||
| 34 | |||
| 35 | static struct mISDN_sock_list base_sockets = { | ||
| 36 | .lock = __RW_LOCK_UNLOCKED(base_sockets.lock) | ||
| 37 | }; | ||
| 38 | |||
| 39 | #define L2_HEADER_LEN 4 | ||
| 40 | |||
| 41 | static inline struct sk_buff * | ||
| 42 | _l2_alloc_skb(unsigned int len, gfp_t gfp_mask) | ||
| 43 | { | ||
| 44 | struct sk_buff *skb; | ||
| 45 | |||
| 46 | skb = alloc_skb(len + L2_HEADER_LEN, gfp_mask); | ||
| 47 | if (likely(skb)) | ||
| 48 | skb_reserve(skb, L2_HEADER_LEN); | ||
| 49 | return skb; | ||
| 50 | } | ||
| 51 | |||
| 52 | static void | ||
| 53 | mISDN_sock_link(struct mISDN_sock_list *l, struct sock *sk) | ||
| 54 | { | ||
| 55 | write_lock_bh(&l->lock); | ||
| 56 | sk_add_node(sk, &l->head); | ||
| 57 | write_unlock_bh(&l->lock); | ||
| 58 | } | ||
| 59 | |||
| 60 | static void mISDN_sock_unlink(struct mISDN_sock_list *l, struct sock *sk) | ||
| 61 | { | ||
| 62 | write_lock_bh(&l->lock); | ||
| 63 | sk_del_node_init(sk); | ||
| 64 | write_unlock_bh(&l->lock); | ||
| 65 | } | ||
| 66 | |||
| 67 | static int | ||
| 68 | mISDN_send(struct mISDNchannel *ch, struct sk_buff *skb) | ||
| 69 | { | ||
| 70 | struct mISDN_sock *msk; | ||
| 71 | int err; | ||
| 72 | |||
| 73 | msk = container_of(ch, struct mISDN_sock, ch); | ||
| 74 | if (*debug & DEBUG_SOCKET) | ||
| 75 | printk(KERN_DEBUG "%s len %d %p\n", __func__, skb->len, skb); | ||
| 76 | if (msk->sk.sk_state == MISDN_CLOSED) | ||
| 77 | return -EUNATCH; | ||
| 78 | __net_timestamp(skb); | ||
| 79 | err = sock_queue_rcv_skb(&msk->sk, skb); | ||
| 80 | if (err) | ||
| 81 | printk(KERN_WARNING "%s: error %d\n", __func__, err); | ||
| 82 | return err; | ||
| 83 | } | ||
| 84 | |||
| 85 | static int | ||
| 86 | mISDN_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
| 87 | { | ||
| 88 | struct mISDN_sock *msk; | ||
| 89 | |||
| 90 | msk = container_of(ch, struct mISDN_sock, ch); | ||
| 91 | if (*debug & DEBUG_SOCKET) | ||
| 92 | printk(KERN_DEBUG "%s(%p, %x, %p)\n", __func__, ch, cmd, arg); | ||
| 93 | switch (cmd) { | ||
| 94 | case CLOSE_CHANNEL: | ||
| 95 | msk->sk.sk_state = MISDN_CLOSED; | ||
| 96 | break; | ||
| 97 | } | ||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | |||
| 101 | static inline void | ||
| 102 | mISDN_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) | ||
| 103 | { | ||
| 104 | struct timeval tv; | ||
| 105 | |||
| 106 | if (_pms(sk)->cmask & MISDN_TIME_STAMP) { | ||
| 107 | skb_get_timestamp(skb, &tv); | ||
| 108 | put_cmsg(msg, SOL_MISDN, MISDN_TIME_STAMP, sizeof(tv), &tv); | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | static int | ||
| 113 | mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock, | ||
| 114 | struct msghdr *msg, size_t len, int flags) | ||
| 115 | { | ||
| 116 | struct sk_buff *skb; | ||
| 117 | struct sock *sk = sock->sk; | ||
| 118 | struct sockaddr_mISDN *maddr; | ||
| 119 | |||
| 120 | int copied, err; | ||
| 121 | |||
| 122 | if (*debug & DEBUG_SOCKET) | ||
| 123 | printk(KERN_DEBUG "%s: len %d, flags %x ch.nr %d, proto %x\n", | ||
| 124 | __func__, (int)len, flags, _pms(sk)->ch.nr, | ||
| 125 | sk->sk_protocol); | ||
| 126 | if (flags & (MSG_OOB)) | ||
| 127 | return -EOPNOTSUPP; | ||
| 128 | |||
| 129 | if (sk->sk_state == MISDN_CLOSED) | ||
| 130 | return 0; | ||
| 131 | |||
| 132 | skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err); | ||
| 133 | if (!skb) | ||
| 134 | return err; | ||
| 135 | |||
| 136 | if (msg->msg_namelen >= sizeof(struct sockaddr_mISDN)) { | ||
| 137 | msg->msg_namelen = sizeof(struct sockaddr_mISDN); | ||
| 138 | maddr = (struct sockaddr_mISDN *)msg->msg_name; | ||
| 139 | maddr->family = AF_ISDN; | ||
| 140 | maddr->dev = _pms(sk)->dev->id; | ||
| 141 | if ((sk->sk_protocol == ISDN_P_LAPD_TE) || | ||
| 142 | (sk->sk_protocol == ISDN_P_LAPD_NT)) { | ||
| 143 | maddr->channel = (mISDN_HEAD_ID(skb) >> 16) & 0xff; | ||
| 144 | maddr->tei = (mISDN_HEAD_ID(skb) >> 8) & 0xff; | ||
| 145 | maddr->sapi = mISDN_HEAD_ID(skb) & 0xff; | ||
| 146 | } else { | ||
| 147 | maddr->channel = _pms(sk)->ch.nr; | ||
| 148 | maddr->sapi = _pms(sk)->ch.addr & 0xFF; | ||
| 149 | maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xFF; | ||
| 150 | } | ||
| 151 | } else { | ||
| 152 | if (msg->msg_namelen) | ||
| 153 | printk(KERN_WARNING "%s: too small namelen %d\n", | ||
| 154 | __func__, msg->msg_namelen); | ||
| 155 | msg->msg_namelen = 0; | ||
| 156 | } | ||
| 157 | |||
| 158 | copied = skb->len + MISDN_HEADER_LEN; | ||
| 159 | if (len < copied) { | ||
| 160 | if (flags & MSG_PEEK) | ||
| 161 | atomic_dec(&skb->users); | ||
| 162 | else | ||
| 163 | skb_queue_head(&sk->sk_receive_queue, skb); | ||
| 164 | return -ENOSPC; | ||
| 165 | } | ||
| 166 | memcpy(skb_push(skb, MISDN_HEADER_LEN), mISDN_HEAD_P(skb), | ||
| 167 | MISDN_HEADER_LEN); | ||
| 168 | |||
| 169 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); | ||
| 170 | |||
| 171 | mISDN_sock_cmsg(sk, msg, skb); | ||
| 172 | |||
| 173 | skb_free_datagram(sk, skb); | ||
| 174 | |||
| 175 | return err ? : copied; | ||
| 176 | } | ||
| 177 | |||
| 178 | static int | ||
| 179 | mISDN_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | ||
| 180 | struct msghdr *msg, size_t len) | ||
| 181 | { | ||
| 182 | struct sock *sk = sock->sk; | ||
| 183 | struct sk_buff *skb; | ||
| 184 | int err = -ENOMEM; | ||
| 185 | struct sockaddr_mISDN *maddr; | ||
| 186 | |||
| 187 | if (*debug & DEBUG_SOCKET) | ||
| 188 | printk(KERN_DEBUG "%s: len %d flags %x ch %d proto %x\n", | ||
| 189 | __func__, (int)len, msg->msg_flags, _pms(sk)->ch.nr, | ||
| 190 | sk->sk_protocol); | ||
| 191 | |||
| 192 | if (msg->msg_flags & MSG_OOB) | ||
| 193 | return -EOPNOTSUPP; | ||
| 194 | |||
| 195 | if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE)) | ||
| 196 | return -EINVAL; | ||
| 197 | |||
| 198 | if (len < MISDN_HEADER_LEN) | ||
| 199 | return -EINVAL; | ||
| 200 | |||
| 201 | if (sk->sk_state != MISDN_BOUND) | ||
| 202 | return -EBADFD; | ||
| 203 | |||
| 204 | lock_sock(sk); | ||
| 205 | |||
| 206 | skb = _l2_alloc_skb(len, GFP_KERNEL); | ||
| 207 | if (!skb) | ||
| 208 | goto done; | ||
| 209 | |||
| 210 | if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { | ||
| 211 | err = -EFAULT; | ||
| 212 | goto drop; | ||
| 213 | } | ||
| 214 | |||
| 215 | memcpy(mISDN_HEAD_P(skb), skb->data, MISDN_HEADER_LEN); | ||
| 216 | skb_pull(skb, MISDN_HEADER_LEN); | ||
| 217 | |||
| 218 | if (msg->msg_namelen >= sizeof(struct sockaddr_mISDN)) { | ||
| 219 | /* if we have a address, we use it */ | ||
| 220 | maddr = (struct sockaddr_mISDN *)msg->msg_name; | ||
| 221 | mISDN_HEAD_ID(skb) = maddr->channel; | ||
| 222 | } else { /* use default for L2 messages */ | ||
| 223 | if ((sk->sk_protocol == ISDN_P_LAPD_TE) || | ||
| 224 | (sk->sk_protocol == ISDN_P_LAPD_NT)) | ||
| 225 | mISDN_HEAD_ID(skb) = _pms(sk)->ch.nr; | ||
| 226 | } | ||
| 227 | |||
| 228 | if (*debug & DEBUG_SOCKET) | ||
| 229 | printk(KERN_DEBUG "%s: ID:%x\n", | ||
| 230 | __func__, mISDN_HEAD_ID(skb)); | ||
| 231 | |||
| 232 | err = -ENODEV; | ||
| 233 | if (!_pms(sk)->ch.peer || | ||
| 234 | (err = _pms(sk)->ch.recv(_pms(sk)->ch.peer, skb))) | ||
| 235 | goto drop; | ||
| 236 | |||
| 237 | err = len; | ||
| 238 | |||
| 239 | done: | ||
| 240 | release_sock(sk); | ||
| 241 | return err; | ||
| 242 | |||
| 243 | drop: | ||
| 244 | kfree_skb(skb); | ||
| 245 | goto done; | ||
| 246 | } | ||
| 247 | |||
| 248 | static int | ||
| 249 | data_sock_release(struct socket *sock) | ||
| 250 | { | ||
| 251 | struct sock *sk = sock->sk; | ||
| 252 | |||
| 253 | if (*debug & DEBUG_SOCKET) | ||
| 254 | printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk); | ||
| 255 | if (!sk) | ||
| 256 | return 0; | ||
| 257 | switch (sk->sk_protocol) { | ||
| 258 | case ISDN_P_TE_S0: | ||
| 259 | case ISDN_P_NT_S0: | ||
| 260 | case ISDN_P_TE_E1: | ||
| 261 | case ISDN_P_NT_E1: | ||
| 262 | if (sk->sk_state == MISDN_BOUND) | ||
| 263 | delete_channel(&_pms(sk)->ch); | ||
| 264 | else | ||
| 265 | mISDN_sock_unlink(&data_sockets, sk); | ||
| 266 | break; | ||
| 267 | case ISDN_P_LAPD_TE: | ||
| 268 | case ISDN_P_LAPD_NT: | ||
| 269 | case ISDN_P_B_RAW: | ||
| 270 | case ISDN_P_B_HDLC: | ||
| 271 | case ISDN_P_B_X75SLP: | ||
| 272 | case ISDN_P_B_L2DTMF: | ||
| 273 | case ISDN_P_B_L2DSP: | ||
| 274 | case ISDN_P_B_L2DSPHDLC: | ||
| 275 | delete_channel(&_pms(sk)->ch); | ||
| 276 | mISDN_sock_unlink(&data_sockets, sk); | ||
| 277 | break; | ||
| 278 | } | ||
| 279 | |||
| 280 | lock_sock(sk); | ||
| 281 | |||
| 282 | sock_orphan(sk); | ||
| 283 | skb_queue_purge(&sk->sk_receive_queue); | ||
| 284 | |||
| 285 | release_sock(sk); | ||
| 286 | sock_put(sk); | ||
| 287 | |||
| 288 | return 0; | ||
| 289 | } | ||
| 290 | |||
| 291 | static int | ||
| 292 | data_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p) | ||
| 293 | { | ||
| 294 | struct mISDN_ctrl_req cq; | ||
| 295 | int err = -EINVAL, val; | ||
| 296 | struct mISDNchannel *bchan, *next; | ||
| 297 | |||
| 298 | lock_sock(sk); | ||
| 299 | if (!_pms(sk)->dev) { | ||
| 300 | err = -ENODEV; | ||
| 301 | goto done; | ||
| 302 | } | ||
| 303 | switch (cmd) { | ||
| 304 | case IMCTRLREQ: | ||
| 305 | if (copy_from_user(&cq, p, sizeof(cq))) { | ||
| 306 | err = -EFAULT; | ||
| 307 | break; | ||
| 308 | } | ||
| 309 | if ((sk->sk_protocol & ~ISDN_P_B_MASK) == ISDN_P_B_START) { | ||
| 310 | list_for_each_entry_safe(bchan, next, | ||
| 311 | &_pms(sk)->dev->bchannels, list) { | ||
| 312 | if (bchan->nr == cq.channel) { | ||
| 313 | err = bchan->ctrl(bchan, | ||
| 314 | CONTROL_CHANNEL, &cq); | ||
| 315 | break; | ||
| 316 | } | ||
| 317 | } | ||
| 318 | } else | ||
| 319 | err = _pms(sk)->dev->D.ctrl(&_pms(sk)->dev->D, | ||
| 320 | CONTROL_CHANNEL, &cq); | ||
| 321 | if (err) | ||
| 322 | break; | ||
| 323 | if (copy_to_user(p, &cq, sizeof(cq))) | ||
| 324 | err = -EFAULT; | ||
| 325 | break; | ||
| 326 | case IMCLEAR_L2: | ||
| 327 | if (sk->sk_protocol != ISDN_P_LAPD_NT) { | ||
| 328 | err = -EINVAL; | ||
| 329 | break; | ||
| 330 | } | ||
| 331 | if (get_user(val, (int __user *)p)) { | ||
| 332 | err = -EFAULT; | ||
| 333 | break; | ||
| 334 | } | ||
| 335 | err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr, | ||
| 336 | CONTROL_CHANNEL, &val); | ||
| 337 | break; | ||
| 338 | default: | ||
| 339 | err = -EINVAL; | ||
| 340 | break; | ||
| 341 | } | ||
| 342 | done: | ||
| 343 | release_sock(sk); | ||
| 344 | return err; | ||
| 345 | } | ||
| 346 | |||
| 347 | static int | ||
| 348 | data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | ||
| 349 | { | ||
| 350 | int err = 0, id; | ||
| 351 | struct sock *sk = sock->sk; | ||
| 352 | struct mISDNdevice *dev; | ||
| 353 | struct mISDNversion ver; | ||
| 354 | |||
| 355 | switch (cmd) { | ||
| 356 | case IMGETVERSION: | ||
| 357 | ver.major = MISDN_MAJOR_VERSION; | ||
| 358 | ver.minor = MISDN_MINOR_VERSION; | ||
| 359 | ver.release = MISDN_RELEASE; | ||
| 360 | if (copy_to_user((void __user *)arg, &ver, sizeof(ver))) | ||
| 361 | err = -EFAULT; | ||
| 362 | break; | ||
| 363 | case IMGETCOUNT: | ||
| 364 | id = get_mdevice_count(); | ||
| 365 | if (put_user(id, (int __user *)arg)) | ||
| 366 | err = -EFAULT; | ||
| 367 | break; | ||
| 368 | case IMGETDEVINFO: | ||
| 369 | if (get_user(id, (int __user *)arg)) { | ||
| 370 | err = -EFAULT; | ||
| 371 | break; | ||
| 372 | } | ||
| 373 | dev = get_mdevice(id); | ||
| 374 | if (dev) { | ||
| 375 | struct mISDN_devinfo di; | ||
| 376 | |||
| 377 | di.id = dev->id; | ||
| 378 | di.Dprotocols = dev->Dprotocols; | ||
| 379 | di.Bprotocols = dev->Bprotocols | get_all_Bprotocols(); | ||
| 380 | di.protocol = dev->D.protocol; | ||
| 381 | memcpy(di.channelmap, dev->channelmap, | ||
| 382 | MISDN_CHMAP_SIZE * 4); | ||
| 383 | di.nrbchan = dev->nrbchan; | ||
| 384 | strcpy(di.name, dev->name); | ||
| 385 | if (copy_to_user((void __user *)arg, &di, sizeof(di))) | ||
| 386 | err = -EFAULT; | ||
| 387 | } else | ||
| 388 | err = -ENODEV; | ||
| 389 | break; | ||
| 390 | default: | ||
| 391 | if (sk->sk_state == MISDN_BOUND) | ||
| 392 | err = data_sock_ioctl_bound(sk, cmd, | ||
| 393 | (void __user *)arg); | ||
| 394 | else | ||
| 395 | err = -ENOTCONN; | ||
| 396 | } | ||
| 397 | return err; | ||
| 398 | } | ||
| 399 | |||
| 400 | static int data_sock_setsockopt(struct socket *sock, int level, int optname, | ||
| 401 | char __user *optval, int len) | ||
| 402 | { | ||
| 403 | struct sock *sk = sock->sk; | ||
| 404 | int err = 0, opt = 0; | ||
| 405 | |||
| 406 | if (*debug & DEBUG_SOCKET) | ||
| 407 | printk(KERN_DEBUG "%s(%p, %d, %x, %p, %d)\n", __func__, sock, | ||
| 408 | level, optname, optval, len); | ||
| 409 | |||
| 410 | lock_sock(sk); | ||
| 411 | |||
| 412 | switch (optname) { | ||
| 413 | case MISDN_TIME_STAMP: | ||
| 414 | if (get_user(opt, (int __user *)optval)) { | ||
| 415 | err = -EFAULT; | ||
| 416 | break; | ||
| 417 | } | ||
| 418 | |||
| 419 | if (opt) | ||
| 420 | _pms(sk)->cmask |= MISDN_TIME_STAMP; | ||
| 421 | else | ||
| 422 | _pms(sk)->cmask &= ~MISDN_TIME_STAMP; | ||
| 423 | break; | ||
| 424 | default: | ||
| 425 | err = -ENOPROTOOPT; | ||
| 426 | break; | ||
| 427 | } | ||
| 428 | release_sock(sk); | ||
| 429 | return err; | ||
| 430 | } | ||
| 431 | |||
| 432 | static int data_sock_getsockopt(struct socket *sock, int level, int optname, | ||
| 433 | char __user *optval, int __user *optlen) | ||
| 434 | { | ||
| 435 | struct sock *sk = sock->sk; | ||
| 436 | int len, opt; | ||
| 437 | |||
| 438 | if (get_user(len, optlen)) | ||
| 439 | return -EFAULT; | ||
| 440 | |||
| 441 | switch (optname) { | ||
| 442 | case MISDN_TIME_STAMP: | ||
| 443 | if (_pms(sk)->cmask & MISDN_TIME_STAMP) | ||
| 444 | opt = 1; | ||
| 445 | else | ||
| 446 | opt = 0; | ||
| 447 | |||
| 448 | if (put_user(opt, optval)) | ||
| 449 | return -EFAULT; | ||
| 450 | break; | ||
| 451 | default: | ||
| 452 | return -ENOPROTOOPT; | ||
| 453 | } | ||
| 454 | |||
| 455 | return 0; | ||
| 456 | } | ||
| 457 | |||
| 458 | static int | ||
| 459 | data_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) | ||
| 460 | { | ||
| 461 | struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; | ||
| 462 | struct sock *sk = sock->sk; | ||
| 463 | int err = 0; | ||
| 464 | |||
| 465 | if (*debug & DEBUG_SOCKET) | ||
| 466 | printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk); | ||
| 467 | if (addr_len != sizeof(struct sockaddr_mISDN)) | ||
| 468 | return -EINVAL; | ||
| 469 | if (!maddr || maddr->family != AF_ISDN) | ||
| 470 | return -EINVAL; | ||
| 471 | |||
| 472 | lock_sock(sk); | ||
| 473 | |||
| 474 | if (_pms(sk)->dev) { | ||
| 475 | err = -EALREADY; | ||
| 476 | goto done; | ||
| 477 | } | ||
| 478 | _pms(sk)->dev = get_mdevice(maddr->dev); | ||
| 479 | if (!_pms(sk)->dev) { | ||
| 480 | err = -ENODEV; | ||
| 481 | goto done; | ||
| 482 | } | ||
| 483 | _pms(sk)->ch.send = mISDN_send; | ||
| 484 | _pms(sk)->ch.ctrl = mISDN_ctrl; | ||
| 485 | |||
| 486 | switch (sk->sk_protocol) { | ||
| 487 | case ISDN_P_TE_S0: | ||
| 488 | case ISDN_P_NT_S0: | ||
| 489 | case ISDN_P_TE_E1: | ||
| 490 | case ISDN_P_NT_E1: | ||
| 491 | mISDN_sock_unlink(&data_sockets, sk); | ||
| 492 | err = connect_layer1(_pms(sk)->dev, &_pms(sk)->ch, | ||
| 493 | sk->sk_protocol, maddr); | ||
| 494 | if (err) | ||
| 495 | mISDN_sock_link(&data_sockets, sk); | ||
| 496 | break; | ||
| 497 | case ISDN_P_LAPD_TE: | ||
| 498 | case ISDN_P_LAPD_NT: | ||
| 499 | err = create_l2entity(_pms(sk)->dev, &_pms(sk)->ch, | ||
| 500 | sk->sk_protocol, maddr); | ||
| 501 | break; | ||
| 502 | case ISDN_P_B_RAW: | ||
| 503 | case ISDN_P_B_HDLC: | ||
| 504 | case ISDN_P_B_X75SLP: | ||
| 505 | case ISDN_P_B_L2DTMF: | ||
| 506 | case ISDN_P_B_L2DSP: | ||
| 507 | case ISDN_P_B_L2DSPHDLC: | ||
| 508 | err = connect_Bstack(_pms(sk)->dev, &_pms(sk)->ch, | ||
| 509 | sk->sk_protocol, maddr); | ||
| 510 | break; | ||
| 511 | default: | ||
| 512 | err = -EPROTONOSUPPORT; | ||
| 513 | } | ||
| 514 | if (err) | ||
| 515 | goto done; | ||
| 516 | sk->sk_state = MISDN_BOUND; | ||
| 517 | _pms(sk)->ch.protocol = sk->sk_protocol; | ||
| 518 | |||
| 519 | done: | ||
| 520 | release_sock(sk); | ||
| 521 | return err; | ||
| 522 | } | ||
| 523 | |||
| 524 | static int | ||
| 525 | data_sock_getname(struct socket *sock, struct sockaddr *addr, | ||
| 526 | int *addr_len, int peer) | ||
| 527 | { | ||
| 528 | struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; | ||
| 529 | struct sock *sk = sock->sk; | ||
| 530 | |||
| 531 | if (!_pms(sk)->dev) | ||
| 532 | return -EBADFD; | ||
| 533 | |||
| 534 | lock_sock(sk); | ||
| 535 | |||
| 536 | *addr_len = sizeof(*maddr); | ||
| 537 | maddr->dev = _pms(sk)->dev->id; | ||
| 538 | maddr->channel = _pms(sk)->ch.nr; | ||
| 539 | maddr->sapi = _pms(sk)->ch.addr & 0xff; | ||
| 540 | maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xff; | ||
| 541 | release_sock(sk); | ||
| 542 | return 0; | ||
| 543 | } | ||
| 544 | |||
| 545 | static const struct proto_ops data_sock_ops = { | ||
| 546 | .family = PF_ISDN, | ||
| 547 | .owner = THIS_MODULE, | ||
| 548 | .release = data_sock_release, | ||
| 549 | .ioctl = data_sock_ioctl, | ||
| 550 | .bind = data_sock_bind, | ||
| 551 | .getname = data_sock_getname, | ||
| 552 | .sendmsg = mISDN_sock_sendmsg, | ||
| 553 | .recvmsg = mISDN_sock_recvmsg, | ||
| 554 | .poll = datagram_poll, | ||
| 555 | .listen = sock_no_listen, | ||
| 556 | .shutdown = sock_no_shutdown, | ||
| 557 | .setsockopt = data_sock_setsockopt, | ||
| 558 | .getsockopt = data_sock_getsockopt, | ||
| 559 | .connect = sock_no_connect, | ||
| 560 | .socketpair = sock_no_socketpair, | ||
| 561 | .accept = sock_no_accept, | ||
| 562 | .mmap = sock_no_mmap | ||
| 563 | }; | ||
| 564 | |||
| 565 | static int | ||
| 566 | data_sock_create(struct net *net, struct socket *sock, int protocol) | ||
| 567 | { | ||
| 568 | struct sock *sk; | ||
| 569 | |||
| 570 | if (sock->type != SOCK_DGRAM) | ||
| 571 | return -ESOCKTNOSUPPORT; | ||
| 572 | |||
| 573 | sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto); | ||
| 574 | if (!sk) | ||
| 575 | return -ENOMEM; | ||
| 576 | |||
| 577 | sock_init_data(sock, sk); | ||
| 578 | |||
| 579 | sock->ops = &data_sock_ops; | ||
| 580 | sock->state = SS_UNCONNECTED; | ||
| 581 | sock_reset_flag(sk, SOCK_ZAPPED); | ||
| 582 | |||
| 583 | sk->sk_protocol = protocol; | ||
| 584 | sk->sk_state = MISDN_OPEN; | ||
| 585 | mISDN_sock_link(&data_sockets, sk); | ||
| 586 | |||
| 587 | return 0; | ||
| 588 | } | ||
| 589 | |||
| 590 | static int | ||
| 591 | base_sock_release(struct socket *sock) | ||
| 592 | { | ||
| 593 | struct sock *sk = sock->sk; | ||
| 594 | |||
| 595 | printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk); | ||
| 596 | if (!sk) | ||
| 597 | return 0; | ||
| 598 | |||
| 599 | mISDN_sock_unlink(&base_sockets, sk); | ||
| 600 | sock_orphan(sk); | ||
| 601 | sock_put(sk); | ||
| 602 | |||
| 603 | return 0; | ||
| 604 | } | ||
| 605 | |||
| 606 | static int | ||
| 607 | base_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | ||
| 608 | { | ||
| 609 | int err = 0, id; | ||
| 610 | struct mISDNdevice *dev; | ||
| 611 | struct mISDNversion ver; | ||
| 612 | |||
| 613 | switch (cmd) { | ||
| 614 | case IMGETVERSION: | ||
| 615 | ver.major = MISDN_MAJOR_VERSION; | ||
| 616 | ver.minor = MISDN_MINOR_VERSION; | ||
| 617 | ver.release = MISDN_RELEASE; | ||
| 618 | if (copy_to_user((void __user *)arg, &ver, sizeof(ver))) | ||
| 619 | err = -EFAULT; | ||
| 620 | break; | ||
| 621 | case IMGETCOUNT: | ||
| 622 | id = get_mdevice_count(); | ||
| 623 | if (put_user(id, (int __user *)arg)) | ||
| 624 | err = -EFAULT; | ||
| 625 | break; | ||
| 626 | case IMGETDEVINFO: | ||
| 627 | if (get_user(id, (int __user *)arg)) { | ||
| 628 | err = -EFAULT; | ||
| 629 | break; | ||
| 630 | } | ||
| 631 | dev = get_mdevice(id); | ||
| 632 | if (dev) { | ||
| 633 | struct mISDN_devinfo di; | ||
| 634 | |||
| 635 | di.id = dev->id; | ||
| 636 | di.Dprotocols = dev->Dprotocols; | ||
| 637 | di.Bprotocols = dev->Bprotocols | get_all_Bprotocols(); | ||
| 638 | di.protocol = dev->D.protocol; | ||
| 639 | memcpy(di.channelmap, dev->channelmap, | ||
| 640 | MISDN_CHMAP_SIZE * 4); | ||
| 641 | di.nrbchan = dev->nrbchan; | ||
| 642 | strcpy(di.name, dev->name); | ||
| 643 | if (copy_to_user((void __user *)arg, &di, sizeof(di))) | ||
| 644 | err = -EFAULT; | ||
| 645 | } else | ||
| 646 | err = -ENODEV; | ||
| 647 | break; | ||
| 648 | default: | ||
| 649 | err = -EINVAL; | ||
| 650 | } | ||
| 651 | return err; | ||
| 652 | } | ||
| 653 | |||
| 654 | static int | ||
| 655 | base_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) | ||
| 656 | { | ||
| 657 | struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; | ||
| 658 | struct sock *sk = sock->sk; | ||
| 659 | int err = 0; | ||
| 660 | |||
| 661 | if (!maddr || maddr->family != AF_ISDN) | ||
| 662 | return -EINVAL; | ||
| 663 | |||
| 664 | lock_sock(sk); | ||
| 665 | |||
| 666 | if (_pms(sk)->dev) { | ||
| 667 | err = -EALREADY; | ||
| 668 | goto done; | ||
| 669 | } | ||
| 670 | |||
| 671 | _pms(sk)->dev = get_mdevice(maddr->dev); | ||
| 672 | if (!_pms(sk)->dev) { | ||
| 673 | err = -ENODEV; | ||
| 674 | goto done; | ||
| 675 | } | ||
| 676 | sk->sk_state = MISDN_BOUND; | ||
| 677 | |||
| 678 | done: | ||
| 679 | release_sock(sk); | ||
| 680 | return err; | ||
| 681 | } | ||
| 682 | |||
| 683 | static const struct proto_ops base_sock_ops = { | ||
| 684 | .family = PF_ISDN, | ||
| 685 | .owner = THIS_MODULE, | ||
| 686 | .release = base_sock_release, | ||
| 687 | .ioctl = base_sock_ioctl, | ||
| 688 | .bind = base_sock_bind, | ||
| 689 | .getname = sock_no_getname, | ||
| 690 | .sendmsg = sock_no_sendmsg, | ||
| 691 | .recvmsg = sock_no_recvmsg, | ||
| 692 | .poll = sock_no_poll, | ||
| 693 | .listen = sock_no_listen, | ||
| 694 | .shutdown = sock_no_shutdown, | ||
| 695 | .setsockopt = sock_no_setsockopt, | ||
| 696 | .getsockopt = sock_no_getsockopt, | ||
| 697 | .connect = sock_no_connect, | ||
| 698 | .socketpair = sock_no_socketpair, | ||
| 699 | .accept = sock_no_accept, | ||
| 700 | .mmap = sock_no_mmap | ||
| 701 | }; | ||
| 702 | |||
| 703 | |||
| 704 | static int | ||
| 705 | base_sock_create(struct net *net, struct socket *sock, int protocol) | ||
| 706 | { | ||
| 707 | struct sock *sk; | ||
| 708 | |||
| 709 | if (sock->type != SOCK_RAW) | ||
| 710 | return -ESOCKTNOSUPPORT; | ||
| 711 | |||
| 712 | sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto); | ||
| 713 | if (!sk) | ||
| 714 | return -ENOMEM; | ||
| 715 | |||
| 716 | sock_init_data(sock, sk); | ||
| 717 | sock->ops = &base_sock_ops; | ||
| 718 | sock->state = SS_UNCONNECTED; | ||
| 719 | sock_reset_flag(sk, SOCK_ZAPPED); | ||
| 720 | sk->sk_protocol = protocol; | ||
| 721 | sk->sk_state = MISDN_OPEN; | ||
| 722 | mISDN_sock_link(&base_sockets, sk); | ||
| 723 | |||
| 724 | return 0; | ||
| 725 | } | ||
| 726 | |||
| 727 | static int | ||
| 728 | mISDN_sock_create(struct net *net, struct socket *sock, int proto) | ||
| 729 | { | ||
| 730 | int err = -EPROTONOSUPPORT; | ||
| 731 | |||
| 732 | switch (proto) { | ||
| 733 | case ISDN_P_BASE: | ||
| 734 | err = base_sock_create(net, sock, proto); | ||
| 735 | break; | ||
| 736 | case ISDN_P_TE_S0: | ||
| 737 | case ISDN_P_NT_S0: | ||
| 738 | case ISDN_P_TE_E1: | ||
| 739 | case ISDN_P_NT_E1: | ||
| 740 | case ISDN_P_LAPD_TE: | ||
| 741 | case ISDN_P_LAPD_NT: | ||
| 742 | case ISDN_P_B_RAW: | ||
| 743 | case ISDN_P_B_HDLC: | ||
| 744 | case ISDN_P_B_X75SLP: | ||
| 745 | case ISDN_P_B_L2DTMF: | ||
| 746 | case ISDN_P_B_L2DSP: | ||
| 747 | case ISDN_P_B_L2DSPHDLC: | ||
| 748 | err = data_sock_create(net, sock, proto); | ||
| 749 | break; | ||
| 750 | default: | ||
| 751 | return err; | ||
| 752 | } | ||
| 753 | |||
| 754 | return err; | ||
| 755 | } | ||
| 756 | |||
| 757 | static struct | ||
| 758 | net_proto_family mISDN_sock_family_ops = { | ||
| 759 | .owner = THIS_MODULE, | ||
| 760 | .family = PF_ISDN, | ||
| 761 | .create = mISDN_sock_create, | ||
| 762 | }; | ||
| 763 | |||
| 764 | int | ||
| 765 | misdn_sock_init(u_int *deb) | ||
| 766 | { | ||
| 767 | int err; | ||
| 768 | |||
| 769 | debug = deb; | ||
| 770 | err = sock_register(&mISDN_sock_family_ops); | ||
| 771 | if (err) | ||
| 772 | printk(KERN_ERR "%s: error(%d)\n", __func__, err); | ||
| 773 | return err; | ||
| 774 | } | ||
| 775 | |||
| 776 | void | ||
| 777 | misdn_sock_cleanup(void) | ||
| 778 | { | ||
| 779 | sock_unregister(PF_ISDN); | ||
| 780 | } | ||
| 781 | |||
diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c new file mode 100644 index 000000000000..54cfddcc4784 --- /dev/null +++ b/drivers/isdn/mISDN/stack.c | |||
| @@ -0,0 +1,674 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * Author Karsten Keil <kkeil@novell.com> | ||
| 4 | * | ||
| 5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/mISDNif.h> | ||
| 19 | #include <linux/kthread.h> | ||
| 20 | #include "core.h" | ||
| 21 | |||
| 22 | static u_int *debug; | ||
| 23 | |||
| 24 | static inline void | ||
| 25 | _queue_message(struct mISDNstack *st, struct sk_buff *skb) | ||
| 26 | { | ||
| 27 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
| 28 | |||
| 29 | if (*debug & DEBUG_QUEUE_FUNC) | ||
| 30 | printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n", | ||
| 31 | __func__, hh->prim, hh->id, skb); | ||
| 32 | skb_queue_tail(&st->msgq, skb); | ||
| 33 | if (likely(!test_bit(mISDN_STACK_STOPPED, &st->status))) { | ||
| 34 | test_and_set_bit(mISDN_STACK_WORK, &st->status); | ||
| 35 | wake_up_interruptible(&st->workq); | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | int | ||
| 40 | mISDN_queue_message(struct mISDNchannel *ch, struct sk_buff *skb) | ||
| 41 | { | ||
| 42 | _queue_message(ch->st, skb); | ||
| 43 | return 0; | ||
| 44 | } | ||
| 45 | |||
| 46 | static struct mISDNchannel * | ||
| 47 | get_channel4id(struct mISDNstack *st, u_int id) | ||
| 48 | { | ||
| 49 | struct mISDNchannel *ch; | ||
| 50 | |||
| 51 | mutex_lock(&st->lmutex); | ||
| 52 | list_for_each_entry(ch, &st->layer2, list) { | ||
| 53 | if (id == ch->nr) | ||
| 54 | goto unlock; | ||
| 55 | } | ||
| 56 | ch = NULL; | ||
| 57 | unlock: | ||
| 58 | mutex_unlock(&st->lmutex); | ||
| 59 | return ch; | ||
| 60 | } | ||
| 61 | |||
| 62 | static void | ||
| 63 | send_socklist(struct mISDN_sock_list *sl, struct sk_buff *skb) | ||
| 64 | { | ||
| 65 | struct hlist_node *node; | ||
| 66 | struct sock *sk; | ||
| 67 | struct sk_buff *cskb = NULL; | ||
| 68 | |||
| 69 | read_lock(&sl->lock); | ||
| 70 | sk_for_each(sk, node, &sl->head) { | ||
| 71 | if (sk->sk_state != MISDN_BOUND) | ||
| 72 | continue; | ||
| 73 | if (!cskb) | ||
| 74 | cskb = skb_copy(skb, GFP_KERNEL); | ||
| 75 | if (!cskb) { | ||
| 76 | printk(KERN_WARNING "%s no skb\n", __func__); | ||
| 77 | break; | ||
| 78 | } | ||
| 79 | if (!sock_queue_rcv_skb(sk, cskb)) | ||
| 80 | cskb = NULL; | ||
| 81 | } | ||
| 82 | read_unlock(&sl->lock); | ||
| 83 | if (cskb) | ||
| 84 | dev_kfree_skb(cskb); | ||
| 85 | } | ||
| 86 | |||
| 87 | static void | ||
| 88 | send_layer2(struct mISDNstack *st, struct sk_buff *skb) | ||
| 89 | { | ||
| 90 | struct sk_buff *cskb; | ||
| 91 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
| 92 | struct mISDNchannel *ch; | ||
| 93 | int ret; | ||
| 94 | |||
| 95 | if (!st) | ||
| 96 | return; | ||
| 97 | mutex_lock(&st->lmutex); | ||
| 98 | if ((hh->id & MISDN_ID_ADDR_MASK) == MISDN_ID_ANY) { /* L2 for all */ | ||
| 99 | list_for_each_entry(ch, &st->layer2, list) { | ||
| 100 | if (list_is_last(&ch->list, &st->layer2)) { | ||
| 101 | cskb = skb; | ||
| 102 | skb = NULL; | ||
| 103 | } else { | ||
| 104 | cskb = skb_copy(skb, GFP_KERNEL); | ||
| 105 | } | ||
| 106 | if (cskb) { | ||
| 107 | ret = ch->send(ch, cskb); | ||
| 108 | if (ret) { | ||
| 109 | if (*debug & DEBUG_SEND_ERR) | ||
| 110 | printk(KERN_DEBUG | ||
| 111 | "%s ch%d prim(%x) addr(%x)" | ||
| 112 | " err %d\n", | ||
| 113 | __func__, ch->nr, | ||
| 114 | hh->prim, ch->addr, ret); | ||
| 115 | dev_kfree_skb(cskb); | ||
| 116 | } | ||
| 117 | } else { | ||
| 118 | printk(KERN_WARNING "%s ch%d addr %x no mem\n", | ||
| 119 | __func__, ch->nr, ch->addr); | ||
| 120 | goto out; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | } else { | ||
| 124 | list_for_each_entry(ch, &st->layer2, list) { | ||
| 125 | if ((hh->id & MISDN_ID_ADDR_MASK) == ch->addr) { | ||
| 126 | ret = ch->send(ch, skb); | ||
| 127 | if (!ret) | ||
| 128 | skb = NULL; | ||
| 129 | goto out; | ||
| 130 | } | ||
| 131 | } | ||
| 132 | ret = st->dev->teimgr->ctrl(st->dev->teimgr, CHECK_DATA, skb); | ||
| 133 | if (!ret) | ||
| 134 | skb = NULL; | ||
| 135 | else if (*debug & DEBUG_SEND_ERR) | ||
| 136 | printk(KERN_DEBUG | ||
| 137 | "%s ch%d mgr prim(%x) addr(%x) err %d\n", | ||
| 138 | __func__, ch->nr, hh->prim, ch->addr, ret); | ||
| 139 | } | ||
| 140 | out: | ||
| 141 | mutex_unlock(&st->lmutex); | ||
| 142 | if (skb) | ||
| 143 | dev_kfree_skb(skb); | ||
| 144 | } | ||
| 145 | |||
| 146 | static inline int | ||
| 147 | send_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb) | ||
| 148 | { | ||
| 149 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
| 150 | struct mISDNchannel *ch; | ||
| 151 | int lm; | ||
| 152 | |||
| 153 | lm = hh->prim & MISDN_LAYERMASK; | ||
| 154 | if (*debug & DEBUG_QUEUE_FUNC) | ||
| 155 | printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n", | ||
| 156 | __func__, hh->prim, hh->id, skb); | ||
| 157 | if (lm == 0x1) { | ||
| 158 | if (!hlist_empty(&st->l1sock.head)) { | ||
| 159 | __net_timestamp(skb); | ||
| 160 | send_socklist(&st->l1sock, skb); | ||
| 161 | } | ||
| 162 | return st->layer1->send(st->layer1, skb); | ||
| 163 | } else if (lm == 0x2) { | ||
| 164 | if (!hlist_empty(&st->l1sock.head)) | ||
| 165 | send_socklist(&st->l1sock, skb); | ||
| 166 | send_layer2(st, skb); | ||
| 167 | return 0; | ||
| 168 | } else if (lm == 0x4) { | ||
| 169 | ch = get_channel4id(st, hh->id); | ||
| 170 | if (ch) | ||
| 171 | return ch->send(ch, skb); | ||
| 172 | else | ||
| 173 | printk(KERN_WARNING | ||
| 174 | "%s: dev(%s) prim(%x) id(%x) no channel\n", | ||
| 175 | __func__, st->dev->name, hh->prim, hh->id); | ||
| 176 | } else if (lm == 0x8) { | ||
| 177 | WARN_ON(lm == 0x8); | ||
| 178 | ch = get_channel4id(st, hh->id); | ||
| 179 | if (ch) | ||
| 180 | return ch->send(ch, skb); | ||
| 181 | else | ||
| 182 | printk(KERN_WARNING | ||
| 183 | "%s: dev(%s) prim(%x) id(%x) no channel\n", | ||
| 184 | __func__, st->dev->name, hh->prim, hh->id); | ||
| 185 | } else { | ||
| 186 | /* broadcast not handled yet */ | ||
| 187 | printk(KERN_WARNING "%s: dev(%s) prim %x not delivered\n", | ||
| 188 | __func__, st->dev->name, hh->prim); | ||
| 189 | } | ||
| 190 | return -ESRCH; | ||
| 191 | } | ||
| 192 | |||
| 193 | static void | ||
| 194 | do_clear_stack(struct mISDNstack *st) | ||
| 195 | { | ||
| 196 | } | ||
| 197 | |||
| 198 | static int | ||
| 199 | mISDNStackd(void *data) | ||
| 200 | { | ||
| 201 | struct mISDNstack *st = data; | ||
| 202 | int err = 0; | ||
| 203 | |||
| 204 | #ifdef CONFIG_SMP | ||
| 205 | lock_kernel(); | ||
| 206 | #endif | ||
| 207 | sigfillset(¤t->blocked); | ||
| 208 | #ifdef CONFIG_SMP | ||
| 209 | unlock_kernel(); | ||
| 210 | #endif | ||
| 211 | if (*debug & DEBUG_MSG_THREAD) | ||
| 212 | printk(KERN_DEBUG "mISDNStackd %s started\n", st->dev->name); | ||
| 213 | |||
| 214 | if (st->notify != NULL) { | ||
| 215 | complete(st->notify); | ||
| 216 | st->notify = NULL; | ||
| 217 | } | ||
| 218 | |||
| 219 | for (;;) { | ||
| 220 | struct sk_buff *skb; | ||
| 221 | |||
| 222 | if (unlikely(test_bit(mISDN_STACK_STOPPED, &st->status))) { | ||
| 223 | test_and_clear_bit(mISDN_STACK_WORK, &st->status); | ||
| 224 | test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); | ||
| 225 | } else | ||
| 226 | test_and_set_bit(mISDN_STACK_RUNNING, &st->status); | ||
| 227 | while (test_bit(mISDN_STACK_WORK, &st->status)) { | ||
| 228 | skb = skb_dequeue(&st->msgq); | ||
| 229 | if (!skb) { | ||
| 230 | test_and_clear_bit(mISDN_STACK_WORK, | ||
| 231 | &st->status); | ||
| 232 | /* test if a race happens */ | ||
| 233 | skb = skb_dequeue(&st->msgq); | ||
| 234 | if (!skb) | ||
| 235 | continue; | ||
| 236 | test_and_set_bit(mISDN_STACK_WORK, | ||
| 237 | &st->status); | ||
| 238 | } | ||
| 239 | #ifdef MISDN_MSG_STATS | ||
| 240 | st->msg_cnt++; | ||
| 241 | #endif | ||
| 242 | err = send_msg_to_layer(st, skb); | ||
| 243 | if (unlikely(err)) { | ||
| 244 | if (*debug & DEBUG_SEND_ERR) | ||
| 245 | printk(KERN_DEBUG | ||
| 246 | "%s: %s prim(%x) id(%x) " | ||
| 247 | "send call(%d)\n", | ||
| 248 | __func__, st->dev->name, | ||
| 249 | mISDN_HEAD_PRIM(skb), | ||
| 250 | mISDN_HEAD_ID(skb), err); | ||
| 251 | dev_kfree_skb(skb); | ||
| 252 | continue; | ||
| 253 | } | ||
| 254 | if (unlikely(test_bit(mISDN_STACK_STOPPED, | ||
| 255 | &st->status))) { | ||
| 256 | test_and_clear_bit(mISDN_STACK_WORK, | ||
| 257 | &st->status); | ||
| 258 | test_and_clear_bit(mISDN_STACK_RUNNING, | ||
| 259 | &st->status); | ||
| 260 | break; | ||
| 261 | } | ||
| 262 | } | ||
| 263 | if (test_bit(mISDN_STACK_CLEARING, &st->status)) { | ||
| 264 | test_and_set_bit(mISDN_STACK_STOPPED, &st->status); | ||
| 265 | test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); | ||
| 266 | do_clear_stack(st); | ||
| 267 | test_and_clear_bit(mISDN_STACK_CLEARING, &st->status); | ||
| 268 | test_and_set_bit(mISDN_STACK_RESTART, &st->status); | ||
| 269 | } | ||
| 270 | if (test_and_clear_bit(mISDN_STACK_RESTART, &st->status)) { | ||
| 271 | test_and_clear_bit(mISDN_STACK_STOPPED, &st->status); | ||
| 272 | test_and_set_bit(mISDN_STACK_RUNNING, &st->status); | ||
| 273 | if (!skb_queue_empty(&st->msgq)) | ||
| 274 | test_and_set_bit(mISDN_STACK_WORK, | ||
| 275 | &st->status); | ||
| 276 | } | ||
| 277 | if (test_bit(mISDN_STACK_ABORT, &st->status)) | ||
| 278 | break; | ||
| 279 | if (st->notify != NULL) { | ||
| 280 | complete(st->notify); | ||
| 281 | st->notify = NULL; | ||
| 282 | } | ||
| 283 | #ifdef MISDN_MSG_STATS | ||
| 284 | st->sleep_cnt++; | ||
| 285 | #endif | ||
| 286 | test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status); | ||
| 287 | wait_event_interruptible(st->workq, (st->status & | ||
| 288 | mISDN_STACK_ACTION_MASK)); | ||
| 289 | if (*debug & DEBUG_MSG_THREAD) | ||
| 290 | printk(KERN_DEBUG "%s: %s wake status %08lx\n", | ||
| 291 | __func__, st->dev->name, st->status); | ||
| 292 | test_and_set_bit(mISDN_STACK_ACTIVE, &st->status); | ||
| 293 | |||
| 294 | test_and_clear_bit(mISDN_STACK_WAKEUP, &st->status); | ||
| 295 | |||
| 296 | if (test_bit(mISDN_STACK_STOPPED, &st->status)) { | ||
| 297 | test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); | ||
| 298 | #ifdef MISDN_MSG_STATS | ||
| 299 | st->stopped_cnt++; | ||
| 300 | #endif | ||
| 301 | } | ||
| 302 | } | ||
| 303 | #ifdef MISDN_MSG_STATS | ||
| 304 | printk(KERN_DEBUG "mISDNStackd daemon for %s proceed %d " | ||
| 305 | "msg %d sleep %d stopped\n", | ||
| 306 | st->dev->name, st->msg_cnt, st->sleep_cnt, st->stopped_cnt); | ||
| 307 | printk(KERN_DEBUG | ||
| 308 | "mISDNStackd daemon for %s utime(%ld) stime(%ld)\n", | ||
| 309 | st->dev->name, st->thread->utime, st->thread->stime); | ||
| 310 | printk(KERN_DEBUG | ||
| 311 | "mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n", | ||
| 312 | st->dev->name, st->thread->nvcsw, st->thread->nivcsw); | ||
| 313 | printk(KERN_DEBUG "mISDNStackd daemon for %s killed now\n", | ||
| 314 | st->dev->name); | ||
| 315 | #endif | ||
| 316 | test_and_set_bit(mISDN_STACK_KILLED, &st->status); | ||
| 317 | test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); | ||
| 318 | test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status); | ||
| 319 | test_and_clear_bit(mISDN_STACK_ABORT, &st->status); | ||
| 320 | skb_queue_purge(&st->msgq); | ||
| 321 | st->thread = NULL; | ||
| 322 | if (st->notify != NULL) { | ||
| 323 | complete(st->notify); | ||
| 324 | st->notify = NULL; | ||
| 325 | } | ||
| 326 | return 0; | ||
| 327 | } | ||
| 328 | |||
| 329 | static int | ||
| 330 | l1_receive(struct mISDNchannel *ch, struct sk_buff *skb) | ||
| 331 | { | ||
| 332 | if (!ch->st) | ||
| 333 | return -ENODEV; | ||
| 334 | __net_timestamp(skb); | ||
| 335 | _queue_message(ch->st, skb); | ||
| 336 | return 0; | ||
| 337 | } | ||
| 338 | |||
| 339 | void | ||
| 340 | set_channel_address(struct mISDNchannel *ch, u_int sapi, u_int tei) | ||
| 341 | { | ||
| 342 | ch->addr = sapi | (tei << 8); | ||
| 343 | } | ||
| 344 | |||
| 345 | void | ||
| 346 | __add_layer2(struct mISDNchannel *ch, struct mISDNstack *st) | ||
| 347 | { | ||
| 348 | list_add_tail(&ch->list, &st->layer2); | ||
| 349 | } | ||
| 350 | |||
| 351 | void | ||
| 352 | add_layer2(struct mISDNchannel *ch, struct mISDNstack *st) | ||
| 353 | { | ||
| 354 | mutex_lock(&st->lmutex); | ||
| 355 | __add_layer2(ch, st); | ||
| 356 | mutex_unlock(&st->lmutex); | ||
| 357 | } | ||
| 358 | |||
| 359 | static int | ||
| 360 | st_own_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
| 361 | { | ||
| 362 | if (!ch->st || ch->st->layer1) | ||
| 363 | return -EINVAL; | ||
| 364 | return ch->st->layer1->ctrl(ch->st->layer1, cmd, arg); | ||
| 365 | } | ||
| 366 | |||
| 367 | int | ||
| 368 | create_stack(struct mISDNdevice *dev) | ||
| 369 | { | ||
| 370 | struct mISDNstack *newst; | ||
| 371 | int err; | ||
| 372 | DECLARE_COMPLETION_ONSTACK(done); | ||
| 373 | |||
| 374 | newst = kzalloc(sizeof(struct mISDNstack), GFP_KERNEL); | ||
| 375 | if (!newst) { | ||
| 376 | printk(KERN_ERR "kmalloc mISDN_stack failed\n"); | ||
| 377 | return -ENOMEM; | ||
| 378 | } | ||
| 379 | newst->dev = dev; | ||
| 380 | INIT_LIST_HEAD(&newst->layer2); | ||
| 381 | INIT_HLIST_HEAD(&newst->l1sock.head); | ||
| 382 | rwlock_init(&newst->l1sock.lock); | ||
| 383 | init_waitqueue_head(&newst->workq); | ||
| 384 | skb_queue_head_init(&newst->msgq); | ||
| 385 | mutex_init(&newst->lmutex); | ||
| 386 | dev->D.st = newst; | ||
| 387 | err = create_teimanager(dev); | ||
| 388 | if (err) { | ||
| 389 | printk(KERN_ERR "kmalloc teimanager failed\n"); | ||
| 390 | kfree(newst); | ||
| 391 | return err; | ||
| 392 | } | ||
| 393 | dev->teimgr->peer = &newst->own; | ||
| 394 | dev->teimgr->recv = mISDN_queue_message; | ||
| 395 | dev->teimgr->st = newst; | ||
| 396 | newst->layer1 = &dev->D; | ||
| 397 | dev->D.recv = l1_receive; | ||
| 398 | dev->D.peer = &newst->own; | ||
| 399 | newst->own.st = newst; | ||
| 400 | newst->own.ctrl = st_own_ctrl; | ||
| 401 | newst->own.send = mISDN_queue_message; | ||
| 402 | newst->own.recv = mISDN_queue_message; | ||
| 403 | if (*debug & DEBUG_CORE_FUNC) | ||
| 404 | printk(KERN_DEBUG "%s: st(%s)\n", __func__, newst->dev->name); | ||
| 405 | newst->notify = &done; | ||
| 406 | newst->thread = kthread_run(mISDNStackd, (void *)newst, "mISDN_%s", | ||
| 407 | newst->dev->name); | ||
| 408 | if (IS_ERR(newst->thread)) { | ||
| 409 | err = PTR_ERR(newst->thread); | ||
| 410 | printk(KERN_ERR | ||
| 411 | "mISDN:cannot create kernel thread for %s (%d)\n", | ||
| 412 | newst->dev->name, err); | ||
| 413 | delete_teimanager(dev->teimgr); | ||
| 414 | kfree(newst); | ||
| 415 | } else | ||
| 416 | wait_for_completion(&done); | ||
| 417 | return err; | ||
| 418 | } | ||
| 419 | |||
| 420 | int | ||
| 421 | connect_layer1(struct mISDNdevice *dev, struct mISDNchannel *ch, | ||
| 422 | u_int protocol, struct sockaddr_mISDN *adr) | ||
| 423 | { | ||
| 424 | struct mISDN_sock *msk = container_of(ch, struct mISDN_sock, ch); | ||
| 425 | struct channel_req rq; | ||
| 426 | int err; | ||
| 427 | |||
| 428 | |||
| 429 | if (*debug & DEBUG_CORE_FUNC) | ||
| 430 | printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", | ||
| 431 | __func__, dev->name, protocol, adr->dev, adr->channel, | ||
| 432 | adr->sapi, adr->tei); | ||
| 433 | switch (protocol) { | ||
| 434 | case ISDN_P_NT_S0: | ||
| 435 | case ISDN_P_NT_E1: | ||
| 436 | case ISDN_P_TE_S0: | ||
| 437 | case ISDN_P_TE_E1: | ||
| 438 | #ifdef PROTOCOL_CHECK | ||
| 439 | /* this should be enhanced */ | ||
| 440 | if (!list_empty(&dev->D.st->layer2) | ||
| 441 | && dev->D.protocol != protocol) | ||
| 442 | return -EBUSY; | ||
| 443 | if (!hlist_empty(&dev->D.st->l1sock.head) | ||
| 444 | && dev->D.protocol != protocol) | ||
| 445 | return -EBUSY; | ||
| 446 | #endif | ||
| 447 | ch->recv = mISDN_queue_message; | ||
| 448 | ch->peer = &dev->D.st->own; | ||
| 449 | ch->st = dev->D.st; | ||
| 450 | rq.protocol = protocol; | ||
| 451 | rq.adr.channel = 0; | ||
| 452 | err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); | ||
| 453 | printk(KERN_DEBUG "%s: ret 1 %d\n", __func__, err); | ||
| 454 | if (err) | ||
| 455 | return err; | ||
| 456 | write_lock_bh(&dev->D.st->l1sock.lock); | ||
| 457 | sk_add_node(&msk->sk, &dev->D.st->l1sock.head); | ||
| 458 | write_unlock_bh(&dev->D.st->l1sock.lock); | ||
| 459 | break; | ||
| 460 | default: | ||
| 461 | return -ENOPROTOOPT; | ||
| 462 | } | ||
| 463 | return 0; | ||
| 464 | } | ||
| 465 | |||
| 466 | int | ||
| 467 | connect_Bstack(struct mISDNdevice *dev, struct mISDNchannel *ch, | ||
| 468 | u_int protocol, struct sockaddr_mISDN *adr) | ||
| 469 | { | ||
| 470 | struct channel_req rq, rq2; | ||
| 471 | int pmask, err; | ||
| 472 | struct Bprotocol *bp; | ||
| 473 | |||
| 474 | if (*debug & DEBUG_CORE_FUNC) | ||
| 475 | printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", | ||
| 476 | __func__, dev->name, protocol, | ||
| 477 | adr->dev, adr->channel, adr->sapi, | ||
| 478 | adr->tei); | ||
| 479 | ch->st = dev->D.st; | ||
| 480 | pmask = 1 << (protocol & ISDN_P_B_MASK); | ||
| 481 | if (pmask & dev->Bprotocols) { | ||
| 482 | rq.protocol = protocol; | ||
| 483 | rq.adr = *adr; | ||
| 484 | err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); | ||
| 485 | if (err) | ||
| 486 | return err; | ||
| 487 | ch->recv = rq.ch->send; | ||
| 488 | ch->peer = rq.ch; | ||
| 489 | rq.ch->recv = ch->send; | ||
| 490 | rq.ch->peer = ch; | ||
| 491 | rq.ch->st = dev->D.st; | ||
| 492 | } else { | ||
| 493 | bp = get_Bprotocol4mask(pmask); | ||
| 494 | if (!bp) | ||
| 495 | return -ENOPROTOOPT; | ||
| 496 | rq2.protocol = protocol; | ||
| 497 | rq2.adr = *adr; | ||
| 498 | rq2.ch = ch; | ||
| 499 | err = bp->create(&rq2); | ||
| 500 | if (err) | ||
| 501 | return err; | ||
| 502 | ch->recv = rq2.ch->send; | ||
| 503 | ch->peer = rq2.ch; | ||
| 504 | rq2.ch->st = dev->D.st; | ||
| 505 | rq.protocol = rq2.protocol; | ||
| 506 | rq.adr = *adr; | ||
| 507 | err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); | ||
| 508 | if (err) { | ||
| 509 | rq2.ch->ctrl(rq2.ch, CLOSE_CHANNEL, NULL); | ||
| 510 | return err; | ||
| 511 | } | ||
| 512 | rq2.ch->recv = rq.ch->send; | ||
| 513 | rq2.ch->peer = rq.ch; | ||
| 514 | rq.ch->recv = rq2.ch->send; | ||
| 515 | rq.ch->peer = rq2.ch; | ||
| 516 | rq.ch->st = dev->D.st; | ||
| 517 | } | ||
| 518 | ch->protocol = protocol; | ||
| 519 | ch->nr = rq.ch->nr; | ||
| 520 | return 0; | ||
| 521 | } | ||
| 522 | |||
| 523 | int | ||
| 524 | create_l2entity(struct mISDNdevice *dev, struct mISDNchannel *ch, | ||
| 525 | u_int protocol, struct sockaddr_mISDN *adr) | ||
| 526 | { | ||
| 527 | struct channel_req rq; | ||
| 528 | int err; | ||
| 529 | |||
| 530 | if (*debug & DEBUG_CORE_FUNC) | ||
| 531 | printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", | ||
| 532 | __func__, dev->name, protocol, | ||
| 533 | adr->dev, adr->channel, adr->sapi, | ||
| 534 | adr->tei); | ||
| 535 | rq.protocol = ISDN_P_TE_S0; | ||
| 536 | if (dev->Dprotocols & (1 << ISDN_P_TE_E1)) | ||
| 537 | rq.protocol = ISDN_P_TE_E1; | ||
| 538 | switch (protocol) { | ||
| 539 | case ISDN_P_LAPD_NT: | ||
| 540 | rq.protocol = ISDN_P_NT_S0; | ||
| 541 | if (dev->Dprotocols & (1 << ISDN_P_NT_E1)) | ||
| 542 | rq.protocol = ISDN_P_NT_E1; | ||
| 543 | case ISDN_P_LAPD_TE: | ||
| 544 | #ifdef PROTOCOL_CHECK | ||
| 545 | /* this should be enhanced */ | ||
| 546 | if (!list_empty(&dev->D.st->layer2) | ||
| 547 | && dev->D.protocol != protocol) | ||
| 548 | return -EBUSY; | ||
| 549 | if (!hlist_empty(&dev->D.st->l1sock.head) | ||
| 550 | && dev->D.protocol != protocol) | ||
| 551 | return -EBUSY; | ||
| 552 | #endif | ||
| 553 | ch->recv = mISDN_queue_message; | ||
| 554 | ch->peer = &dev->D.st->own; | ||
| 555 | ch->st = dev->D.st; | ||
| 556 | rq.adr.channel = 0; | ||
| 557 | err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); | ||
| 558 | printk(KERN_DEBUG "%s: ret 1 %d\n", __func__, err); | ||
| 559 | if (err) | ||
| 560 | break; | ||
| 561 | rq.protocol = protocol; | ||
| 562 | rq.adr = *adr; | ||
| 563 | rq.ch = ch; | ||
| 564 | err = dev->teimgr->ctrl(dev->teimgr, OPEN_CHANNEL, &rq); | ||
| 565 | printk(KERN_DEBUG "%s: ret 2 %d\n", __func__, err); | ||
| 566 | if (!err) { | ||
| 567 | if ((protocol == ISDN_P_LAPD_NT) && !rq.ch) | ||
| 568 | break; | ||
| 569 | add_layer2(rq.ch, dev->D.st); | ||
| 570 | rq.ch->recv = mISDN_queue_message; | ||
| 571 | rq.ch->peer = &dev->D.st->own; | ||
| 572 | rq.ch->ctrl(rq.ch, OPEN_CHANNEL, NULL); /* can't fail */ | ||
| 573 | } | ||
| 574 | break; | ||
| 575 | default: | ||
| 576 | err = -EPROTONOSUPPORT; | ||
| 577 | } | ||
| 578 | return err; | ||
| 579 | } | ||
| 580 | |||
| 581 | void | ||
| 582 | delete_channel(struct mISDNchannel *ch) | ||
| 583 | { | ||
| 584 | struct mISDN_sock *msk = container_of(ch, struct mISDN_sock, ch); | ||
| 585 | struct mISDNchannel *pch; | ||
| 586 | |||
| 587 | if (!ch->st) { | ||
| 588 | printk(KERN_WARNING "%s: no stack\n", __func__); | ||
| 589 | return; | ||
| 590 | } | ||
| 591 | if (*debug & DEBUG_CORE_FUNC) | ||
| 592 | printk(KERN_DEBUG "%s: st(%s) protocol(%x)\n", __func__, | ||
| 593 | ch->st->dev->name, ch->protocol); | ||
| 594 | if (ch->protocol >= ISDN_P_B_START) { | ||
| 595 | if (ch->peer) { | ||
| 596 | ch->peer->ctrl(ch->peer, CLOSE_CHANNEL, NULL); | ||
| 597 | ch->peer = NULL; | ||
| 598 | } | ||
| 599 | return; | ||
| 600 | } | ||
| 601 | switch (ch->protocol) { | ||
| 602 | case ISDN_P_NT_S0: | ||
| 603 | case ISDN_P_TE_S0: | ||
| 604 | case ISDN_P_NT_E1: | ||
| 605 | case ISDN_P_TE_E1: | ||
| 606 | write_lock_bh(&ch->st->l1sock.lock); | ||
| 607 | sk_del_node_init(&msk->sk); | ||
| 608 | write_unlock_bh(&ch->st->l1sock.lock); | ||
| 609 | ch->st->dev->D.ctrl(&ch->st->dev->D, CLOSE_CHANNEL, NULL); | ||
| 610 | break; | ||
| 611 | case ISDN_P_LAPD_TE: | ||
| 612 | pch = get_channel4id(ch->st, ch->nr); | ||
| 613 | if (pch) { | ||
| 614 | mutex_lock(&ch->st->lmutex); | ||
| 615 | list_del(&pch->list); | ||
| 616 | mutex_unlock(&ch->st->lmutex); | ||
| 617 | pch->ctrl(pch, CLOSE_CHANNEL, NULL); | ||
| 618 | pch = ch->st->dev->teimgr; | ||
| 619 | pch->ctrl(pch, CLOSE_CHANNEL, NULL); | ||
| 620 | } else | ||
| 621 | printk(KERN_WARNING "%s: no l2 channel\n", | ||
| 622 | __func__); | ||
| 623 | break; | ||
| 624 | case ISDN_P_LAPD_NT: | ||
| 625 | pch = ch->st->dev->teimgr; | ||
| 626 | if (pch) { | ||
| 627 | pch->ctrl(pch, CLOSE_CHANNEL, NULL); | ||
| 628 | } else | ||
| 629 | printk(KERN_WARNING "%s: no l2 channel\n", | ||
| 630 | __func__); | ||
| 631 | break; | ||
| 632 | default: | ||
| 633 | break; | ||
| 634 | } | ||
| 635 | return; | ||
| 636 | } | ||
| 637 | |||
| 638 | void | ||
| 639 | delete_stack(struct mISDNdevice *dev) | ||
| 640 | { | ||
| 641 | struct mISDNstack *st = dev->D.st; | ||
| 642 | DECLARE_COMPLETION_ONSTACK(done); | ||
| 643 | |||
| 644 | if (*debug & DEBUG_CORE_FUNC) | ||
| 645 | printk(KERN_DEBUG "%s: st(%s)\n", __func__, | ||
| 646 | st->dev->name); | ||
| 647 | if (dev->teimgr) | ||
| 648 | delete_teimanager(dev->teimgr); | ||
| 649 | if (st->thread) { | ||
| 650 | if (st->notify) { | ||
| 651 | printk(KERN_WARNING "%s: notifier in use\n", | ||
| 652 | __func__); | ||
| 653 | complete(st->notify); | ||
| 654 | } | ||
| 655 | st->notify = &done; | ||
| 656 | test_and_set_bit(mISDN_STACK_ABORT, &st->status); | ||
| 657 | test_and_set_bit(mISDN_STACK_WAKEUP, &st->status); | ||
| 658 | wake_up_interruptible(&st->workq); | ||
| 659 | wait_for_completion(&done); | ||
| 660 | } | ||
| 661 | if (!list_empty(&st->layer2)) | ||
| 662 | printk(KERN_WARNING "%s: layer2 list not empty\n", | ||
| 663 | __func__); | ||
| 664 | if (!hlist_empty(&st->l1sock.head)) | ||
| 665 | printk(KERN_WARNING "%s: layer1 list not empty\n", | ||
| 666 | __func__); | ||
| 667 | kfree(st); | ||
| 668 | } | ||
| 669 | |||
| 670 | void | ||
| 671 | mISDN_initstack(u_int *dp) | ||
| 672 | { | ||
| 673 | debug = dp; | ||
| 674 | } | ||
diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c new file mode 100644 index 000000000000..6fbae42127bf --- /dev/null +++ b/drivers/isdn/mISDN/tei.c | |||
| @@ -0,0 +1,1340 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * Author Karsten Keil <kkeil@novell.com> | ||
| 4 | * | ||
| 5 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | #include "layer2.h" | ||
| 18 | #include <linux/random.h> | ||
| 19 | #include "core.h" | ||
| 20 | |||
| 21 | #define ID_REQUEST 1 | ||
| 22 | #define ID_ASSIGNED 2 | ||
| 23 | #define ID_DENIED 3 | ||
| 24 | #define ID_CHK_REQ 4 | ||
| 25 | #define ID_CHK_RES 5 | ||
| 26 | #define ID_REMOVE 6 | ||
| 27 | #define ID_VERIFY 7 | ||
| 28 | |||
| 29 | #define TEI_ENTITY_ID 0xf | ||
| 30 | |||
| 31 | #define MGR_PH_ACTIVE 16 | ||
| 32 | #define MGR_PH_NOTREADY 17 | ||
| 33 | |||
| 34 | #define DATIMER_VAL 10000 | ||
| 35 | |||
| 36 | static u_int *debug; | ||
| 37 | |||
| 38 | static struct Fsm deactfsm = {NULL, 0, 0, NULL, NULL}; | ||
| 39 | static struct Fsm teifsmu = {NULL, 0, 0, NULL, NULL}; | ||
| 40 | static struct Fsm teifsmn = {NULL, 0, 0, NULL, NULL}; | ||
| 41 | |||
| 42 | enum { | ||
| 43 | ST_L1_DEACT, | ||
| 44 | ST_L1_DEACT_PENDING, | ||
| 45 | ST_L1_ACTIV, | ||
| 46 | }; | ||
| 47 | #define DEACT_STATE_COUNT (ST_L1_ACTIV+1) | ||
| 48 | |||
| 49 | static char *strDeactState[] = | ||
| 50 | { | ||
| 51 | "ST_L1_DEACT", | ||
| 52 | "ST_L1_DEACT_PENDING", | ||
| 53 | "ST_L1_ACTIV", | ||
| 54 | }; | ||
| 55 | |||
| 56 | enum { | ||
| 57 | EV_ACTIVATE, | ||
| 58 | EV_ACTIVATE_IND, | ||
| 59 | EV_DEACTIVATE, | ||
| 60 | EV_DEACTIVATE_IND, | ||
| 61 | EV_UI, | ||
| 62 | EV_DATIMER, | ||
| 63 | }; | ||
| 64 | |||
| 65 | #define DEACT_EVENT_COUNT (EV_DATIMER+1) | ||
| 66 | |||
| 67 | static char *strDeactEvent[] = | ||
| 68 | { | ||
| 69 | "EV_ACTIVATE", | ||
| 70 | "EV_ACTIVATE_IND", | ||
| 71 | "EV_DEACTIVATE", | ||
| 72 | "EV_DEACTIVATE_IND", | ||
| 73 | "EV_UI", | ||
| 74 | "EV_DATIMER", | ||
| 75 | }; | ||
| 76 | |||
| 77 | static void | ||
| 78 | da_debug(struct FsmInst *fi, char *fmt, ...) | ||
| 79 | { | ||
| 80 | struct manager *mgr = fi->userdata; | ||
| 81 | va_list va; | ||
| 82 | |||
| 83 | if (!(*debug & DEBUG_L2_TEIFSM)) | ||
| 84 | return; | ||
| 85 | va_start(va, fmt); | ||
| 86 | printk(KERN_DEBUG "mgr(%d): ", mgr->ch.st->dev->id); | ||
| 87 | vprintk(fmt, va); | ||
| 88 | printk("\n"); | ||
| 89 | va_end(va); | ||
| 90 | } | ||
| 91 | |||
| 92 | static void | ||
| 93 | da_activate(struct FsmInst *fi, int event, void *arg) | ||
| 94 | { | ||
| 95 | struct manager *mgr = fi->userdata; | ||
| 96 | |||
| 97 | if (fi->state == ST_L1_DEACT_PENDING) | ||
| 98 | mISDN_FsmDelTimer(&mgr->datimer, 1); | ||
| 99 | mISDN_FsmChangeState(fi, ST_L1_ACTIV); | ||
| 100 | } | ||
| 101 | |||
| 102 | static void | ||
| 103 | da_deactivate_ind(struct FsmInst *fi, int event, void *arg) | ||
| 104 | { | ||
| 105 | mISDN_FsmChangeState(fi, ST_L1_DEACT); | ||
| 106 | } | ||
| 107 | |||
| 108 | static void | ||
| 109 | da_deactivate(struct FsmInst *fi, int event, void *arg) | ||
| 110 | { | ||
| 111 | struct manager *mgr = fi->userdata; | ||
| 112 | struct layer2 *l2; | ||
| 113 | u_long flags; | ||
| 114 | |||
| 115 | read_lock_irqsave(&mgr->lock, flags); | ||
| 116 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
| 117 | if (l2->l2m.state > ST_L2_4) { | ||
| 118 | /* have still activ TEI */ | ||
| 119 | read_unlock_irqrestore(&mgr->lock, flags); | ||
| 120 | return; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | read_unlock_irqrestore(&mgr->lock, flags); | ||
| 124 | /* All TEI are inactiv */ | ||
| 125 | mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 1); | ||
| 126 | mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING); | ||
| 127 | } | ||
| 128 | |||
| 129 | static void | ||
| 130 | da_ui(struct FsmInst *fi, int event, void *arg) | ||
| 131 | { | ||
| 132 | struct manager *mgr = fi->userdata; | ||
| 133 | |||
| 134 | /* restart da timer */ | ||
| 135 | mISDN_FsmDelTimer(&mgr->datimer, 2); | ||
| 136 | mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 2); | ||
| 137 | |||
| 138 | } | ||
| 139 | |||
| 140 | static void | ||
| 141 | da_timer(struct FsmInst *fi, int event, void *arg) | ||
| 142 | { | ||
| 143 | struct manager *mgr = fi->userdata; | ||
| 144 | struct layer2 *l2; | ||
| 145 | u_long flags; | ||
| 146 | |||
| 147 | /* check again */ | ||
| 148 | read_lock_irqsave(&mgr->lock, flags); | ||
| 149 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
| 150 | if (l2->l2m.state > ST_L2_4) { | ||
| 151 | /* have still activ TEI */ | ||
| 152 | read_unlock_irqrestore(&mgr->lock, flags); | ||
| 153 | mISDN_FsmChangeState(fi, ST_L1_ACTIV); | ||
| 154 | return; | ||
| 155 | } | ||
| 156 | } | ||
| 157 | read_unlock_irqrestore(&mgr->lock, flags); | ||
| 158 | /* All TEI are inactiv */ | ||
| 159 | mISDN_FsmChangeState(fi, ST_L1_DEACT); | ||
| 160 | _queue_data(&mgr->ch, PH_DEACTIVATE_REQ, MISDN_ID_ANY, 0, NULL, | ||
| 161 | GFP_ATOMIC); | ||
| 162 | } | ||
| 163 | |||
| 164 | static struct FsmNode DeactFnList[] = | ||
| 165 | { | ||
| 166 | {ST_L1_DEACT, EV_ACTIVATE_IND, da_activate}, | ||
| 167 | {ST_L1_ACTIV, EV_DEACTIVATE_IND, da_deactivate_ind}, | ||
| 168 | {ST_L1_ACTIV, EV_DEACTIVATE, da_deactivate}, | ||
| 169 | {ST_L1_DEACT_PENDING, EV_ACTIVATE, da_activate}, | ||
| 170 | {ST_L1_DEACT_PENDING, EV_UI, da_ui}, | ||
| 171 | {ST_L1_DEACT_PENDING, EV_DATIMER, da_timer}, | ||
| 172 | }; | ||
| 173 | |||
| 174 | enum { | ||
| 175 | ST_TEI_NOP, | ||
| 176 | ST_TEI_IDREQ, | ||
| 177 | ST_TEI_IDVERIFY, | ||
| 178 | }; | ||
| 179 | |||
| 180 | #define TEI_STATE_COUNT (ST_TEI_IDVERIFY+1) | ||
| 181 | |||
| 182 | static char *strTeiState[] = | ||
| 183 | { | ||
| 184 | "ST_TEI_NOP", | ||
| 185 | "ST_TEI_IDREQ", | ||
| 186 | "ST_TEI_IDVERIFY", | ||
| 187 | }; | ||
| 188 | |||
| 189 | enum { | ||
| 190 | EV_IDREQ, | ||
| 191 | EV_ASSIGN, | ||
| 192 | EV_ASSIGN_REQ, | ||
| 193 | EV_DENIED, | ||
| 194 | EV_CHKREQ, | ||
| 195 | EV_CHKRESP, | ||
| 196 | EV_REMOVE, | ||
| 197 | EV_VERIFY, | ||
| 198 | EV_TIMER, | ||
| 199 | }; | ||
| 200 | |||
| 201 | #define TEI_EVENT_COUNT (EV_TIMER+1) | ||
| 202 | |||
| 203 | static char *strTeiEvent[] = | ||
| 204 | { | ||
| 205 | "EV_IDREQ", | ||
| 206 | "EV_ASSIGN", | ||
| 207 | "EV_ASSIGN_REQ", | ||
| 208 | "EV_DENIED", | ||
| 209 | "EV_CHKREQ", | ||
| 210 | "EV_CHKRESP", | ||
| 211 | "EV_REMOVE", | ||
| 212 | "EV_VERIFY", | ||
| 213 | "EV_TIMER", | ||
| 214 | }; | ||
| 215 | |||
| 216 | static void | ||
| 217 | tei_debug(struct FsmInst *fi, char *fmt, ...) | ||
| 218 | { | ||
| 219 | struct teimgr *tm = fi->userdata; | ||
| 220 | va_list va; | ||
| 221 | |||
| 222 | if (!(*debug & DEBUG_L2_TEIFSM)) | ||
| 223 | return; | ||
| 224 | va_start(va, fmt); | ||
| 225 | printk(KERN_DEBUG "tei(%d): ", tm->l2->tei); | ||
| 226 | vprintk(fmt, va); | ||
| 227 | printk("\n"); | ||
| 228 | va_end(va); | ||
| 229 | } | ||
| 230 | |||
| 231 | |||
| 232 | |||
| 233 | static int | ||
| 234 | get_free_id(struct manager *mgr) | ||
| 235 | { | ||
| 236 | u64 ids = 0; | ||
| 237 | int i; | ||
| 238 | struct layer2 *l2; | ||
| 239 | |||
| 240 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
| 241 | if (l2->ch.nr > 63) { | ||
| 242 | printk(KERN_WARNING | ||
| 243 | "%s: more as 63 layer2 for one device\n", | ||
| 244 | __func__); | ||
| 245 | return -EBUSY; | ||
| 246 | } | ||
| 247 | test_and_set_bit(l2->ch.nr, (u_long *)&ids); | ||
| 248 | } | ||
| 249 | for (i = 1; i < 64; i++) | ||
| 250 | if (!test_bit(i, (u_long *)&ids)) | ||
| 251 | return i; | ||
| 252 | printk(KERN_WARNING "%s: more as 63 layer2 for one device\n", | ||
| 253 | __func__); | ||
| 254 | return -EBUSY; | ||
| 255 | } | ||
| 256 | |||
| 257 | static int | ||
| 258 | get_free_tei(struct manager *mgr) | ||
| 259 | { | ||
| 260 | u64 ids = 0; | ||
| 261 | int i; | ||
| 262 | struct layer2 *l2; | ||
| 263 | |||
| 264 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
| 265 | if (l2->ch.nr == 0) | ||
| 266 | continue; | ||
| 267 | if ((l2->ch.addr & 0xff) != 0) | ||
| 268 | continue; | ||
| 269 | i = l2->ch.addr >> 8; | ||
| 270 | if (i < 64) | ||
| 271 | continue; | ||
| 272 | i -= 64; | ||
| 273 | |||
| 274 | test_and_set_bit(i, (u_long *)&ids); | ||
| 275 | } | ||
| 276 | for (i = 0; i < 64; i++) | ||
| 277 | if (!test_bit(i, (u_long *)&ids)) | ||
| 278 | return i + 64; | ||
| 279 | printk(KERN_WARNING "%s: more as 63 dynamic tei for one device\n", | ||
| 280 | __func__); | ||
| 281 | return -1; | ||
| 282 | } | ||
| 283 | |||
| 284 | static void | ||
| 285 | teiup_create(struct manager *mgr, u_int prim, int len, void *arg) | ||
| 286 | { | ||
| 287 | struct sk_buff *skb; | ||
| 288 | struct mISDNhead *hh; | ||
| 289 | int err; | ||
| 290 | |||
| 291 | skb = mI_alloc_skb(len, GFP_ATOMIC); | ||
| 292 | if (!skb) | ||
| 293 | return; | ||
| 294 | hh = mISDN_HEAD_P(skb); | ||
| 295 | hh->prim = prim; | ||
| 296 | hh->id = (mgr->ch.nr << 16) | mgr->ch.addr; | ||
| 297 | if (len) | ||
| 298 | memcpy(skb_put(skb, len), arg, len); | ||
| 299 | err = mgr->up->send(mgr->up, skb); | ||
| 300 | if (err) { | ||
| 301 | printk(KERN_WARNING "%s: err=%d\n", __func__, err); | ||
| 302 | dev_kfree_skb(skb); | ||
| 303 | } | ||
| 304 | } | ||
| 305 | |||
| 306 | static u_int | ||
| 307 | new_id(struct manager *mgr) | ||
| 308 | { | ||
| 309 | u_int id; | ||
| 310 | |||
| 311 | id = mgr->nextid++; | ||
| 312 | if (id == 0x7fff) | ||
| 313 | mgr->nextid = 1; | ||
| 314 | id <<= 16; | ||
| 315 | id |= GROUP_TEI << 8; | ||
| 316 | id |= TEI_SAPI; | ||
| 317 | return id; | ||
| 318 | } | ||
| 319 | |||
| 320 | static void | ||
| 321 | do_send(struct manager *mgr) | ||
| 322 | { | ||
| 323 | if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) | ||
| 324 | return; | ||
| 325 | |||
| 326 | if (!test_and_set_bit(MGR_PH_NOTREADY, &mgr->options)) { | ||
| 327 | struct sk_buff *skb = skb_dequeue(&mgr->sendq); | ||
| 328 | |||
| 329 | if (!skb) { | ||
| 330 | test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); | ||
| 331 | return; | ||
| 332 | } | ||
| 333 | mgr->lastid = mISDN_HEAD_ID(skb); | ||
| 334 | mISDN_FsmEvent(&mgr->deact, EV_UI, NULL); | ||
| 335 | if (mgr->ch.recv(mgr->ch.peer, skb)) { | ||
| 336 | dev_kfree_skb(skb); | ||
| 337 | test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); | ||
| 338 | mgr->lastid = MISDN_ID_NONE; | ||
| 339 | } | ||
| 340 | } | ||
| 341 | } | ||
| 342 | |||
| 343 | static void | ||
| 344 | do_ack(struct manager *mgr, u_int id) | ||
| 345 | { | ||
| 346 | if (test_bit(MGR_PH_NOTREADY, &mgr->options)) { | ||
| 347 | if (id == mgr->lastid) { | ||
| 348 | if (test_bit(MGR_PH_ACTIVE, &mgr->options)) { | ||
| 349 | struct sk_buff *skb; | ||
| 350 | |||
| 351 | skb = skb_dequeue(&mgr->sendq); | ||
| 352 | if (skb) { | ||
| 353 | mgr->lastid = mISDN_HEAD_ID(skb); | ||
| 354 | if (!mgr->ch.recv(mgr->ch.peer, skb)) | ||
| 355 | return; | ||
| 356 | dev_kfree_skb(skb); | ||
| 357 | } | ||
| 358 | } | ||
| 359 | mgr->lastid = MISDN_ID_NONE; | ||
| 360 | test_and_clear_bit(MGR_PH_NOTREADY, &mgr->options); | ||
| 361 | } | ||
| 362 | } | ||
| 363 | } | ||
| 364 | |||
| 365 | static void | ||
| 366 | mgr_send_down(struct manager *mgr, struct sk_buff *skb) | ||
| 367 | { | ||
| 368 | skb_queue_tail(&mgr->sendq, skb); | ||
| 369 | if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) { | ||
| 370 | _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0, | ||
| 371 | NULL, GFP_KERNEL); | ||
| 372 | } else { | ||
| 373 | do_send(mgr); | ||
| 374 | } | ||
| 375 | } | ||
| 376 | |||
| 377 | static int | ||
| 378 | dl_unit_data(struct manager *mgr, struct sk_buff *skb) | ||
| 379 | { | ||
| 380 | if (!test_bit(MGR_OPT_NETWORK, &mgr->options)) /* only net send UI */ | ||
| 381 | return -EINVAL; | ||
| 382 | if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) | ||
| 383 | _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0, | ||
| 384 | NULL, GFP_KERNEL); | ||
| 385 | skb_push(skb, 3); | ||
| 386 | skb->data[0] = 0x02; /* SAPI 0 C/R = 1 */ | ||
| 387 | skb->data[1] = 0xff; /* TEI 127 */ | ||
| 388 | skb->data[2] = UI; /* UI frame */ | ||
| 389 | mISDN_HEAD_PRIM(skb) = PH_DATA_REQ; | ||
| 390 | mISDN_HEAD_ID(skb) = new_id(mgr); | ||
| 391 | skb_queue_tail(&mgr->sendq, skb); | ||
| 392 | do_send(mgr); | ||
| 393 | return 0; | ||
| 394 | } | ||
| 395 | |||
| 396 | unsigned int | ||
| 397 | random_ri(void) | ||
| 398 | { | ||
| 399 | u16 x; | ||
| 400 | |||
| 401 | get_random_bytes(&x, sizeof(x)); | ||
| 402 | return x; | ||
| 403 | } | ||
| 404 | |||
| 405 | static struct layer2 * | ||
| 406 | findtei(struct manager *mgr, int tei) | ||
| 407 | { | ||
| 408 | struct layer2 *l2; | ||
| 409 | u_long flags; | ||
| 410 | |||
| 411 | read_lock_irqsave(&mgr->lock, flags); | ||
| 412 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
| 413 | if ((l2->sapi == 0) && (l2->tei > 0) && | ||
| 414 | (l2->tei != GROUP_TEI) && (l2->tei == tei)) | ||
| 415 | goto done; | ||
| 416 | } | ||
| 417 | l2 = NULL; | ||
| 418 | done: | ||
| 419 | read_unlock_irqrestore(&mgr->lock, flags); | ||
| 420 | return l2; | ||
| 421 | } | ||
| 422 | |||
| 423 | static void | ||
| 424 | put_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, u_char tei) | ||
| 425 | { | ||
| 426 | struct sk_buff *skb; | ||
| 427 | u_char bp[8]; | ||
| 428 | |||
| 429 | bp[0] = (TEI_SAPI << 2); | ||
| 430 | if (test_bit(MGR_OPT_NETWORK, &mgr->options)) | ||
| 431 | bp[0] |= 2; /* CR:=1 for net command */ | ||
| 432 | bp[1] = (GROUP_TEI << 1) | 0x1; | ||
| 433 | bp[2] = UI; | ||
| 434 | bp[3] = TEI_ENTITY_ID; | ||
| 435 | bp[4] = ri >> 8; | ||
| 436 | bp[5] = ri & 0xff; | ||
| 437 | bp[6] = m_id; | ||
| 438 | bp[7] = (tei << 1) | 1; | ||
| 439 | skb = _alloc_mISDN_skb(PH_DATA_REQ, new_id(mgr), | ||
| 440 | 8, bp, GFP_ATOMIC); | ||
| 441 | if (!skb) { | ||
| 442 | printk(KERN_WARNING "%s: no skb for tei msg\n", __func__); | ||
| 443 | return; | ||
| 444 | } | ||
| 445 | mgr_send_down(mgr, skb); | ||
| 446 | } | ||
| 447 | |||
| 448 | static void | ||
| 449 | tei_id_request(struct FsmInst *fi, int event, void *arg) | ||
| 450 | { | ||
| 451 | struct teimgr *tm = fi->userdata; | ||
| 452 | |||
| 453 | if (tm->l2->tei != GROUP_TEI) { | ||
| 454 | tm->tei_m.printdebug(&tm->tei_m, | ||
| 455 | "assign request for allready assigned tei %d", | ||
| 456 | tm->l2->tei); | ||
| 457 | return; | ||
| 458 | } | ||
| 459 | tm->ri = random_ri(); | ||
| 460 | if (*debug & DEBUG_L2_TEI) | ||
| 461 | tm->tei_m.printdebug(&tm->tei_m, | ||
| 462 | "assign request ri %d", tm->ri); | ||
| 463 | put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI); | ||
| 464 | mISDN_FsmChangeState(fi, ST_TEI_IDREQ); | ||
| 465 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 1); | ||
| 466 | tm->nval = 3; | ||
| 467 | } | ||
| 468 | |||
| 469 | static void | ||
| 470 | tei_id_assign(struct FsmInst *fi, int event, void *arg) | ||
| 471 | { | ||
| 472 | struct teimgr *tm = fi->userdata; | ||
| 473 | struct layer2 *l2; | ||
| 474 | u_char *dp = arg; | ||
| 475 | int ri, tei; | ||
| 476 | |||
| 477 | ri = ((unsigned int) *dp++ << 8); | ||
| 478 | ri += *dp++; | ||
| 479 | dp++; | ||
| 480 | tei = *dp >> 1; | ||
| 481 | if (*debug & DEBUG_L2_TEI) | ||
| 482 | tm->tei_m.printdebug(fi, "identity assign ri %d tei %d", | ||
| 483 | ri, tei); | ||
| 484 | l2 = findtei(tm->mgr, tei); | ||
| 485 | if (l2) { /* same tei is in use */ | ||
| 486 | if (ri != l2->tm->ri) { | ||
| 487 | tm->tei_m.printdebug(fi, | ||
| 488 | "possible duplicate assignment tei %d", tei); | ||
| 489 | tei_l2(l2, MDL_ERROR_RSP, 0); | ||
| 490 | } | ||
| 491 | } else if (ri == tm->ri) { | ||
| 492 | mISDN_FsmDelTimer(&tm->timer, 1); | ||
| 493 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
| 494 | tei_l2(tm->l2, MDL_ASSIGN_REQ, tei); | ||
| 495 | } | ||
| 496 | } | ||
| 497 | |||
| 498 | static void | ||
| 499 | tei_id_test_dup(struct FsmInst *fi, int event, void *arg) | ||
| 500 | { | ||
| 501 | struct teimgr *tm = fi->userdata; | ||
| 502 | struct layer2 *l2; | ||
| 503 | u_char *dp = arg; | ||
| 504 | int tei, ri; | ||
| 505 | |||
| 506 | ri = ((unsigned int) *dp++ << 8); | ||
| 507 | ri += *dp++; | ||
| 508 | dp++; | ||
| 509 | tei = *dp >> 1; | ||
| 510 | if (*debug & DEBUG_L2_TEI) | ||
| 511 | tm->tei_m.printdebug(fi, "foreign identity assign ri %d tei %d", | ||
| 512 | ri, tei); | ||
| 513 | l2 = findtei(tm->mgr, tei); | ||
| 514 | if (l2) { /* same tei is in use */ | ||
| 515 | if (ri != l2->tm->ri) { /* and it wasn't our request */ | ||
| 516 | tm->tei_m.printdebug(fi, | ||
| 517 | "possible duplicate assignment tei %d", tei); | ||
| 518 | mISDN_FsmEvent(&l2->tm->tei_m, EV_VERIFY, NULL); | ||
| 519 | } | ||
| 520 | } | ||
| 521 | } | ||
| 522 | |||
| 523 | static void | ||
| 524 | tei_id_denied(struct FsmInst *fi, int event, void *arg) | ||
| 525 | { | ||
| 526 | struct teimgr *tm = fi->userdata; | ||
| 527 | u_char *dp = arg; | ||
| 528 | int ri, tei; | ||
| 529 | |||
| 530 | ri = ((unsigned int) *dp++ << 8); | ||
| 531 | ri += *dp++; | ||
| 532 | dp++; | ||
| 533 | tei = *dp >> 1; | ||
| 534 | if (*debug & DEBUG_L2_TEI) | ||
| 535 | tm->tei_m.printdebug(fi, "identity denied ri %d tei %d", | ||
| 536 | ri, tei); | ||
| 537 | } | ||
| 538 | |||
| 539 | static void | ||
| 540 | tei_id_chk_req(struct FsmInst *fi, int event, void *arg) | ||
| 541 | { | ||
| 542 | struct teimgr *tm = fi->userdata; | ||
| 543 | u_char *dp = arg; | ||
| 544 | int tei; | ||
| 545 | |||
| 546 | tei = *(dp+3) >> 1; | ||
| 547 | if (*debug & DEBUG_L2_TEI) | ||
| 548 | tm->tei_m.printdebug(fi, "identity check req tei %d", tei); | ||
| 549 | if ((tm->l2->tei != GROUP_TEI) && ((tei == GROUP_TEI) || | ||
| 550 | (tei == tm->l2->tei))) { | ||
| 551 | mISDN_FsmDelTimer(&tm->timer, 4); | ||
| 552 | mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP); | ||
| 553 | put_tei_msg(tm->mgr, ID_CHK_RES, random_ri(), tm->l2->tei); | ||
| 554 | } | ||
| 555 | } | ||
| 556 | |||
| 557 | static void | ||
| 558 | tei_id_remove(struct FsmInst *fi, int event, void *arg) | ||
| 559 | { | ||
| 560 | struct teimgr *tm = fi->userdata; | ||
| 561 | u_char *dp = arg; | ||
| 562 | int tei; | ||
| 563 | |||
| 564 | tei = *(dp+3) >> 1; | ||
| 565 | if (*debug & DEBUG_L2_TEI) | ||
| 566 | tm->tei_m.printdebug(fi, "identity remove tei %d", tei); | ||
| 567 | if ((tm->l2->tei != GROUP_TEI) && | ||
| 568 | ((tei == GROUP_TEI) || (tei == tm->l2->tei))) { | ||
| 569 | mISDN_FsmDelTimer(&tm->timer, 5); | ||
| 570 | mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP); | ||
| 571 | tei_l2(tm->l2, MDL_REMOVE_REQ, 0); | ||
| 572 | } | ||
| 573 | } | ||
| 574 | |||
| 575 | static void | ||
| 576 | tei_id_verify(struct FsmInst *fi, int event, void *arg) | ||
| 577 | { | ||
| 578 | struct teimgr *tm = fi->userdata; | ||
| 579 | |||
| 580 | if (*debug & DEBUG_L2_TEI) | ||
| 581 | tm->tei_m.printdebug(fi, "id verify request for tei %d", | ||
| 582 | tm->l2->tei); | ||
| 583 | put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei); | ||
| 584 | mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY); | ||
| 585 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2); | ||
| 586 | tm->nval = 2; | ||
| 587 | } | ||
| 588 | |||
| 589 | static void | ||
| 590 | tei_id_req_tout(struct FsmInst *fi, int event, void *arg) | ||
| 591 | { | ||
| 592 | struct teimgr *tm = fi->userdata; | ||
| 593 | |||
| 594 | if (--tm->nval) { | ||
| 595 | tm->ri = random_ri(); | ||
| 596 | if (*debug & DEBUG_L2_TEI) | ||
| 597 | tm->tei_m.printdebug(fi, "assign req(%d) ri %d", | ||
| 598 | 4 - tm->nval, tm->ri); | ||
| 599 | put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI); | ||
| 600 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 3); | ||
| 601 | } else { | ||
| 602 | tm->tei_m.printdebug(fi, "assign req failed"); | ||
| 603 | tei_l2(tm->l2, MDL_ERROR_RSP, 0); | ||
| 604 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
| 605 | } | ||
| 606 | } | ||
| 607 | |||
| 608 | static void | ||
| 609 | tei_id_ver_tout(struct FsmInst *fi, int event, void *arg) | ||
| 610 | { | ||
| 611 | struct teimgr *tm = fi->userdata; | ||
| 612 | |||
| 613 | if (--tm->nval) { | ||
| 614 | if (*debug & DEBUG_L2_TEI) | ||
| 615 | tm->tei_m.printdebug(fi, | ||
| 616 | "id verify req(%d) for tei %d", | ||
| 617 | 3 - tm->nval, tm->l2->tei); | ||
| 618 | put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei); | ||
| 619 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4); | ||
| 620 | } else { | ||
| 621 | tm->tei_m.printdebug(fi, "verify req for tei %d failed", | ||
| 622 | tm->l2->tei); | ||
| 623 | tei_l2(tm->l2, MDL_REMOVE_REQ, 0); | ||
| 624 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
| 625 | } | ||
| 626 | } | ||
| 627 | |||
| 628 | static struct FsmNode TeiFnListUser[] = | ||
| 629 | { | ||
| 630 | {ST_TEI_NOP, EV_IDREQ, tei_id_request}, | ||
| 631 | {ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup}, | ||
| 632 | {ST_TEI_NOP, EV_VERIFY, tei_id_verify}, | ||
| 633 | {ST_TEI_NOP, EV_REMOVE, tei_id_remove}, | ||
| 634 | {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req}, | ||
| 635 | {ST_TEI_IDREQ, EV_TIMER, tei_id_req_tout}, | ||
| 636 | {ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign}, | ||
| 637 | {ST_TEI_IDREQ, EV_DENIED, tei_id_denied}, | ||
| 638 | {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout}, | ||
| 639 | {ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove}, | ||
| 640 | {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req}, | ||
| 641 | }; | ||
| 642 | |||
| 643 | static void | ||
| 644 | tei_l2remove(struct layer2 *l2) | ||
| 645 | { | ||
| 646 | put_tei_msg(l2->tm->mgr, ID_REMOVE, 0, l2->tei); | ||
| 647 | tei_l2(l2, MDL_REMOVE_REQ, 0); | ||
| 648 | list_del(&l2->ch.list); | ||
| 649 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
| 650 | } | ||
| 651 | |||
| 652 | static void | ||
| 653 | tei_assign_req(struct FsmInst *fi, int event, void *arg) | ||
| 654 | { | ||
| 655 | struct teimgr *tm = fi->userdata; | ||
| 656 | u_char *dp = arg; | ||
| 657 | |||
| 658 | if (tm->l2->tei == GROUP_TEI) { | ||
| 659 | tm->tei_m.printdebug(&tm->tei_m, | ||
| 660 | "net tei assign request without tei"); | ||
| 661 | return; | ||
| 662 | } | ||
| 663 | tm->ri = ((unsigned int) *dp++ << 8); | ||
| 664 | tm->ri += *dp++; | ||
| 665 | if (*debug & DEBUG_L2_TEI) | ||
| 666 | tm->tei_m.printdebug(&tm->tei_m, | ||
| 667 | "net assign request ri %d teim %d", tm->ri, *dp); | ||
| 668 | put_tei_msg(tm->mgr, ID_ASSIGNED, tm->ri, tm->l2->tei); | ||
| 669 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
| 670 | } | ||
| 671 | |||
| 672 | static void | ||
| 673 | tei_id_chk_req_net(struct FsmInst *fi, int event, void *arg) | ||
| 674 | { | ||
| 675 | struct teimgr *tm = fi->userdata; | ||
| 676 | |||
| 677 | if (*debug & DEBUG_L2_TEI) | ||
| 678 | tm->tei_m.printdebug(fi, "id check request for tei %d", | ||
| 679 | tm->l2->tei); | ||
| 680 | tm->rcnt = 0; | ||
| 681 | put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei); | ||
| 682 | mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY); | ||
| 683 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2); | ||
| 684 | tm->nval = 2; | ||
| 685 | } | ||
| 686 | |||
| 687 | static void | ||
| 688 | tei_id_chk_resp(struct FsmInst *fi, int event, void *arg) | ||
| 689 | { | ||
| 690 | struct teimgr *tm = fi->userdata; | ||
| 691 | u_char *dp = arg; | ||
| 692 | int tei; | ||
| 693 | |||
| 694 | tei = dp[3] >> 1; | ||
| 695 | if (*debug & DEBUG_L2_TEI) | ||
| 696 | tm->tei_m.printdebug(fi, "identity check resp tei %d", tei); | ||
| 697 | if (tei == tm->l2->tei) | ||
| 698 | tm->rcnt++; | ||
| 699 | } | ||
| 700 | |||
| 701 | static void | ||
| 702 | tei_id_verify_net(struct FsmInst *fi, int event, void *arg) | ||
| 703 | { | ||
| 704 | struct teimgr *tm = fi->userdata; | ||
| 705 | u_char *dp = arg; | ||
| 706 | int tei; | ||
| 707 | |||
| 708 | tei = dp[3] >> 1; | ||
| 709 | if (*debug & DEBUG_L2_TEI) | ||
| 710 | tm->tei_m.printdebug(fi, "identity verify req tei %d/%d", | ||
| 711 | tei, tm->l2->tei); | ||
| 712 | if (tei == tm->l2->tei) | ||
| 713 | tei_id_chk_req_net(fi, event, arg); | ||
| 714 | } | ||
| 715 | |||
| 716 | static void | ||
| 717 | tei_id_ver_tout_net(struct FsmInst *fi, int event, void *arg) | ||
| 718 | { | ||
| 719 | struct teimgr *tm = fi->userdata; | ||
| 720 | |||
| 721 | if (tm->rcnt == 1) { | ||
| 722 | if (*debug & DEBUG_L2_TEI) | ||
| 723 | tm->tei_m.printdebug(fi, | ||
| 724 | "check req for tei %d sucessful\n", tm->l2->tei); | ||
| 725 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
| 726 | } else if (tm->rcnt > 1) { | ||
| 727 | /* duplicate assignment; remove */ | ||
| 728 | tei_l2remove(tm->l2); | ||
| 729 | } else if (--tm->nval) { | ||
| 730 | if (*debug & DEBUG_L2_TEI) | ||
| 731 | tm->tei_m.printdebug(fi, | ||
| 732 | "id check req(%d) for tei %d", | ||
| 733 | 3 - tm->nval, tm->l2->tei); | ||
| 734 | put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei); | ||
| 735 | mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4); | ||
| 736 | } else { | ||
| 737 | tm->tei_m.printdebug(fi, "check req for tei %d failed", | ||
| 738 | tm->l2->tei); | ||
| 739 | mISDN_FsmChangeState(fi, ST_TEI_NOP); | ||
| 740 | tei_l2remove(tm->l2); | ||
| 741 | } | ||
| 742 | } | ||
| 743 | |||
| 744 | static struct FsmNode TeiFnListNet[] = | ||
| 745 | { | ||
| 746 | {ST_TEI_NOP, EV_ASSIGN_REQ, tei_assign_req}, | ||
| 747 | {ST_TEI_NOP, EV_VERIFY, tei_id_verify_net}, | ||
| 748 | {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req_net}, | ||
| 749 | {ST_TEI_IDVERIFY, EV_TIMER, tei_id_ver_tout_net}, | ||
| 750 | {ST_TEI_IDVERIFY, EV_CHKRESP, tei_id_chk_resp}, | ||
| 751 | }; | ||
| 752 | |||
| 753 | static void | ||
| 754 | tei_ph_data_ind(struct teimgr *tm, u_int mt, u_char *dp, int len) | ||
| 755 | { | ||
| 756 | if (test_bit(FLG_FIXED_TEI, &tm->l2->flag)) | ||
| 757 | return; | ||
| 758 | if (*debug & DEBUG_L2_TEI) | ||
| 759 | tm->tei_m.printdebug(&tm->tei_m, "tei handler mt %x", mt); | ||
| 760 | if (mt == ID_ASSIGNED) | ||
| 761 | mISDN_FsmEvent(&tm->tei_m, EV_ASSIGN, dp); | ||
| 762 | else if (mt == ID_DENIED) | ||
| 763 | mISDN_FsmEvent(&tm->tei_m, EV_DENIED, dp); | ||
| 764 | else if (mt == ID_CHK_REQ) | ||
| 765 | mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, dp); | ||
| 766 | else if (mt == ID_REMOVE) | ||
| 767 | mISDN_FsmEvent(&tm->tei_m, EV_REMOVE, dp); | ||
| 768 | else if (mt == ID_VERIFY) | ||
| 769 | mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, dp); | ||
| 770 | else if (mt == ID_CHK_RES) | ||
| 771 | mISDN_FsmEvent(&tm->tei_m, EV_CHKRESP, dp); | ||
| 772 | } | ||
| 773 | |||
| 774 | static struct layer2 * | ||
| 775 | create_new_tei(struct manager *mgr, int tei) | ||
| 776 | { | ||
| 777 | u_long opt = 0; | ||
| 778 | u_long flags; | ||
| 779 | int id; | ||
| 780 | struct layer2 *l2; | ||
| 781 | |||
| 782 | if (!mgr->up) | ||
| 783 | return NULL; | ||
| 784 | if (tei < 64) | ||
| 785 | test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); | ||
| 786 | if (mgr->ch.st->dev->Dprotocols | ||
| 787 | & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) | ||
| 788 | test_and_set_bit(OPTION_L2_PMX, &opt); | ||
| 789 | l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, (u_int)opt, (u_long)tei); | ||
| 790 | if (!l2) { | ||
| 791 | printk(KERN_WARNING "%s:no memory for layer2\n", __func__); | ||
| 792 | return NULL; | ||
| 793 | } | ||
| 794 | l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL); | ||
| 795 | if (!l2->tm) { | ||
| 796 | kfree(l2); | ||
| 797 | printk(KERN_WARNING "%s:no memory for teimgr\n", __func__); | ||
| 798 | return NULL; | ||
| 799 | } | ||
| 800 | l2->tm->mgr = mgr; | ||
| 801 | l2->tm->l2 = l2; | ||
| 802 | l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM; | ||
| 803 | l2->tm->tei_m.userdata = l2->tm; | ||
| 804 | l2->tm->tei_m.printdebug = tei_debug; | ||
| 805 | l2->tm->tei_m.fsm = &teifsmn; | ||
| 806 | l2->tm->tei_m.state = ST_TEI_NOP; | ||
| 807 | l2->tm->tval = 2000; /* T202 2 sec */ | ||
| 808 | mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); | ||
| 809 | write_lock_irqsave(&mgr->lock, flags); | ||
| 810 | id = get_free_id(mgr); | ||
| 811 | list_add_tail(&l2->list, &mgr->layer2); | ||
| 812 | write_unlock_irqrestore(&mgr->lock, flags); | ||
| 813 | if (id < 0) { | ||
| 814 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
| 815 | printk(KERN_WARNING "%s:no free id\n", __func__); | ||
| 816 | return NULL; | ||
| 817 | } else { | ||
| 818 | l2->ch.nr = id; | ||
| 819 | __add_layer2(&l2->ch, mgr->ch.st); | ||
| 820 | l2->ch.recv = mgr->ch.recv; | ||
| 821 | l2->ch.peer = mgr->ch.peer; | ||
| 822 | l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); | ||
| 823 | } | ||
| 824 | return l2; | ||
| 825 | } | ||
| 826 | |||
| 827 | static void | ||
| 828 | new_tei_req(struct manager *mgr, u_char *dp) | ||
| 829 | { | ||
| 830 | int tei, ri; | ||
| 831 | struct layer2 *l2; | ||
| 832 | |||
| 833 | ri = dp[0] << 8; | ||
| 834 | ri += dp[1]; | ||
| 835 | if (!mgr->up) | ||
| 836 | goto denied; | ||
| 837 | tei = get_free_tei(mgr); | ||
| 838 | if (tei < 0) { | ||
| 839 | printk(KERN_WARNING "%s:No free tei\n", __func__); | ||
| 840 | goto denied; | ||
| 841 | } | ||
| 842 | l2 = create_new_tei(mgr, tei); | ||
| 843 | if (!l2) | ||
| 844 | goto denied; | ||
| 845 | else | ||
| 846 | mISDN_FsmEvent(&l2->tm->tei_m, EV_ASSIGN_REQ, dp); | ||
| 847 | return; | ||
| 848 | denied: | ||
| 849 | put_tei_msg(mgr, ID_DENIED, ri, GROUP_TEI); | ||
| 850 | } | ||
| 851 | |||
| 852 | static int | ||
| 853 | ph_data_ind(struct manager *mgr, struct sk_buff *skb) | ||
| 854 | { | ||
| 855 | int ret = -EINVAL; | ||
| 856 | struct layer2 *l2; | ||
| 857 | u_long flags; | ||
| 858 | u_char mt; | ||
| 859 | |||
| 860 | if (skb->len < 8) { | ||
| 861 | if (*debug & DEBUG_L2_TEI) | ||
| 862 | printk(KERN_DEBUG "%s: short mgr frame %d/8\n", | ||
| 863 | __func__, skb->len); | ||
| 864 | goto done; | ||
| 865 | } | ||
| 866 | if (*debug & DEBUG_L2_TEI) | ||
| 867 | |||
| 868 | if ((skb->data[0] >> 2) != TEI_SAPI) /* not for us */ | ||
| 869 | goto done; | ||
| 870 | if (skb->data[0] & 1) /* EA0 formal error */ | ||
| 871 | goto done; | ||
| 872 | if (!(skb->data[1] & 1)) /* EA1 formal error */ | ||
| 873 | goto done; | ||
| 874 | if ((skb->data[1] >> 1) != GROUP_TEI) /* not for us */ | ||
| 875 | goto done; | ||
| 876 | if ((skb->data[2] & 0xef) != UI) /* not UI */ | ||
| 877 | goto done; | ||
| 878 | if (skb->data[3] != TEI_ENTITY_ID) /* not tei entity */ | ||
| 879 | goto done; | ||
| 880 | mt = skb->data[6]; | ||
| 881 | switch (mt) { | ||
| 882 | case ID_REQUEST: | ||
| 883 | case ID_CHK_RES: | ||
| 884 | case ID_VERIFY: | ||
| 885 | if (!test_bit(MGR_OPT_NETWORK, &mgr->options)) | ||
| 886 | goto done; | ||
| 887 | break; | ||
| 888 | case ID_ASSIGNED: | ||
| 889 | case ID_DENIED: | ||
| 890 | case ID_CHK_REQ: | ||
| 891 | case ID_REMOVE: | ||
| 892 | if (test_bit(MGR_OPT_NETWORK, &mgr->options)) | ||
| 893 | goto done; | ||
| 894 | break; | ||
| 895 | default: | ||
| 896 | goto done; | ||
| 897 | } | ||
| 898 | ret = 0; | ||
| 899 | if (mt == ID_REQUEST) { | ||
| 900 | new_tei_req(mgr, &skb->data[4]); | ||
| 901 | goto done; | ||
| 902 | } | ||
| 903 | read_lock_irqsave(&mgr->lock, flags); | ||
| 904 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
| 905 | tei_ph_data_ind(l2->tm, mt, &skb->data[4], skb->len - 4); | ||
| 906 | } | ||
| 907 | read_unlock_irqrestore(&mgr->lock, flags); | ||
| 908 | done: | ||
| 909 | return ret; | ||
| 910 | } | ||
| 911 | |||
| 912 | int | ||
| 913 | l2_tei(struct layer2 *l2, u_int cmd, u_long arg) | ||
| 914 | { | ||
| 915 | struct teimgr *tm = l2->tm; | ||
| 916 | |||
| 917 | if (test_bit(FLG_FIXED_TEI, &l2->flag)) | ||
| 918 | return 0; | ||
| 919 | if (*debug & DEBUG_L2_TEI) | ||
| 920 | printk(KERN_DEBUG "%s: cmd(%x)\n", __func__, cmd); | ||
| 921 | switch (cmd) { | ||
| 922 | case MDL_ASSIGN_IND: | ||
| 923 | mISDN_FsmEvent(&tm->tei_m, EV_IDREQ, NULL); | ||
| 924 | break; | ||
| 925 | case MDL_ERROR_IND: | ||
| 926 | if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) | ||
| 927 | mISDN_FsmEvent(&tm->tei_m, EV_CHKREQ, &l2->tei); | ||
| 928 | if (test_bit(MGR_OPT_USER, &tm->mgr->options)) | ||
| 929 | mISDN_FsmEvent(&tm->tei_m, EV_VERIFY, NULL); | ||
| 930 | break; | ||
| 931 | case MDL_STATUS_UP_IND: | ||
| 932 | if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) | ||
| 933 | mISDN_FsmEvent(&tm->mgr->deact, EV_ACTIVATE, NULL); | ||
| 934 | break; | ||
| 935 | case MDL_STATUS_DOWN_IND: | ||
| 936 | if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) | ||
| 937 | mISDN_FsmEvent(&tm->mgr->deact, EV_DEACTIVATE, NULL); | ||
| 938 | break; | ||
| 939 | case MDL_STATUS_UI_IND: | ||
| 940 | if (test_bit(MGR_OPT_NETWORK, &tm->mgr->options)) | ||
| 941 | mISDN_FsmEvent(&tm->mgr->deact, EV_UI, NULL); | ||
| 942 | break; | ||
| 943 | } | ||
| 944 | return 0; | ||
| 945 | } | ||
| 946 | |||
| 947 | void | ||
| 948 | TEIrelease(struct layer2 *l2) | ||
| 949 | { | ||
| 950 | struct teimgr *tm = l2->tm; | ||
| 951 | u_long flags; | ||
| 952 | |||
| 953 | mISDN_FsmDelTimer(&tm->timer, 1); | ||
| 954 | write_lock_irqsave(&tm->mgr->lock, flags); | ||
| 955 | list_del(&l2->list); | ||
| 956 | write_unlock_irqrestore(&tm->mgr->lock, flags); | ||
| 957 | l2->tm = NULL; | ||
| 958 | kfree(tm); | ||
| 959 | } | ||
| 960 | |||
| 961 | static int | ||
| 962 | create_teimgr(struct manager *mgr, struct channel_req *crq) | ||
| 963 | { | ||
| 964 | struct layer2 *l2; | ||
| 965 | u_long opt = 0; | ||
| 966 | u_long flags; | ||
| 967 | int id; | ||
| 968 | |||
| 969 | if (*debug & DEBUG_L2_TEI) | ||
| 970 | printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", | ||
| 971 | __func__, mgr->ch.st->dev->name, crq->protocol, | ||
| 972 | crq->adr.dev, crq->adr.channel, crq->adr.sapi, | ||
| 973 | crq->adr.tei); | ||
| 974 | if (crq->adr.sapi != 0) /* not supported yet */ | ||
| 975 | return -EINVAL; | ||
| 976 | if (crq->adr.tei > GROUP_TEI) | ||
| 977 | return -EINVAL; | ||
| 978 | if (crq->adr.tei < 64) | ||
| 979 | test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); | ||
| 980 | if (crq->adr.tei == 0) | ||
| 981 | test_and_set_bit(OPTION_L2_PTP, &opt); | ||
| 982 | if (test_bit(MGR_OPT_NETWORK, &mgr->options)) { | ||
| 983 | if (crq->protocol == ISDN_P_LAPD_TE) | ||
| 984 | return -EPROTONOSUPPORT; | ||
| 985 | if ((crq->adr.tei != 0) && (crq->adr.tei != 127)) | ||
| 986 | return -EINVAL; | ||
| 987 | if (mgr->up) { | ||
| 988 | printk(KERN_WARNING | ||
| 989 | "%s: only one network manager is allowed\n", | ||
| 990 | __func__); | ||
| 991 | return -EBUSY; | ||
| 992 | } | ||
| 993 | } else if (test_bit(MGR_OPT_USER, &mgr->options)) { | ||
| 994 | if (crq->protocol == ISDN_P_LAPD_NT) | ||
| 995 | return -EPROTONOSUPPORT; | ||
| 996 | if ((crq->adr.tei >= 64) && (crq->adr.tei < GROUP_TEI)) | ||
| 997 | return -EINVAL; /* dyn tei */ | ||
| 998 | } else { | ||
| 999 | if (crq->protocol == ISDN_P_LAPD_NT) | ||
| 1000 | test_and_set_bit(MGR_OPT_NETWORK, &mgr->options); | ||
| 1001 | if (crq->protocol == ISDN_P_LAPD_TE) | ||
| 1002 | test_and_set_bit(MGR_OPT_USER, &mgr->options); | ||
| 1003 | } | ||
| 1004 | if (mgr->ch.st->dev->Dprotocols | ||
| 1005 | & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) | ||
| 1006 | test_and_set_bit(OPTION_L2_PMX, &opt); | ||
| 1007 | if ((crq->protocol == ISDN_P_LAPD_NT) && (crq->adr.tei == 127)) { | ||
| 1008 | mgr->up = crq->ch; | ||
| 1009 | id = DL_INFO_L2_CONNECT; | ||
| 1010 | teiup_create(mgr, DL_INFORMATION_IND, sizeof(id), &id); | ||
| 1011 | crq->ch = NULL; | ||
| 1012 | if (!list_empty(&mgr->layer2)) { | ||
| 1013 | read_lock_irqsave(&mgr->lock, flags); | ||
| 1014 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
| 1015 | l2->up = mgr->up; | ||
| 1016 | l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); | ||
| 1017 | } | ||
| 1018 | read_unlock_irqrestore(&mgr->lock, flags); | ||
| 1019 | } | ||
| 1020 | return 0; | ||
| 1021 | } | ||
| 1022 | l2 = create_l2(crq->ch, crq->protocol, (u_int)opt, | ||
| 1023 | (u_long)crq->adr.tei); | ||
| 1024 | if (!l2) | ||
| 1025 | return -ENOMEM; | ||
| 1026 | l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL); | ||
| 1027 | if (!l2->tm) { | ||
| 1028 | kfree(l2); | ||
| 1029 | printk(KERN_ERR "kmalloc teimgr failed\n"); | ||
| 1030 | return -ENOMEM; | ||
| 1031 | } | ||
| 1032 | l2->tm->mgr = mgr; | ||
| 1033 | l2->tm->l2 = l2; | ||
| 1034 | l2->tm->tei_m.debug = *debug & DEBUG_L2_TEIFSM; | ||
| 1035 | l2->tm->tei_m.userdata = l2->tm; | ||
| 1036 | l2->tm->tei_m.printdebug = tei_debug; | ||
| 1037 | if (crq->protocol == ISDN_P_LAPD_TE) { | ||
| 1038 | l2->tm->tei_m.fsm = &teifsmu; | ||
| 1039 | l2->tm->tei_m.state = ST_TEI_NOP; | ||
| 1040 | l2->tm->tval = 1000; /* T201 1 sec */ | ||
| 1041 | } else { | ||
| 1042 | l2->tm->tei_m.fsm = &teifsmn; | ||
| 1043 | l2->tm->tei_m.state = ST_TEI_NOP; | ||
| 1044 | l2->tm->tval = 2000; /* T202 2 sec */ | ||
| 1045 | } | ||
| 1046 | mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); | ||
| 1047 | write_lock_irqsave(&mgr->lock, flags); | ||
| 1048 | id = get_free_id(mgr); | ||
| 1049 | list_add_tail(&l2->list, &mgr->layer2); | ||
| 1050 | write_unlock_irqrestore(&mgr->lock, flags); | ||
| 1051 | if (id < 0) { | ||
| 1052 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
| 1053 | } else { | ||
| 1054 | l2->ch.nr = id; | ||
| 1055 | l2->up->nr = id; | ||
| 1056 | crq->ch = &l2->ch; | ||
| 1057 | id = 0; | ||
| 1058 | } | ||
| 1059 | return id; | ||
| 1060 | } | ||
| 1061 | |||
| 1062 | static int | ||
| 1063 | mgr_send(struct mISDNchannel *ch, struct sk_buff *skb) | ||
| 1064 | { | ||
| 1065 | struct manager *mgr; | ||
| 1066 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
| 1067 | int ret = -EINVAL; | ||
| 1068 | |||
| 1069 | mgr = container_of(ch, struct manager, ch); | ||
| 1070 | if (*debug & DEBUG_L2_RECV) | ||
| 1071 | printk(KERN_DEBUG "%s: prim(%x) id(%x)\n", | ||
| 1072 | __func__, hh->prim, hh->id); | ||
| 1073 | switch (hh->prim) { | ||
| 1074 | case PH_DATA_IND: | ||
| 1075 | mISDN_FsmEvent(&mgr->deact, EV_UI, NULL); | ||
| 1076 | ret = ph_data_ind(mgr, skb); | ||
| 1077 | break; | ||
| 1078 | case PH_DATA_CNF: | ||
| 1079 | do_ack(mgr, hh->id); | ||
| 1080 | ret = 0; | ||
| 1081 | break; | ||
| 1082 | case PH_ACTIVATE_IND: | ||
| 1083 | test_and_set_bit(MGR_PH_ACTIVE, &mgr->options); | ||
| 1084 | mISDN_FsmEvent(&mgr->deact, EV_ACTIVATE_IND, NULL); | ||
| 1085 | do_send(mgr); | ||
| 1086 | ret = 0; | ||
| 1087 | break; | ||
| 1088 | case PH_DEACTIVATE_IND: | ||
| 1089 | test_and_clear_bit(MGR_PH_ACTIVE, &mgr->options); | ||
| 1090 | mISDN_FsmEvent(&mgr->deact, EV_DEACTIVATE_IND, NULL); | ||
| 1091 | ret = 0; | ||
| 1092 | break; | ||
| 1093 | case DL_UNITDATA_REQ: | ||
| 1094 | return dl_unit_data(mgr, skb); | ||
| 1095 | } | ||
| 1096 | if (!ret) | ||
| 1097 | dev_kfree_skb(skb); | ||
| 1098 | return ret; | ||
| 1099 | } | ||
| 1100 | |||
| 1101 | static int | ||
| 1102 | free_teimanager(struct manager *mgr) | ||
| 1103 | { | ||
| 1104 | struct layer2 *l2, *nl2; | ||
| 1105 | |||
| 1106 | if (test_bit(MGR_OPT_NETWORK, &mgr->options)) { | ||
| 1107 | /* not locked lock is taken in release tei */ | ||
| 1108 | mgr->up = NULL; | ||
| 1109 | if (test_bit(OPTION_L2_CLEANUP, &mgr->options)) { | ||
| 1110 | list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { | ||
| 1111 | put_tei_msg(mgr, ID_REMOVE, 0, l2->tei); | ||
| 1112 | mutex_lock(&mgr->ch.st->lmutex); | ||
| 1113 | list_del(&l2->ch.list); | ||
| 1114 | mutex_unlock(&mgr->ch.st->lmutex); | ||
| 1115 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
| 1116 | } | ||
| 1117 | test_and_clear_bit(MGR_OPT_NETWORK, &mgr->options); | ||
| 1118 | } else { | ||
| 1119 | list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { | ||
| 1120 | l2->up = NULL; | ||
| 1121 | } | ||
| 1122 | } | ||
| 1123 | } | ||
| 1124 | if (test_bit(MGR_OPT_USER, &mgr->options)) { | ||
| 1125 | if (list_empty(&mgr->layer2)) | ||
| 1126 | test_and_clear_bit(MGR_OPT_USER, &mgr->options); | ||
| 1127 | } | ||
| 1128 | mgr->ch.st->dev->D.ctrl(&mgr->ch.st->dev->D, CLOSE_CHANNEL, NULL); | ||
| 1129 | return 0; | ||
| 1130 | } | ||
| 1131 | |||
| 1132 | static int | ||
| 1133 | ctrl_teimanager(struct manager *mgr, void *arg) | ||
| 1134 | { | ||
| 1135 | /* currently we only have one option */ | ||
| 1136 | int clean = *((int *)arg); | ||
| 1137 | |||
| 1138 | if (clean) | ||
| 1139 | test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options); | ||
| 1140 | else | ||
| 1141 | test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options); | ||
| 1142 | return 0; | ||
| 1143 | } | ||
| 1144 | |||
| 1145 | /* This function does create a L2 for fixed TEI in NT Mode */ | ||
| 1146 | static int | ||
| 1147 | check_data(struct manager *mgr, struct sk_buff *skb) | ||
| 1148 | { | ||
| 1149 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
| 1150 | int ret, tei; | ||
| 1151 | struct layer2 *l2; | ||
| 1152 | |||
| 1153 | if (*debug & DEBUG_L2_CTRL) | ||
| 1154 | printk(KERN_DEBUG "%s: prim(%x) id(%x)\n", | ||
| 1155 | __func__, hh->prim, hh->id); | ||
| 1156 | if (test_bit(MGR_OPT_USER, &mgr->options)) | ||
| 1157 | return -ENOTCONN; | ||
| 1158 | if (hh->prim != PH_DATA_IND) | ||
| 1159 | return -ENOTCONN; | ||
| 1160 | if (skb->len != 3) | ||
| 1161 | return -ENOTCONN; | ||
| 1162 | if (skb->data[0] != 0) | ||
| 1163 | /* only SAPI 0 command */ | ||
| 1164 | return -ENOTCONN; | ||
| 1165 | if (!(skb->data[1] & 1)) /* invalid EA1 */ | ||
| 1166 | return -EINVAL; | ||
| 1167 | tei = skb->data[1] >> 0; | ||
| 1168 | if (tei > 63) /* not a fixed tei */ | ||
| 1169 | return -ENOTCONN; | ||
| 1170 | if ((skb->data[2] & ~0x10) != SABME) | ||
| 1171 | return -ENOTCONN; | ||
| 1172 | /* We got a SABME for a fixed TEI */ | ||
| 1173 | l2 = create_new_tei(mgr, tei); | ||
| 1174 | if (!l2) | ||
| 1175 | return -ENOMEM; | ||
| 1176 | ret = l2->ch.send(&l2->ch, skb); | ||
| 1177 | return ret; | ||
| 1178 | } | ||
| 1179 | |||
| 1180 | void | ||
| 1181 | delete_teimanager(struct mISDNchannel *ch) | ||
| 1182 | { | ||
| 1183 | struct manager *mgr; | ||
| 1184 | struct layer2 *l2, *nl2; | ||
| 1185 | |||
| 1186 | mgr = container_of(ch, struct manager, ch); | ||
| 1187 | /* not locked lock is taken in release tei */ | ||
| 1188 | list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { | ||
| 1189 | mutex_lock(&mgr->ch.st->lmutex); | ||
| 1190 | list_del(&l2->ch.list); | ||
| 1191 | mutex_unlock(&mgr->ch.st->lmutex); | ||
| 1192 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
| 1193 | } | ||
| 1194 | list_del(&mgr->ch.list); | ||
| 1195 | list_del(&mgr->bcast.list); | ||
| 1196 | skb_queue_purge(&mgr->sendq); | ||
| 1197 | kfree(mgr); | ||
| 1198 | } | ||
| 1199 | |||
| 1200 | static int | ||
| 1201 | mgr_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
| 1202 | { | ||
| 1203 | struct manager *mgr; | ||
| 1204 | int ret = -EINVAL; | ||
| 1205 | |||
| 1206 | mgr = container_of(ch, struct manager, ch); | ||
| 1207 | if (*debug & DEBUG_L2_CTRL) | ||
| 1208 | printk(KERN_DEBUG "%s(%x, %p)\n", __func__, cmd, arg); | ||
| 1209 | switch (cmd) { | ||
| 1210 | case OPEN_CHANNEL: | ||
| 1211 | ret = create_teimgr(mgr, arg); | ||
| 1212 | break; | ||
| 1213 | case CLOSE_CHANNEL: | ||
| 1214 | ret = free_teimanager(mgr); | ||
| 1215 | break; | ||
| 1216 | case CONTROL_CHANNEL: | ||
| 1217 | ret = ctrl_teimanager(mgr, arg); | ||
| 1218 | break; | ||
| 1219 | case CHECK_DATA: | ||
| 1220 | ret = check_data(mgr, arg); | ||
| 1221 | break; | ||
| 1222 | } | ||
| 1223 | return ret; | ||
| 1224 | } | ||
| 1225 | |||
| 1226 | static int | ||
| 1227 | mgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb) | ||
| 1228 | { | ||
| 1229 | struct manager *mgr = container_of(ch, struct manager, bcast); | ||
| 1230 | struct mISDNhead *hh = mISDN_HEAD_P(skb); | ||
| 1231 | struct sk_buff *cskb = NULL; | ||
| 1232 | struct layer2 *l2; | ||
| 1233 | u_long flags; | ||
| 1234 | int ret; | ||
| 1235 | |||
| 1236 | read_lock_irqsave(&mgr->lock, flags); | ||
| 1237 | list_for_each_entry(l2, &mgr->layer2, list) { | ||
| 1238 | if ((hh->id & MISDN_ID_SAPI_MASK) == | ||
| 1239 | (l2->ch.addr & MISDN_ID_SAPI_MASK)) { | ||
| 1240 | if (list_is_last(&l2->list, &mgr->layer2)) { | ||
| 1241 | cskb = skb; | ||
| 1242 | skb = NULL; | ||
| 1243 | } else { | ||
| 1244 | if (!cskb) | ||
| 1245 | cskb = skb_copy(skb, GFP_KERNEL); | ||
| 1246 | } | ||
| 1247 | if (cskb) { | ||
| 1248 | ret = l2->ch.send(&l2->ch, cskb); | ||
| 1249 | if (ret) { | ||
| 1250 | if (*debug & DEBUG_SEND_ERR) | ||
| 1251 | printk(KERN_DEBUG | ||
| 1252 | "%s ch%d prim(%x) addr(%x)" | ||
| 1253 | " err %d\n", | ||
| 1254 | __func__, l2->ch.nr, | ||
| 1255 | hh->prim, l2->ch.addr, ret); | ||
| 1256 | } else | ||
| 1257 | cskb = NULL; | ||
| 1258 | } else { | ||
| 1259 | printk(KERN_WARNING "%s ch%d addr %x no mem\n", | ||
| 1260 | __func__, ch->nr, ch->addr); | ||
| 1261 | goto out; | ||
| 1262 | } | ||
| 1263 | } | ||
| 1264 | } | ||
| 1265 | out: | ||
| 1266 | read_unlock_irqrestore(&mgr->lock, flags); | ||
| 1267 | if (cskb) | ||
| 1268 | dev_kfree_skb(cskb); | ||
| 1269 | if (skb) | ||
| 1270 | dev_kfree_skb(skb); | ||
| 1271 | return 0; | ||
| 1272 | } | ||
| 1273 | |||
| 1274 | static int | ||
| 1275 | mgr_bcast_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) | ||
| 1276 | { | ||
| 1277 | |||
| 1278 | return -EINVAL; | ||
| 1279 | } | ||
| 1280 | |||
| 1281 | int | ||
| 1282 | create_teimanager(struct mISDNdevice *dev) | ||
| 1283 | { | ||
| 1284 | struct manager *mgr; | ||
| 1285 | |||
| 1286 | mgr = kzalloc(sizeof(struct manager), GFP_KERNEL); | ||
| 1287 | if (!mgr) | ||
| 1288 | return -ENOMEM; | ||
| 1289 | INIT_LIST_HEAD(&mgr->layer2); | ||
| 1290 | mgr->lock = __RW_LOCK_UNLOCKED(mgr->lock); | ||
| 1291 | skb_queue_head_init(&mgr->sendq); | ||
| 1292 | mgr->nextid = 1; | ||
| 1293 | mgr->lastid = MISDN_ID_NONE; | ||
| 1294 | mgr->ch.send = mgr_send; | ||
| 1295 | mgr->ch.ctrl = mgr_ctrl; | ||
| 1296 | mgr->ch.st = dev->D.st; | ||
| 1297 | set_channel_address(&mgr->ch, TEI_SAPI, GROUP_TEI); | ||
| 1298 | add_layer2(&mgr->ch, dev->D.st); | ||
| 1299 | mgr->bcast.send = mgr_bcast; | ||
| 1300 | mgr->bcast.ctrl = mgr_bcast_ctrl; | ||
| 1301 | mgr->bcast.st = dev->D.st; | ||
| 1302 | set_channel_address(&mgr->bcast, 0, GROUP_TEI); | ||
| 1303 | add_layer2(&mgr->bcast, dev->D.st); | ||
| 1304 | mgr->deact.debug = *debug & DEBUG_MANAGER; | ||
| 1305 | mgr->deact.userdata = mgr; | ||
| 1306 | mgr->deact.printdebug = da_debug; | ||
| 1307 | mgr->deact.fsm = &deactfsm; | ||
| 1308 | mgr->deact.state = ST_L1_DEACT; | ||
| 1309 | mISDN_FsmInitTimer(&mgr->deact, &mgr->datimer); | ||
| 1310 | dev->teimgr = &mgr->ch; | ||
| 1311 | return 0; | ||
| 1312 | } | ||
| 1313 | |||
| 1314 | int TEIInit(u_int *deb) | ||
| 1315 | { | ||
| 1316 | debug = deb; | ||
| 1317 | teifsmu.state_count = TEI_STATE_COUNT; | ||
| 1318 | teifsmu.event_count = TEI_EVENT_COUNT; | ||
| 1319 | teifsmu.strEvent = strTeiEvent; | ||
| 1320 | teifsmu.strState = strTeiState; | ||
| 1321 | mISDN_FsmNew(&teifsmu, TeiFnListUser, ARRAY_SIZE(TeiFnListUser)); | ||
| 1322 | teifsmn.state_count = TEI_STATE_COUNT; | ||
| 1323 | teifsmn.event_count = TEI_EVENT_COUNT; | ||
| 1324 | teifsmn.strEvent = strTeiEvent; | ||
| 1325 | teifsmn.strState = strTeiState; | ||
| 1326 | mISDN_FsmNew(&teifsmn, TeiFnListNet, ARRAY_SIZE(TeiFnListNet)); | ||
| 1327 | deactfsm.state_count = DEACT_STATE_COUNT; | ||
| 1328 | deactfsm.event_count = DEACT_EVENT_COUNT; | ||
| 1329 | deactfsm.strEvent = strDeactEvent; | ||
| 1330 | deactfsm.strState = strDeactState; | ||
| 1331 | mISDN_FsmNew(&deactfsm, DeactFnList, ARRAY_SIZE(DeactFnList)); | ||
| 1332 | return 0; | ||
| 1333 | } | ||
| 1334 | |||
| 1335 | void TEIFree(void) | ||
| 1336 | { | ||
| 1337 | mISDN_FsmFree(&teifsmu); | ||
| 1338 | mISDN_FsmFree(&teifsmn); | ||
| 1339 | mISDN_FsmFree(&deactfsm); | ||
| 1340 | } | ||
diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c new file mode 100644 index 000000000000..b5fabc7019d8 --- /dev/null +++ b/drivers/isdn/mISDN/timerdev.c | |||
| @@ -0,0 +1,301 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * general timer device for using in ISDN stacks | ||
| 4 | * | ||
| 5 | * Author Karsten Keil <kkeil@novell.com> | ||
| 6 | * | ||
| 7 | * Copyright 2008 by Karsten Keil <kkeil@novell.com> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/poll.h> | ||
| 21 | #include <linux/vmalloc.h> | ||
| 22 | #include <linux/timer.h> | ||
| 23 | #include <linux/miscdevice.h> | ||
| 24 | #include <linux/module.h> | ||
| 25 | #include <linux/mISDNif.h> | ||
| 26 | |||
| 27 | static int *debug; | ||
| 28 | |||
| 29 | |||
| 30 | struct mISDNtimerdev { | ||
| 31 | int next_id; | ||
| 32 | struct list_head pending; | ||
| 33 | struct list_head expired; | ||
| 34 | wait_queue_head_t wait; | ||
| 35 | u_int work; | ||
| 36 | spinlock_t lock; /* protect lists */ | ||
| 37 | }; | ||
| 38 | |||
| 39 | struct mISDNtimer { | ||
| 40 | struct list_head list; | ||
| 41 | struct mISDNtimerdev *dev; | ||
| 42 | struct timer_list tl; | ||
| 43 | int id; | ||
| 44 | }; | ||
| 45 | |||
| 46 | static int | ||
| 47 | mISDN_open(struct inode *ino, struct file *filep) | ||
| 48 | { | ||
| 49 | struct mISDNtimerdev *dev; | ||
| 50 | |||
| 51 | if (*debug & DEBUG_TIMER) | ||
| 52 | printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep); | ||
| 53 | dev = kmalloc(sizeof(struct mISDNtimerdev) , GFP_KERNEL); | ||
| 54 | if (!dev) | ||
| 55 | return -ENOMEM; | ||
| 56 | dev->next_id = 1; | ||
| 57 | INIT_LIST_HEAD(&dev->pending); | ||
| 58 | INIT_LIST_HEAD(&dev->expired); | ||
| 59 | spin_lock_init(&dev->lock); | ||
| 60 | dev->work = 0; | ||
| 61 | init_waitqueue_head(&dev->wait); | ||
| 62 | filep->private_data = dev; | ||
| 63 | __module_get(THIS_MODULE); | ||
| 64 | return 0; | ||
| 65 | } | ||
| 66 | |||
| 67 | static int | ||
| 68 | mISDN_close(struct inode *ino, struct file *filep) | ||
| 69 | { | ||
| 70 | struct mISDNtimerdev *dev = filep->private_data; | ||
| 71 | struct mISDNtimer *timer, *next; | ||
| 72 | |||
| 73 | if (*debug & DEBUG_TIMER) | ||
| 74 | printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep); | ||
| 75 | list_for_each_entry_safe(timer, next, &dev->pending, list) { | ||
| 76 | del_timer(&timer->tl); | ||
| 77 | kfree(timer); | ||
| 78 | } | ||
| 79 | list_for_each_entry_safe(timer, next, &dev->expired, list) { | ||
| 80 | kfree(timer); | ||
| 81 | } | ||
| 82 | kfree(dev); | ||
| 83 | module_put(THIS_MODULE); | ||
| 84 | return 0; | ||
| 85 | } | ||
| 86 | |||
| 87 | static ssize_t | ||
| 88 | mISDN_read(struct file *filep, char *buf, size_t count, loff_t *off) | ||
| 89 | { | ||
| 90 | struct mISDNtimerdev *dev = filep->private_data; | ||
| 91 | struct mISDNtimer *timer; | ||
| 92 | u_long flags; | ||
| 93 | int ret = 0; | ||
| 94 | |||
| 95 | if (*debug & DEBUG_TIMER) | ||
| 96 | printk(KERN_DEBUG "%s(%p, %p, %d, %p)\n", __func__, | ||
| 97 | filep, buf, (int)count, off); | ||
| 98 | if (*off != filep->f_pos) | ||
| 99 | return -ESPIPE; | ||
| 100 | |||
| 101 | if (list_empty(&dev->expired) && (dev->work == 0)) { | ||
| 102 | if (filep->f_flags & O_NONBLOCK) | ||
| 103 | return -EAGAIN; | ||
| 104 | wait_event_interruptible(dev->wait, (dev->work || | ||
| 105 | !list_empty(&dev->expired))); | ||
| 106 | if (signal_pending(current)) | ||
| 107 | return -ERESTARTSYS; | ||
| 108 | } | ||
| 109 | if (count < sizeof(int)) | ||
| 110 | return -ENOSPC; | ||
| 111 | if (dev->work) | ||
| 112 | dev->work = 0; | ||
| 113 | if (!list_empty(&dev->expired)) { | ||
| 114 | spin_lock_irqsave(&dev->lock, flags); | ||
| 115 | timer = (struct mISDNtimer *)dev->expired.next; | ||
| 116 | list_del(&timer->list); | ||
| 117 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 118 | if (put_user(timer->id, (int *)buf)) | ||
| 119 | ret = -EFAULT; | ||
| 120 | else | ||
| 121 | ret = sizeof(int); | ||
| 122 | kfree(timer); | ||
| 123 | } | ||
| 124 | return ret; | ||
| 125 | } | ||
| 126 | |||
| 127 | static loff_t | ||
| 128 | mISDN_llseek(struct file *filep, loff_t offset, int orig) | ||
| 129 | { | ||
| 130 | return -ESPIPE; | ||
| 131 | } | ||
| 132 | |||
| 133 | static ssize_t | ||
| 134 | mISDN_write(struct file *filep, const char *buf, size_t count, loff_t *off) | ||
| 135 | { | ||
| 136 | return -EOPNOTSUPP; | ||
| 137 | } | ||
| 138 | |||
| 139 | static unsigned int | ||
| 140 | mISDN_poll(struct file *filep, poll_table *wait) | ||
| 141 | { | ||
| 142 | struct mISDNtimerdev *dev = filep->private_data; | ||
| 143 | unsigned int mask = POLLERR; | ||
| 144 | |||
| 145 | if (*debug & DEBUG_TIMER) | ||
| 146 | printk(KERN_DEBUG "%s(%p, %p)\n", __func__, filep, wait); | ||
| 147 | if (dev) { | ||
| 148 | poll_wait(filep, &dev->wait, wait); | ||
| 149 | mask = 0; | ||
| 150 | if (dev->work || !list_empty(&dev->expired)) | ||
| 151 | mask |= (POLLIN | POLLRDNORM); | ||
| 152 | if (*debug & DEBUG_TIMER) | ||
| 153 | printk(KERN_DEBUG "%s work(%d) empty(%d)\n", __func__, | ||
| 154 | dev->work, list_empty(&dev->expired)); | ||
| 155 | } | ||
| 156 | return mask; | ||
| 157 | } | ||
| 158 | |||
| 159 | static void | ||
| 160 | dev_expire_timer(struct mISDNtimer *timer) | ||
| 161 | { | ||
| 162 | u_long flags; | ||
| 163 | |||
| 164 | spin_lock_irqsave(&timer->dev->lock, flags); | ||
| 165 | list_del(&timer->list); | ||
| 166 | list_add_tail(&timer->list, &timer->dev->expired); | ||
| 167 | spin_unlock_irqrestore(&timer->dev->lock, flags); | ||
| 168 | wake_up_interruptible(&timer->dev->wait); | ||
| 169 | } | ||
| 170 | |||
| 171 | static int | ||
| 172 | misdn_add_timer(struct mISDNtimerdev *dev, int timeout) | ||
| 173 | { | ||
| 174 | int id; | ||
| 175 | u_long flags; | ||
| 176 | struct mISDNtimer *timer; | ||
| 177 | |||
| 178 | if (!timeout) { | ||
| 179 | dev->work = 1; | ||
| 180 | wake_up_interruptible(&dev->wait); | ||
| 181 | id = 0; | ||
| 182 | } else { | ||
| 183 | timer = kzalloc(sizeof(struct mISDNtimer), GFP_KERNEL); | ||
| 184 | if (!timer) | ||
| 185 | return -ENOMEM; | ||
| 186 | spin_lock_irqsave(&dev->lock, flags); | ||
| 187 | timer->id = dev->next_id++; | ||
| 188 | if (dev->next_id < 0) | ||
| 189 | dev->next_id = 1; | ||
| 190 | list_add_tail(&timer->list, &dev->pending); | ||
| 191 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 192 | timer->dev = dev; | ||
| 193 | timer->tl.data = (long)timer; | ||
| 194 | timer->tl.function = (void *) dev_expire_timer; | ||
| 195 | init_timer(&timer->tl); | ||
| 196 | timer->tl.expires = jiffies + ((HZ * (u_long)timeout) / 1000); | ||
| 197 | add_timer(&timer->tl); | ||
| 198 | id = timer->id; | ||
| 199 | } | ||
| 200 | return id; | ||
| 201 | } | ||
| 202 | |||
| 203 | static int | ||
| 204 | misdn_del_timer(struct mISDNtimerdev *dev, int id) | ||
| 205 | { | ||
| 206 | u_long flags; | ||
| 207 | struct mISDNtimer *timer; | ||
| 208 | int ret = 0; | ||
| 209 | |||
| 210 | spin_lock_irqsave(&dev->lock, flags); | ||
| 211 | list_for_each_entry(timer, &dev->pending, list) { | ||
| 212 | if (timer->id == id) { | ||
| 213 | list_del_init(&timer->list); | ||
| 214 | del_timer(&timer->tl); | ||
| 215 | ret = timer->id; | ||
| 216 | kfree(timer); | ||
| 217 | goto unlock; | ||
| 218 | } | ||
| 219 | } | ||
| 220 | unlock: | ||
| 221 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 222 | return ret; | ||
| 223 | } | ||
| 224 | |||
| 225 | static int | ||
| 226 | mISDN_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, | ||
| 227 | unsigned long arg) | ||
| 228 | { | ||
| 229 | struct mISDNtimerdev *dev = filep->private_data; | ||
| 230 | int id, tout, ret = 0; | ||
| 231 | |||
| 232 | |||
| 233 | if (*debug & DEBUG_TIMER) | ||
| 234 | printk(KERN_DEBUG "%s(%p, %x, %lx)\n", __func__, | ||
| 235 | filep, cmd, arg); | ||
| 236 | switch (cmd) { | ||
| 237 | case IMADDTIMER: | ||
| 238 | if (get_user(tout, (int __user *)arg)) { | ||
| 239 | ret = -EFAULT; | ||
| 240 | break; | ||
| 241 | } | ||
| 242 | id = misdn_add_timer(dev, tout); | ||
| 243 | if (*debug & DEBUG_TIMER) | ||
| 244 | printk(KERN_DEBUG "%s add %d id %d\n", __func__, | ||
| 245 | tout, id); | ||
| 246 | if (id < 0) { | ||
| 247 | ret = id; | ||
| 248 | break; | ||
| 249 | } | ||
| 250 | if (put_user(id, (int __user *)arg)) | ||
| 251 | ret = -EFAULT; | ||
| 252 | break; | ||
| 253 | case IMDELTIMER: | ||
| 254 | if (get_user(id, (int __user *)arg)) { | ||
| 255 | ret = -EFAULT; | ||
| 256 | break; | ||
| 257 | } | ||
| 258 | if (*debug & DEBUG_TIMER) | ||
| 259 | printk(KERN_DEBUG "%s del id %d\n", __func__, id); | ||
| 260 | id = misdn_del_timer(dev, id); | ||
| 261 | if (put_user(id, (int __user *)arg)) | ||
| 262 | ret = -EFAULT; | ||
| 263 | break; | ||
| 264 | default: | ||
| 265 | ret = -EINVAL; | ||
| 266 | } | ||
| 267 | return ret; | ||
| 268 | } | ||
| 269 | |||
| 270 | static struct file_operations mISDN_fops = { | ||
| 271 | .llseek = mISDN_llseek, | ||
| 272 | .read = mISDN_read, | ||
| 273 | .write = mISDN_write, | ||
| 274 | .poll = mISDN_poll, | ||
| 275 | .ioctl = mISDN_ioctl, | ||
| 276 | .open = mISDN_open, | ||
| 277 | .release = mISDN_close, | ||
| 278 | }; | ||
| 279 | |||
| 280 | static struct miscdevice mISDNtimer = { | ||
| 281 | .minor = MISC_DYNAMIC_MINOR, | ||
| 282 | .name = "mISDNtimer", | ||
| 283 | .fops = &mISDN_fops, | ||
| 284 | }; | ||
| 285 | |||
| 286 | int | ||
| 287 | mISDN_inittimer(int *deb) | ||
| 288 | { | ||
| 289 | int err; | ||
| 290 | |||
| 291 | debug = deb; | ||
| 292 | err = misc_register(&mISDNtimer); | ||
| 293 | if (err) | ||
| 294 | printk(KERN_WARNING "mISDN: Could not register timer device\n"); | ||
| 295 | return err; | ||
| 296 | } | ||
| 297 | |||
| 298 | void mISDN_timer_cleanup(void) | ||
| 299 | { | ||
| 300 | misc_deregister(&mISDNtimer); | ||
| 301 | } | ||
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index fea966d66f98..71dd65aa31b6 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c | |||
| @@ -147,9 +147,12 @@ static struct priority_group *alloc_priority_group(void) | |||
| 147 | static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti) | 147 | static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti) |
| 148 | { | 148 | { |
| 149 | struct pgpath *pgpath, *tmp; | 149 | struct pgpath *pgpath, *tmp; |
| 150 | struct multipath *m = ti->private; | ||
| 150 | 151 | ||
| 151 | list_for_each_entry_safe(pgpath, tmp, pgpaths, list) { | 152 | list_for_each_entry_safe(pgpath, tmp, pgpaths, list) { |
| 152 | list_del(&pgpath->list); | 153 | list_del(&pgpath->list); |
| 154 | if (m->hw_handler_name) | ||
| 155 | scsi_dh_detach(bdev_get_queue(pgpath->path.dev->bdev)); | ||
| 153 | dm_put_device(ti, pgpath->path.dev); | 156 | dm_put_device(ti, pgpath->path.dev); |
| 154 | free_pgpath(pgpath); | 157 | free_pgpath(pgpath); |
| 155 | } | 158 | } |
| @@ -548,6 +551,7 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps, | |||
| 548 | { | 551 | { |
| 549 | int r; | 552 | int r; |
| 550 | struct pgpath *p; | 553 | struct pgpath *p; |
| 554 | struct multipath *m = ti->private; | ||
| 551 | 555 | ||
| 552 | /* we need at least a path arg */ | 556 | /* we need at least a path arg */ |
| 553 | if (as->argc < 1) { | 557 | if (as->argc < 1) { |
| @@ -566,6 +570,15 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps, | |||
| 566 | goto bad; | 570 | goto bad; |
| 567 | } | 571 | } |
| 568 | 572 | ||
| 573 | if (m->hw_handler_name) { | ||
| 574 | r = scsi_dh_attach(bdev_get_queue(p->path.dev->bdev), | ||
| 575 | m->hw_handler_name); | ||
| 576 | if (r < 0) { | ||
| 577 | dm_put_device(ti, p->path.dev); | ||
| 578 | goto bad; | ||
| 579 | } | ||
| 580 | } | ||
| 581 | |||
| 569 | r = ps->type->add_path(ps, &p->path, as->argc, as->argv, &ti->error); | 582 | r = ps->type->add_path(ps, &p->path, as->argc, as->argv, &ti->error); |
| 570 | if (r) { | 583 | if (r) { |
| 571 | dm_put_device(ti, p->path.dev); | 584 | dm_put_device(ti, p->path.dev); |
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c index 1360403b88b6..a9653c63f4db 100644 --- a/drivers/media/dvb/pluto2/pluto2.c +++ b/drivers/media/dvb/pluto2/pluto2.c | |||
| @@ -242,7 +242,7 @@ static int __devinit pluto_dma_map(struct pluto *pluto) | |||
| 242 | pluto->dma_addr = pci_map_single(pluto->pdev, pluto->dma_buf, | 242 | pluto->dma_addr = pci_map_single(pluto->pdev, pluto->dma_buf, |
| 243 | TS_DMA_BYTES, PCI_DMA_FROMDEVICE); | 243 | TS_DMA_BYTES, PCI_DMA_FROMDEVICE); |
| 244 | 244 | ||
| 245 | return pci_dma_mapping_error(pluto->dma_addr); | 245 | return pci_dma_mapping_error(pluto->pdev, pluto->dma_addr); |
| 246 | } | 246 | } |
| 247 | 247 | ||
| 248 | static void pluto_dma_unmap(struct pluto *pluto) | 248 | static void pluto_dma_unmap(struct pluto *pluto) |
diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c index 61b98c333cb0..a38005008a20 100644 --- a/drivers/memstick/core/memstick.c +++ b/drivers/memstick/core/memstick.c | |||
| @@ -249,8 +249,11 @@ EXPORT_SYMBOL(memstick_next_req); | |||
| 249 | */ | 249 | */ |
| 250 | void memstick_new_req(struct memstick_host *host) | 250 | void memstick_new_req(struct memstick_host *host) |
| 251 | { | 251 | { |
| 252 | host->retries = cmd_retries; | 252 | if (host->card) { |
| 253 | host->request(host); | 253 | host->retries = cmd_retries; |
| 254 | INIT_COMPLETION(host->card->mrq_complete); | ||
| 255 | host->request(host); | ||
| 256 | } | ||
| 254 | } | 257 | } |
| 255 | EXPORT_SYMBOL(memstick_new_req); | 258 | EXPORT_SYMBOL(memstick_new_req); |
| 256 | 259 | ||
| @@ -415,10 +418,14 @@ err_out: | |||
| 415 | return NULL; | 418 | return NULL; |
| 416 | } | 419 | } |
| 417 | 420 | ||
| 418 | static void memstick_power_on(struct memstick_host *host) | 421 | static int memstick_power_on(struct memstick_host *host) |
| 419 | { | 422 | { |
| 420 | host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON); | 423 | int rc = host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON); |
| 421 | host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL); | 424 | |
| 425 | if (!rc) | ||
| 426 | rc = host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL); | ||
| 427 | |||
| 428 | return rc; | ||
| 422 | } | 429 | } |
| 423 | 430 | ||
| 424 | static void memstick_check(struct work_struct *work) | 431 | static void memstick_check(struct work_struct *work) |
| @@ -429,8 +436,11 @@ static void memstick_check(struct work_struct *work) | |||
| 429 | 436 | ||
| 430 | dev_dbg(&host->dev, "memstick_check started\n"); | 437 | dev_dbg(&host->dev, "memstick_check started\n"); |
| 431 | mutex_lock(&host->lock); | 438 | mutex_lock(&host->lock); |
| 432 | if (!host->card) | 439 | if (!host->card) { |
| 433 | memstick_power_on(host); | 440 | if (memstick_power_on(host)) |
| 441 | goto out_power_off; | ||
| 442 | } else | ||
| 443 | host->card->stop(host->card); | ||
| 434 | 444 | ||
| 435 | card = memstick_alloc_card(host); | 445 | card = memstick_alloc_card(host); |
| 436 | 446 | ||
| @@ -448,7 +458,8 @@ static void memstick_check(struct work_struct *work) | |||
| 448 | || !(host->card->check(host->card))) { | 458 | || !(host->card->check(host->card))) { |
| 449 | device_unregister(&host->card->dev); | 459 | device_unregister(&host->card->dev); |
| 450 | host->card = NULL; | 460 | host->card = NULL; |
| 451 | } | 461 | } else |
| 462 | host->card->start(host->card); | ||
| 452 | } | 463 | } |
| 453 | 464 | ||
| 454 | if (!host->card) { | 465 | if (!host->card) { |
| @@ -461,6 +472,7 @@ static void memstick_check(struct work_struct *work) | |||
| 461 | kfree(card); | 472 | kfree(card); |
| 462 | } | 473 | } |
| 463 | 474 | ||
| 475 | out_power_off: | ||
| 464 | if (!host->card) | 476 | if (!host->card) |
| 465 | host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); | 477 | host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF); |
| 466 | 478 | ||
| @@ -573,11 +585,15 @@ EXPORT_SYMBOL(memstick_suspend_host); | |||
| 573 | */ | 585 | */ |
| 574 | void memstick_resume_host(struct memstick_host *host) | 586 | void memstick_resume_host(struct memstick_host *host) |
| 575 | { | 587 | { |
| 588 | int rc = 0; | ||
| 589 | |||
| 576 | mutex_lock(&host->lock); | 590 | mutex_lock(&host->lock); |
| 577 | if (host->card) | 591 | if (host->card) |
| 578 | memstick_power_on(host); | 592 | rc = memstick_power_on(host); |
| 579 | mutex_unlock(&host->lock); | 593 | mutex_unlock(&host->lock); |
| 580 | memstick_detect_change(host); | 594 | |
| 595 | if (!rc) | ||
| 596 | memstick_detect_change(host); | ||
| 581 | } | 597 | } |
| 582 | EXPORT_SYMBOL(memstick_resume_host); | 598 | EXPORT_SYMBOL(memstick_resume_host); |
| 583 | 599 | ||
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index 477d0fb6e588..44b1817f2f2f 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c | |||
| @@ -136,9 +136,8 @@ struct mspro_block_data { | |||
| 136 | unsigned int caps; | 136 | unsigned int caps; |
| 137 | struct gendisk *disk; | 137 | struct gendisk *disk; |
| 138 | struct request_queue *queue; | 138 | struct request_queue *queue; |
| 139 | struct request *block_req; | ||
| 139 | spinlock_t q_lock; | 140 | spinlock_t q_lock; |
| 140 | wait_queue_head_t q_wait; | ||
| 141 | struct task_struct *q_thread; | ||
| 142 | 141 | ||
| 143 | unsigned short page_size; | 142 | unsigned short page_size; |
| 144 | unsigned short cylinders; | 143 | unsigned short cylinders; |
| @@ -147,9 +146,10 @@ struct mspro_block_data { | |||
| 147 | 146 | ||
| 148 | unsigned char system; | 147 | unsigned char system; |
| 149 | unsigned char read_only:1, | 148 | unsigned char read_only:1, |
| 150 | active:1, | 149 | eject:1, |
| 151 | has_request:1, | 150 | has_request:1, |
| 152 | data_dir:1; | 151 | data_dir:1, |
| 152 | active:1; | ||
| 153 | unsigned char transfer_cmd; | 153 | unsigned char transfer_cmd; |
| 154 | 154 | ||
| 155 | int (*mrq_handler)(struct memstick_dev *card, | 155 | int (*mrq_handler)(struct memstick_dev *card, |
| @@ -160,12 +160,14 @@ struct mspro_block_data { | |||
| 160 | struct scatterlist req_sg[MSPRO_BLOCK_MAX_SEGS]; | 160 | struct scatterlist req_sg[MSPRO_BLOCK_MAX_SEGS]; |
| 161 | unsigned int seg_count; | 161 | unsigned int seg_count; |
| 162 | unsigned int current_seg; | 162 | unsigned int current_seg; |
| 163 | unsigned short current_page; | 163 | unsigned int current_page; |
| 164 | }; | 164 | }; |
| 165 | 165 | ||
| 166 | static DEFINE_IDR(mspro_block_disk_idr); | 166 | static DEFINE_IDR(mspro_block_disk_idr); |
| 167 | static DEFINE_MUTEX(mspro_block_disk_lock); | 167 | static DEFINE_MUTEX(mspro_block_disk_lock); |
| 168 | 168 | ||
| 169 | static int mspro_block_complete_req(struct memstick_dev *card, int error); | ||
| 170 | |||
| 169 | /*** Block device ***/ | 171 | /*** Block device ***/ |
| 170 | 172 | ||
| 171 | static int mspro_block_bd_open(struct inode *inode, struct file *filp) | 173 | static int mspro_block_bd_open(struct inode *inode, struct file *filp) |
| @@ -197,8 +199,10 @@ static int mspro_block_disk_release(struct gendisk *disk) | |||
| 197 | 199 | ||
| 198 | mutex_lock(&mspro_block_disk_lock); | 200 | mutex_lock(&mspro_block_disk_lock); |
| 199 | 201 | ||
| 200 | if (msb->usage_count) { | 202 | if (msb) { |
| 201 | msb->usage_count--; | 203 | if (msb->usage_count) |
| 204 | msb->usage_count--; | ||
| 205 | |||
| 202 | if (!msb->usage_count) { | 206 | if (!msb->usage_count) { |
| 203 | kfree(msb); | 207 | kfree(msb); |
| 204 | disk->private_data = NULL; | 208 | disk->private_data = NULL; |
| @@ -523,11 +527,13 @@ static int h_mspro_block_req_init(struct memstick_dev *card, | |||
| 523 | static int h_mspro_block_default(struct memstick_dev *card, | 527 | static int h_mspro_block_default(struct memstick_dev *card, |
| 524 | struct memstick_request **mrq) | 528 | struct memstick_request **mrq) |
| 525 | { | 529 | { |
| 526 | complete(&card->mrq_complete); | 530 | return mspro_block_complete_req(card, (*mrq)->error); |
| 527 | if (!(*mrq)->error) | 531 | } |
| 528 | return -EAGAIN; | 532 | |
| 529 | else | 533 | static int h_mspro_block_default_bad(struct memstick_dev *card, |
| 530 | return (*mrq)->error; | 534 | struct memstick_request **mrq) |
| 535 | { | ||
| 536 | return -ENXIO; | ||
| 531 | } | 537 | } |
| 532 | 538 | ||
| 533 | static int h_mspro_block_get_ro(struct memstick_dev *card, | 539 | static int h_mspro_block_get_ro(struct memstick_dev *card, |
| @@ -535,44 +541,30 @@ static int h_mspro_block_get_ro(struct memstick_dev *card, | |||
| 535 | { | 541 | { |
| 536 | struct mspro_block_data *msb = memstick_get_drvdata(card); | 542 | struct mspro_block_data *msb = memstick_get_drvdata(card); |
| 537 | 543 | ||
| 538 | if ((*mrq)->error) { | 544 | if (!(*mrq)->error) { |
| 539 | complete(&card->mrq_complete); | 545 | if ((*mrq)->data[offsetof(struct ms_status_register, status0)] |
| 540 | return (*mrq)->error; | 546 | & MEMSTICK_STATUS0_WP) |
| 547 | msb->read_only = 1; | ||
| 548 | else | ||
| 549 | msb->read_only = 0; | ||
| 541 | } | 550 | } |
| 542 | 551 | ||
| 543 | if ((*mrq)->data[offsetof(struct ms_status_register, status0)] | 552 | return mspro_block_complete_req(card, (*mrq)->error); |
| 544 | & MEMSTICK_STATUS0_WP) | ||
| 545 | msb->read_only = 1; | ||
| 546 | else | ||
| 547 | msb->read_only = 0; | ||
| 548 | |||
| 549 | complete(&card->mrq_complete); | ||
| 550 | return -EAGAIN; | ||
| 551 | } | 553 | } |
| 552 | 554 | ||
| 553 | static int h_mspro_block_wait_for_ced(struct memstick_dev *card, | 555 | static int h_mspro_block_wait_for_ced(struct memstick_dev *card, |
| 554 | struct memstick_request **mrq) | 556 | struct memstick_request **mrq) |
| 555 | { | 557 | { |
| 556 | if ((*mrq)->error) { | ||
| 557 | complete(&card->mrq_complete); | ||
| 558 | return (*mrq)->error; | ||
| 559 | } | ||
| 560 | |||
| 561 | dev_dbg(&card->dev, "wait for ced: value %x\n", (*mrq)->data[0]); | 558 | dev_dbg(&card->dev, "wait for ced: value %x\n", (*mrq)->data[0]); |
| 562 | 559 | ||
| 563 | if ((*mrq)->data[0] & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR)) { | 560 | if (!(*mrq)->error) { |
| 564 | card->current_mrq.error = -EFAULT; | 561 | if ((*mrq)->data[0] & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR)) |
| 565 | complete(&card->mrq_complete); | 562 | (*mrq)->error = -EFAULT; |
| 566 | return card->current_mrq.error; | 563 | else if (!((*mrq)->data[0] & MEMSTICK_INT_CED)) |
| 564 | return 0; | ||
| 567 | } | 565 | } |
| 568 | 566 | ||
| 569 | if (!((*mrq)->data[0] & MEMSTICK_INT_CED)) | 567 | return mspro_block_complete_req(card, (*mrq)->error); |
| 570 | return 0; | ||
| 571 | else { | ||
| 572 | card->current_mrq.error = 0; | ||
| 573 | complete(&card->mrq_complete); | ||
| 574 | return -EAGAIN; | ||
| 575 | } | ||
| 576 | } | 568 | } |
| 577 | 569 | ||
| 578 | static int h_mspro_block_transfer_data(struct memstick_dev *card, | 570 | static int h_mspro_block_transfer_data(struct memstick_dev *card, |
| @@ -583,10 +575,8 @@ static int h_mspro_block_transfer_data(struct memstick_dev *card, | |||
| 583 | struct scatterlist t_sg = { 0 }; | 575 | struct scatterlist t_sg = { 0 }; |
| 584 | size_t t_offset; | 576 | size_t t_offset; |
| 585 | 577 | ||
| 586 | if ((*mrq)->error) { | 578 | if ((*mrq)->error) |
| 587 | complete(&card->mrq_complete); | 579 | return mspro_block_complete_req(card, (*mrq)->error); |
| 588 | return (*mrq)->error; | ||
| 589 | } | ||
| 590 | 580 | ||
| 591 | switch ((*mrq)->tpc) { | 581 | switch ((*mrq)->tpc) { |
| 592 | case MS_TPC_WRITE_REG: | 582 | case MS_TPC_WRITE_REG: |
| @@ -617,8 +607,8 @@ has_int_reg: | |||
| 617 | 607 | ||
| 618 | if (msb->current_seg == msb->seg_count) { | 608 | if (msb->current_seg == msb->seg_count) { |
| 619 | if (t_val & MEMSTICK_INT_CED) { | 609 | if (t_val & MEMSTICK_INT_CED) { |
| 620 | complete(&card->mrq_complete); | 610 | return mspro_block_complete_req(card, |
| 621 | return -EAGAIN; | 611 | 0); |
| 622 | } else { | 612 | } else { |
| 623 | card->next_request | 613 | card->next_request |
| 624 | = h_mspro_block_wait_for_ced; | 614 | = h_mspro_block_wait_for_ced; |
| @@ -666,140 +656,184 @@ has_int_reg: | |||
| 666 | 656 | ||
| 667 | /*** Data transfer ***/ | 657 | /*** Data transfer ***/ |
| 668 | 658 | ||
| 669 | static void mspro_block_process_request(struct memstick_dev *card, | 659 | static int mspro_block_issue_req(struct memstick_dev *card, int chunk) |
| 670 | struct request *req) | ||
| 671 | { | 660 | { |
| 672 | struct mspro_block_data *msb = memstick_get_drvdata(card); | 661 | struct mspro_block_data *msb = memstick_get_drvdata(card); |
| 673 | struct mspro_param_register param; | ||
| 674 | int rc, chunk, cnt; | ||
| 675 | unsigned short page_count; | ||
| 676 | sector_t t_sec; | 662 | sector_t t_sec; |
| 677 | unsigned long flags; | 663 | unsigned int count; |
| 664 | struct mspro_param_register param; | ||
| 678 | 665 | ||
| 679 | do { | 666 | try_again: |
| 680 | page_count = 0; | 667 | while (chunk) { |
| 668 | msb->current_page = 0; | ||
| 681 | msb->current_seg = 0; | 669 | msb->current_seg = 0; |
| 682 | msb->seg_count = blk_rq_map_sg(req->q, req, msb->req_sg); | 670 | msb->seg_count = blk_rq_map_sg(msb->block_req->q, |
| 671 | msb->block_req, | ||
| 672 | msb->req_sg); | ||
| 683 | 673 | ||
| 684 | if (msb->seg_count) { | 674 | if (!msb->seg_count) { |
| 685 | msb->current_page = 0; | 675 | chunk = __blk_end_request(msb->block_req, -ENOMEM, |
| 686 | for (rc = 0; rc < msb->seg_count; rc++) | 676 | blk_rq_cur_bytes(msb->block_req)); |
| 687 | page_count += msb->req_sg[rc].length | 677 | continue; |
| 688 | / msb->page_size; | 678 | } |
| 689 | |||
| 690 | t_sec = req->sector; | ||
| 691 | sector_div(t_sec, msb->page_size >> 9); | ||
| 692 | param.system = msb->system; | ||
| 693 | param.data_count = cpu_to_be16(page_count); | ||
| 694 | param.data_address = cpu_to_be32((uint32_t)t_sec); | ||
| 695 | param.tpc_param = 0; | ||
| 696 | |||
| 697 | msb->data_dir = rq_data_dir(req); | ||
| 698 | msb->transfer_cmd = msb->data_dir == READ | ||
| 699 | ? MSPRO_CMD_READ_DATA | ||
| 700 | : MSPRO_CMD_WRITE_DATA; | ||
| 701 | |||
| 702 | dev_dbg(&card->dev, "data transfer: cmd %x, " | ||
| 703 | "lba %x, count %x\n", msb->transfer_cmd, | ||
| 704 | be32_to_cpu(param.data_address), | ||
| 705 | page_count); | ||
| 706 | |||
| 707 | card->next_request = h_mspro_block_req_init; | ||
| 708 | msb->mrq_handler = h_mspro_block_transfer_data; | ||
| 709 | memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, | ||
| 710 | ¶m, sizeof(param)); | ||
| 711 | memstick_new_req(card->host); | ||
| 712 | wait_for_completion(&card->mrq_complete); | ||
| 713 | rc = card->current_mrq.error; | ||
| 714 | 679 | ||
| 715 | if (rc || (card->current_mrq.tpc == MSPRO_CMD_STOP)) { | 680 | t_sec = msb->block_req->sector << 9; |
| 716 | for (cnt = 0; cnt < msb->current_seg; cnt++) | 681 | sector_div(t_sec, msb->page_size); |
| 717 | page_count += msb->req_sg[cnt].length | ||
| 718 | / msb->page_size; | ||
| 719 | |||
| 720 | if (msb->current_page) | ||
| 721 | page_count += msb->current_page - 1; | ||
| 722 | |||
| 723 | if (page_count && (msb->data_dir == READ)) | ||
| 724 | rc = msb->page_size * page_count; | ||
| 725 | else | ||
| 726 | rc = -EIO; | ||
| 727 | } else | ||
| 728 | rc = msb->page_size * page_count; | ||
| 729 | } else | ||
| 730 | rc = -EFAULT; | ||
| 731 | 682 | ||
| 732 | spin_lock_irqsave(&msb->q_lock, flags); | 683 | count = msb->block_req->nr_sectors << 9; |
| 733 | if (rc >= 0) | 684 | count /= msb->page_size; |
| 734 | chunk = __blk_end_request(req, 0, rc); | ||
| 735 | else | ||
| 736 | chunk = __blk_end_request(req, rc, 0); | ||
| 737 | 685 | ||
| 738 | dev_dbg(&card->dev, "end chunk %d, %d\n", rc, chunk); | 686 | param.system = msb->system; |
| 739 | spin_unlock_irqrestore(&msb->q_lock, flags); | 687 | param.data_count = cpu_to_be16(count); |
| 740 | } while (chunk); | 688 | param.data_address = cpu_to_be32((uint32_t)t_sec); |
| 689 | param.tpc_param = 0; | ||
| 690 | |||
| 691 | msb->data_dir = rq_data_dir(msb->block_req); | ||
| 692 | msb->transfer_cmd = msb->data_dir == READ | ||
| 693 | ? MSPRO_CMD_READ_DATA | ||
| 694 | : MSPRO_CMD_WRITE_DATA; | ||
| 695 | |||
| 696 | dev_dbg(&card->dev, "data transfer: cmd %x, " | ||
| 697 | "lba %x, count %x\n", msb->transfer_cmd, | ||
| 698 | be32_to_cpu(param.data_address), count); | ||
| 699 | |||
| 700 | card->next_request = h_mspro_block_req_init; | ||
| 701 | msb->mrq_handler = h_mspro_block_transfer_data; | ||
| 702 | memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, | ||
| 703 | ¶m, sizeof(param)); | ||
| 704 | memstick_new_req(card->host); | ||
| 705 | return 0; | ||
| 706 | } | ||
| 707 | |||
| 708 | dev_dbg(&card->dev, "elv_next\n"); | ||
| 709 | msb->block_req = elv_next_request(msb->queue); | ||
| 710 | if (!msb->block_req) { | ||
| 711 | dev_dbg(&card->dev, "issue end\n"); | ||
| 712 | return -EAGAIN; | ||
| 713 | } | ||
| 714 | |||
| 715 | dev_dbg(&card->dev, "trying again\n"); | ||
| 716 | chunk = 1; | ||
| 717 | goto try_again; | ||
| 741 | } | 718 | } |
| 742 | 719 | ||
| 743 | static int mspro_block_has_request(struct mspro_block_data *msb) | 720 | static int mspro_block_complete_req(struct memstick_dev *card, int error) |
| 744 | { | 721 | { |
| 745 | int rc = 0; | 722 | struct mspro_block_data *msb = memstick_get_drvdata(card); |
| 723 | int chunk, cnt; | ||
| 724 | unsigned int t_len = 0; | ||
| 746 | unsigned long flags; | 725 | unsigned long flags; |
| 747 | 726 | ||
| 748 | spin_lock_irqsave(&msb->q_lock, flags); | 727 | spin_lock_irqsave(&msb->q_lock, flags); |
| 749 | if (kthread_should_stop() || msb->has_request) | 728 | dev_dbg(&card->dev, "complete %d, %d\n", msb->has_request ? 1 : 0, |
| 750 | rc = 1; | 729 | error); |
| 730 | |||
| 731 | if (msb->has_request) { | ||
| 732 | /* Nothing to do - not really an error */ | ||
| 733 | if (error == -EAGAIN) | ||
| 734 | error = 0; | ||
| 735 | |||
| 736 | if (error || (card->current_mrq.tpc == MSPRO_CMD_STOP)) { | ||
| 737 | if (msb->data_dir == READ) { | ||
| 738 | for (cnt = 0; cnt < msb->current_seg; cnt++) | ||
| 739 | t_len += msb->req_sg[cnt].length | ||
| 740 | / msb->page_size; | ||
| 741 | |||
| 742 | if (msb->current_page) | ||
| 743 | t_len += msb->current_page - 1; | ||
| 744 | |||
| 745 | t_len *= msb->page_size; | ||
| 746 | } | ||
| 747 | } else | ||
| 748 | t_len = msb->block_req->nr_sectors << 9; | ||
| 749 | |||
| 750 | dev_dbg(&card->dev, "transferred %x (%d)\n", t_len, error); | ||
| 751 | |||
| 752 | if (error && !t_len) | ||
| 753 | t_len = blk_rq_cur_bytes(msb->block_req); | ||
| 754 | |||
| 755 | chunk = __blk_end_request(msb->block_req, error, t_len); | ||
| 756 | |||
| 757 | error = mspro_block_issue_req(card, chunk); | ||
| 758 | |||
| 759 | if (!error) | ||
| 760 | goto out; | ||
| 761 | else | ||
| 762 | msb->has_request = 0; | ||
| 763 | } else { | ||
| 764 | if (!error) | ||
| 765 | error = -EAGAIN; | ||
| 766 | } | ||
| 767 | |||
| 768 | card->next_request = h_mspro_block_default_bad; | ||
| 769 | complete_all(&card->mrq_complete); | ||
| 770 | out: | ||
| 751 | spin_unlock_irqrestore(&msb->q_lock, flags); | 771 | spin_unlock_irqrestore(&msb->q_lock, flags); |
| 752 | return rc; | 772 | return error; |
| 753 | } | 773 | } |
| 754 | 774 | ||
| 755 | static int mspro_block_queue_thread(void *data) | 775 | static void mspro_block_stop(struct memstick_dev *card) |
| 756 | { | 776 | { |
| 757 | struct memstick_dev *card = data; | ||
| 758 | struct memstick_host *host = card->host; | ||
| 759 | struct mspro_block_data *msb = memstick_get_drvdata(card); | 777 | struct mspro_block_data *msb = memstick_get_drvdata(card); |
| 760 | struct request *req; | 778 | int rc = 0; |
| 761 | unsigned long flags; | 779 | unsigned long flags; |
| 762 | 780 | ||
| 763 | while (1) { | 781 | while (1) { |
| 764 | wait_event(msb->q_wait, mspro_block_has_request(msb)); | ||
| 765 | dev_dbg(&card->dev, "thread iter\n"); | ||
| 766 | |||
| 767 | spin_lock_irqsave(&msb->q_lock, flags); | 782 | spin_lock_irqsave(&msb->q_lock, flags); |
| 768 | req = elv_next_request(msb->queue); | 783 | if (!msb->has_request) { |
| 769 | dev_dbg(&card->dev, "next req %p\n", req); | 784 | blk_stop_queue(msb->queue); |
| 770 | if (!req) { | 785 | rc = 1; |
| 771 | msb->has_request = 0; | 786 | } |
| 772 | if (kthread_should_stop()) { | ||
| 773 | spin_unlock_irqrestore(&msb->q_lock, flags); | ||
| 774 | break; | ||
| 775 | } | ||
| 776 | } else | ||
| 777 | msb->has_request = 1; | ||
| 778 | spin_unlock_irqrestore(&msb->q_lock, flags); | 787 | spin_unlock_irqrestore(&msb->q_lock, flags); |
| 779 | 788 | ||
| 780 | if (req) { | 789 | if (rc) |
| 781 | mutex_lock(&host->lock); | 790 | break; |
| 782 | mspro_block_process_request(card, req); | 791 | |
| 783 | mutex_unlock(&host->lock); | 792 | wait_for_completion(&card->mrq_complete); |
| 784 | } | ||
| 785 | } | 793 | } |
| 786 | dev_dbg(&card->dev, "thread finished\n"); | ||
| 787 | return 0; | ||
| 788 | } | 794 | } |
| 789 | 795 | ||
| 790 | static void mspro_block_request(struct request_queue *q) | 796 | static void mspro_block_start(struct memstick_dev *card) |
| 797 | { | ||
| 798 | struct mspro_block_data *msb = memstick_get_drvdata(card); | ||
| 799 | unsigned long flags; | ||
| 800 | |||
| 801 | spin_lock_irqsave(&msb->q_lock, flags); | ||
| 802 | blk_start_queue(msb->queue); | ||
| 803 | spin_unlock_irqrestore(&msb->q_lock, flags); | ||
| 804 | } | ||
| 805 | |||
| 806 | static int mspro_block_prepare_req(struct request_queue *q, struct request *req) | ||
| 807 | { | ||
| 808 | if (!blk_fs_request(req) && !blk_pc_request(req)) { | ||
| 809 | blk_dump_rq_flags(req, "MSPro unsupported request"); | ||
| 810 | return BLKPREP_KILL; | ||
| 811 | } | ||
| 812 | |||
| 813 | req->cmd_flags |= REQ_DONTPREP; | ||
| 814 | |||
| 815 | return BLKPREP_OK; | ||
| 816 | } | ||
| 817 | |||
| 818 | static void mspro_block_submit_req(struct request_queue *q) | ||
| 791 | { | 819 | { |
| 792 | struct memstick_dev *card = q->queuedata; | 820 | struct memstick_dev *card = q->queuedata; |
| 793 | struct mspro_block_data *msb = memstick_get_drvdata(card); | 821 | struct mspro_block_data *msb = memstick_get_drvdata(card); |
| 794 | struct request *req = NULL; | 822 | struct request *req = NULL; |
| 795 | 823 | ||
| 796 | if (msb->q_thread) { | 824 | if (msb->has_request) |
| 797 | msb->has_request = 1; | 825 | return; |
| 798 | wake_up_all(&msb->q_wait); | 826 | |
| 799 | } else { | 827 | if (msb->eject) { |
| 800 | while ((req = elv_next_request(q)) != NULL) | 828 | while ((req = elv_next_request(q)) != NULL) |
| 801 | end_queued_request(req, -ENODEV); | 829 | end_queued_request(req, -ENODEV); |
| 830 | |||
| 831 | return; | ||
| 802 | } | 832 | } |
| 833 | |||
| 834 | msb->has_request = 1; | ||
| 835 | if (mspro_block_issue_req(card, 0)) | ||
| 836 | msb->has_request = 0; | ||
| 803 | } | 837 | } |
| 804 | 838 | ||
| 805 | /*** Initialization ***/ | 839 | /*** Initialization ***/ |
| @@ -1169,16 +1203,14 @@ static int mspro_block_init_disk(struct memstick_dev *card) | |||
| 1169 | goto out_release_id; | 1203 | goto out_release_id; |
| 1170 | } | 1204 | } |
| 1171 | 1205 | ||
| 1172 | spin_lock_init(&msb->q_lock); | 1206 | msb->queue = blk_init_queue(mspro_block_submit_req, &msb->q_lock); |
| 1173 | init_waitqueue_head(&msb->q_wait); | ||
| 1174 | |||
| 1175 | msb->queue = blk_init_queue(mspro_block_request, &msb->q_lock); | ||
| 1176 | if (!msb->queue) { | 1207 | if (!msb->queue) { |
| 1177 | rc = -ENOMEM; | 1208 | rc = -ENOMEM; |
| 1178 | goto out_put_disk; | 1209 | goto out_put_disk; |
| 1179 | } | 1210 | } |
| 1180 | 1211 | ||
| 1181 | msb->queue->queuedata = card; | 1212 | msb->queue->queuedata = card; |
| 1213 | blk_queue_prep_rq(msb->queue, mspro_block_prepare_req); | ||
| 1182 | 1214 | ||
| 1183 | blk_queue_bounce_limit(msb->queue, limit); | 1215 | blk_queue_bounce_limit(msb->queue, limit); |
| 1184 | blk_queue_max_sectors(msb->queue, MSPRO_BLOCK_MAX_PAGES); | 1216 | blk_queue_max_sectors(msb->queue, MSPRO_BLOCK_MAX_PAGES); |
| @@ -1204,14 +1236,8 @@ static int mspro_block_init_disk(struct memstick_dev *card) | |||
| 1204 | capacity *= msb->page_size >> 9; | 1236 | capacity *= msb->page_size >> 9; |
| 1205 | set_capacity(msb->disk, capacity); | 1237 | set_capacity(msb->disk, capacity); |
| 1206 | dev_dbg(&card->dev, "capacity set %ld\n", capacity); | 1238 | dev_dbg(&card->dev, "capacity set %ld\n", capacity); |
| 1207 | msb->q_thread = kthread_run(mspro_block_queue_thread, card, | ||
| 1208 | DRIVER_NAME"d"); | ||
| 1209 | if (IS_ERR(msb->q_thread)) | ||
| 1210 | goto out_put_disk; | ||
| 1211 | 1239 | ||
| 1212 | mutex_unlock(&host->lock); | ||
| 1213 | add_disk(msb->disk); | 1240 | add_disk(msb->disk); |
| 1214 | mutex_lock(&host->lock); | ||
| 1215 | msb->active = 1; | 1241 | msb->active = 1; |
| 1216 | return 0; | 1242 | return 0; |
| 1217 | 1243 | ||
| @@ -1259,6 +1285,7 @@ static int mspro_block_probe(struct memstick_dev *card) | |||
| 1259 | return -ENOMEM; | 1285 | return -ENOMEM; |
| 1260 | memstick_set_drvdata(card, msb); | 1286 | memstick_set_drvdata(card, msb); |
| 1261 | msb->card = card; | 1287 | msb->card = card; |
| 1288 | spin_lock_init(&msb->q_lock); | ||
| 1262 | 1289 | ||
| 1263 | rc = mspro_block_init_card(card); | 1290 | rc = mspro_block_init_card(card); |
| 1264 | 1291 | ||
| @@ -1272,6 +1299,8 @@ static int mspro_block_probe(struct memstick_dev *card) | |||
| 1272 | rc = mspro_block_init_disk(card); | 1299 | rc = mspro_block_init_disk(card); |
| 1273 | if (!rc) { | 1300 | if (!rc) { |
| 1274 | card->check = mspro_block_check_card; | 1301 | card->check = mspro_block_check_card; |
| 1302 | card->stop = mspro_block_stop; | ||
| 1303 | card->start = mspro_block_start; | ||
| 1275 | return 0; | 1304 | return 0; |
| 1276 | } | 1305 | } |
| 1277 | 1306 | ||
| @@ -1286,26 +1315,17 @@ out_free: | |||
| 1286 | static void mspro_block_remove(struct memstick_dev *card) | 1315 | static void mspro_block_remove(struct memstick_dev *card) |
| 1287 | { | 1316 | { |
| 1288 | struct mspro_block_data *msb = memstick_get_drvdata(card); | 1317 | struct mspro_block_data *msb = memstick_get_drvdata(card); |
| 1289 | struct task_struct *q_thread = NULL; | ||
| 1290 | unsigned long flags; | 1318 | unsigned long flags; |
| 1291 | 1319 | ||
| 1292 | del_gendisk(msb->disk); | 1320 | del_gendisk(msb->disk); |
| 1293 | dev_dbg(&card->dev, "mspro block remove\n"); | 1321 | dev_dbg(&card->dev, "mspro block remove\n"); |
| 1294 | spin_lock_irqsave(&msb->q_lock, flags); | 1322 | spin_lock_irqsave(&msb->q_lock, flags); |
| 1295 | q_thread = msb->q_thread; | 1323 | msb->eject = 1; |
| 1296 | msb->q_thread = NULL; | 1324 | blk_start_queue(msb->queue); |
| 1297 | msb->active = 0; | ||
| 1298 | spin_unlock_irqrestore(&msb->q_lock, flags); | 1325 | spin_unlock_irqrestore(&msb->q_lock, flags); |
| 1299 | 1326 | ||
| 1300 | if (q_thread) { | ||
| 1301 | mutex_unlock(&card->host->lock); | ||
| 1302 | kthread_stop(q_thread); | ||
| 1303 | mutex_lock(&card->host->lock); | ||
| 1304 | } | ||
| 1305 | |||
| 1306 | dev_dbg(&card->dev, "queue thread stopped\n"); | ||
| 1307 | |||
| 1308 | blk_cleanup_queue(msb->queue); | 1327 | blk_cleanup_queue(msb->queue); |
| 1328 | msb->queue = NULL; | ||
| 1309 | 1329 | ||
| 1310 | sysfs_remove_group(&card->dev.kobj, &msb->attr_group); | 1330 | sysfs_remove_group(&card->dev.kobj, &msb->attr_group); |
| 1311 | 1331 | ||
| @@ -1322,19 +1342,13 @@ static void mspro_block_remove(struct memstick_dev *card) | |||
| 1322 | static int mspro_block_suspend(struct memstick_dev *card, pm_message_t state) | 1342 | static int mspro_block_suspend(struct memstick_dev *card, pm_message_t state) |
| 1323 | { | 1343 | { |
| 1324 | struct mspro_block_data *msb = memstick_get_drvdata(card); | 1344 | struct mspro_block_data *msb = memstick_get_drvdata(card); |
| 1325 | struct task_struct *q_thread = NULL; | ||
| 1326 | unsigned long flags; | 1345 | unsigned long flags; |
| 1327 | 1346 | ||
| 1328 | spin_lock_irqsave(&msb->q_lock, flags); | 1347 | spin_lock_irqsave(&msb->q_lock, flags); |
| 1329 | q_thread = msb->q_thread; | ||
| 1330 | msb->q_thread = NULL; | ||
| 1331 | msb->active = 0; | ||
| 1332 | blk_stop_queue(msb->queue); | 1348 | blk_stop_queue(msb->queue); |
| 1349 | msb->active = 0; | ||
| 1333 | spin_unlock_irqrestore(&msb->q_lock, flags); | 1350 | spin_unlock_irqrestore(&msb->q_lock, flags); |
| 1334 | 1351 | ||
| 1335 | if (q_thread) | ||
| 1336 | kthread_stop(q_thread); | ||
| 1337 | |||
| 1338 | return 0; | 1352 | return 0; |
| 1339 | } | 1353 | } |
| 1340 | 1354 | ||
| @@ -1373,14 +1387,7 @@ static int mspro_block_resume(struct memstick_dev *card) | |||
| 1373 | if (memcmp(s_attr->data, r_attr->data, s_attr->size)) | 1387 | if (memcmp(s_attr->data, r_attr->data, s_attr->size)) |
| 1374 | break; | 1388 | break; |
| 1375 | 1389 | ||
| 1376 | memstick_set_drvdata(card, msb); | 1390 | msb->active = 1; |
| 1377 | msb->q_thread = kthread_run(mspro_block_queue_thread, | ||
| 1378 | card, DRIVER_NAME"d"); | ||
| 1379 | if (IS_ERR(msb->q_thread)) | ||
| 1380 | msb->q_thread = NULL; | ||
| 1381 | else | ||
| 1382 | msb->active = 1; | ||
| 1383 | |||
| 1384 | break; | 1391 | break; |
| 1385 | } | 1392 | } |
| 1386 | } | 1393 | } |
diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c index 4e3bfbcdf155..3485c63d20b0 100644 --- a/drivers/memstick/host/jmb38x_ms.c +++ b/drivers/memstick/host/jmb38x_ms.c | |||
| @@ -50,6 +50,7 @@ struct jmb38x_ms_host { | |||
| 50 | struct jmb38x_ms *chip; | 50 | struct jmb38x_ms *chip; |
| 51 | void __iomem *addr; | 51 | void __iomem *addr; |
| 52 | spinlock_t lock; | 52 | spinlock_t lock; |
| 53 | struct tasklet_struct notify; | ||
| 53 | int id; | 54 | int id; |
| 54 | char host_id[32]; | 55 | char host_id[32]; |
| 55 | int irq; | 56 | int irq; |
| @@ -590,55 +591,97 @@ static void jmb38x_ms_abort(unsigned long data) | |||
| 590 | spin_unlock_irqrestore(&host->lock, flags); | 591 | spin_unlock_irqrestore(&host->lock, flags); |
| 591 | } | 592 | } |
| 592 | 593 | ||
| 593 | static void jmb38x_ms_request(struct memstick_host *msh) | 594 | static void jmb38x_ms_req_tasklet(unsigned long data) |
| 594 | { | 595 | { |
| 596 | struct memstick_host *msh = (struct memstick_host *)data; | ||
| 595 | struct jmb38x_ms_host *host = memstick_priv(msh); | 597 | struct jmb38x_ms_host *host = memstick_priv(msh); |
| 596 | unsigned long flags; | 598 | unsigned long flags; |
| 597 | int rc; | 599 | int rc; |
| 598 | 600 | ||
| 599 | spin_lock_irqsave(&host->lock, flags); | 601 | spin_lock_irqsave(&host->lock, flags); |
| 600 | if (host->req) { | 602 | if (!host->req) { |
| 601 | spin_unlock_irqrestore(&host->lock, flags); | 603 | do { |
| 602 | BUG(); | 604 | rc = memstick_next_req(msh, &host->req); |
| 603 | return; | 605 | dev_dbg(&host->chip->pdev->dev, "tasklet req %d\n", rc); |
| 606 | } while (!rc && jmb38x_ms_issue_cmd(msh)); | ||
| 604 | } | 607 | } |
| 605 | |||
| 606 | do { | ||
| 607 | rc = memstick_next_req(msh, &host->req); | ||
| 608 | } while (!rc && jmb38x_ms_issue_cmd(msh)); | ||
| 609 | spin_unlock_irqrestore(&host->lock, flags); | 608 | spin_unlock_irqrestore(&host->lock, flags); |
| 610 | } | 609 | } |
| 611 | 610 | ||
| 612 | static void jmb38x_ms_reset(struct jmb38x_ms_host *host) | 611 | static void jmb38x_ms_dummy_submit(struct memstick_host *msh) |
| 613 | { | 612 | { |
| 614 | unsigned int host_ctl = readl(host->addr + HOST_CONTROL); | 613 | return; |
| 614 | } | ||
| 615 | |||
| 616 | static void jmb38x_ms_submit_req(struct memstick_host *msh) | ||
| 617 | { | ||
| 618 | struct jmb38x_ms_host *host = memstick_priv(msh); | ||
| 619 | |||
| 620 | tasklet_schedule(&host->notify); | ||
| 621 | } | ||
| 622 | |||
| 623 | static int jmb38x_ms_reset(struct jmb38x_ms_host *host) | ||
| 624 | { | ||
| 625 | int cnt; | ||
| 626 | |||
| 627 | writel(HOST_CONTROL_RESET_REQ | HOST_CONTROL_CLOCK_EN | ||
| 628 | | readl(host->addr + HOST_CONTROL), | ||
| 629 | host->addr + HOST_CONTROL); | ||
| 630 | mmiowb(); | ||
| 631 | |||
| 632 | for (cnt = 0; cnt < 20; ++cnt) { | ||
| 633 | if (!(HOST_CONTROL_RESET_REQ | ||
| 634 | & readl(host->addr + HOST_CONTROL))) | ||
| 635 | goto reset_next; | ||
| 615 | 636 | ||
| 616 | writel(HOST_CONTROL_RESET_REQ, host->addr + HOST_CONTROL); | 637 | ndelay(20); |
| 638 | } | ||
| 639 | dev_dbg(&host->chip->pdev->dev, "reset_req timeout\n"); | ||
| 640 | return -EIO; | ||
| 641 | |||
| 642 | reset_next: | ||
| 643 | writel(HOST_CONTROL_RESET | HOST_CONTROL_CLOCK_EN | ||
| 644 | | readl(host->addr + HOST_CONTROL), | ||
| 645 | host->addr + HOST_CONTROL); | ||
| 646 | mmiowb(); | ||
| 647 | |||
| 648 | for (cnt = 0; cnt < 20; ++cnt) { | ||
| 649 | if (!(HOST_CONTROL_RESET | ||
| 650 | & readl(host->addr + HOST_CONTROL))) | ||
| 651 | goto reset_ok; | ||
| 617 | 652 | ||
| 618 | while (HOST_CONTROL_RESET_REQ | ||
| 619 | & (host_ctl = readl(host->addr + HOST_CONTROL))) { | ||
| 620 | ndelay(20); | 653 | ndelay(20); |
| 621 | dev_dbg(&host->chip->pdev->dev, "reset %08x\n", host_ctl); | ||
| 622 | } | 654 | } |
| 655 | dev_dbg(&host->chip->pdev->dev, "reset timeout\n"); | ||
| 656 | return -EIO; | ||
| 623 | 657 | ||
| 624 | writel(HOST_CONTROL_RESET, host->addr + HOST_CONTROL); | 658 | reset_ok: |
| 625 | mmiowb(); | 659 | mmiowb(); |
| 626 | writel(INT_STATUS_ALL, host->addr + INT_SIGNAL_ENABLE); | 660 | writel(INT_STATUS_ALL, host->addr + INT_SIGNAL_ENABLE); |
| 627 | writel(INT_STATUS_ALL, host->addr + INT_STATUS_ENABLE); | 661 | writel(INT_STATUS_ALL, host->addr + INT_STATUS_ENABLE); |
| 662 | return 0; | ||
| 628 | } | 663 | } |
| 629 | 664 | ||
| 630 | static void jmb38x_ms_set_param(struct memstick_host *msh, | 665 | static int jmb38x_ms_set_param(struct memstick_host *msh, |
| 631 | enum memstick_param param, | 666 | enum memstick_param param, |
| 632 | int value) | 667 | int value) |
| 633 | { | 668 | { |
| 634 | struct jmb38x_ms_host *host = memstick_priv(msh); | 669 | struct jmb38x_ms_host *host = memstick_priv(msh); |
| 635 | unsigned int host_ctl = readl(host->addr + HOST_CONTROL); | 670 | unsigned int host_ctl = readl(host->addr + HOST_CONTROL); |
| 636 | unsigned int clock_ctl = CLOCK_CONTROL_40MHZ, clock_delay = 0; | 671 | unsigned int clock_ctl = CLOCK_CONTROL_40MHZ, clock_delay = 0; |
| 672 | int rc = 0; | ||
| 637 | 673 | ||
| 638 | switch (param) { | 674 | switch (param) { |
| 639 | case MEMSTICK_POWER: | 675 | case MEMSTICK_POWER: |
| 640 | if (value == MEMSTICK_POWER_ON) { | 676 | if (value == MEMSTICK_POWER_ON) { |
| 641 | jmb38x_ms_reset(host); | 677 | rc = jmb38x_ms_reset(host); |
| 678 | if (rc) | ||
| 679 | return rc; | ||
| 680 | |||
| 681 | host_ctl = 7; | ||
| 682 | host_ctl |= HOST_CONTROL_POWER_EN | ||
| 683 | | HOST_CONTROL_CLOCK_EN; | ||
| 684 | writel(host_ctl, host->addr + HOST_CONTROL); | ||
| 642 | 685 | ||
| 643 | writel(host->id ? PAD_PU_PD_ON_MS_SOCK1 | 686 | writel(host->id ? PAD_PU_PD_ON_MS_SOCK1 |
| 644 | : PAD_PU_PD_ON_MS_SOCK0, | 687 | : PAD_PU_PD_ON_MS_SOCK0, |
| @@ -647,11 +690,7 @@ static void jmb38x_ms_set_param(struct memstick_host *msh, | |||
| 647 | writel(PAD_OUTPUT_ENABLE_MS, | 690 | writel(PAD_OUTPUT_ENABLE_MS, |
| 648 | host->addr + PAD_OUTPUT_ENABLE); | 691 | host->addr + PAD_OUTPUT_ENABLE); |
| 649 | 692 | ||
| 650 | host_ctl = 7; | 693 | msleep(10); |
| 651 | host_ctl |= HOST_CONTROL_POWER_EN | ||
| 652 | | HOST_CONTROL_CLOCK_EN; | ||
| 653 | writel(host_ctl, host->addr + HOST_CONTROL); | ||
| 654 | |||
| 655 | dev_dbg(&host->chip->pdev->dev, "power on\n"); | 694 | dev_dbg(&host->chip->pdev->dev, "power on\n"); |
| 656 | } else if (value == MEMSTICK_POWER_OFF) { | 695 | } else if (value == MEMSTICK_POWER_OFF) { |
| 657 | host_ctl &= ~(HOST_CONTROL_POWER_EN | 696 | host_ctl &= ~(HOST_CONTROL_POWER_EN |
| @@ -660,7 +699,8 @@ static void jmb38x_ms_set_param(struct memstick_host *msh, | |||
| 660 | writel(0, host->addr + PAD_OUTPUT_ENABLE); | 699 | writel(0, host->addr + PAD_OUTPUT_ENABLE); |
| 661 | writel(PAD_PU_PD_OFF, host->addr + PAD_PU_PD); | 700 | writel(PAD_PU_PD_OFF, host->addr + PAD_PU_PD); |
| 662 | dev_dbg(&host->chip->pdev->dev, "power off\n"); | 701 | dev_dbg(&host->chip->pdev->dev, "power off\n"); |
| 663 | } | 702 | } else |
| 703 | return -EINVAL; | ||
| 664 | break; | 704 | break; |
| 665 | case MEMSTICK_INTERFACE: | 705 | case MEMSTICK_INTERFACE: |
| 666 | host_ctl &= ~(3 << HOST_CONTROL_IF_SHIFT); | 706 | host_ctl &= ~(3 << HOST_CONTROL_IF_SHIFT); |
| @@ -686,12 +726,14 @@ static void jmb38x_ms_set_param(struct memstick_host *msh, | |||
| 686 | host_ctl &= ~HOST_CONTROL_REI; | 726 | host_ctl &= ~HOST_CONTROL_REI; |
| 687 | clock_ctl = CLOCK_CONTROL_60MHZ; | 727 | clock_ctl = CLOCK_CONTROL_60MHZ; |
| 688 | clock_delay = 0; | 728 | clock_delay = 0; |
| 689 | } | 729 | } else |
| 730 | return -EINVAL; | ||
| 690 | writel(host_ctl, host->addr + HOST_CONTROL); | 731 | writel(host_ctl, host->addr + HOST_CONTROL); |
| 691 | writel(clock_ctl, host->addr + CLOCK_CONTROL); | 732 | writel(clock_ctl, host->addr + CLOCK_CONTROL); |
| 692 | writel(clock_delay, host->addr + CLOCK_DELAY); | 733 | writel(clock_delay, host->addr + CLOCK_DELAY); |
| 693 | break; | 734 | break; |
| 694 | }; | 735 | }; |
| 736 | return 0; | ||
| 695 | } | 737 | } |
| 696 | 738 | ||
| 697 | #ifdef CONFIG_PM | 739 | #ifdef CONFIG_PM |
| @@ -785,7 +827,9 @@ static struct memstick_host *jmb38x_ms_alloc_host(struct jmb38x_ms *jm, int cnt) | |||
| 785 | host->id); | 827 | host->id); |
| 786 | host->irq = jm->pdev->irq; | 828 | host->irq = jm->pdev->irq; |
| 787 | host->timeout_jiffies = msecs_to_jiffies(1000); | 829 | host->timeout_jiffies = msecs_to_jiffies(1000); |
| 788 | msh->request = jmb38x_ms_request; | 830 | |
| 831 | tasklet_init(&host->notify, jmb38x_ms_req_tasklet, (unsigned long)msh); | ||
| 832 | msh->request = jmb38x_ms_submit_req; | ||
| 789 | msh->set_param = jmb38x_ms_set_param; | 833 | msh->set_param = jmb38x_ms_set_param; |
| 790 | 834 | ||
| 791 | msh->caps = MEMSTICK_CAP_PAR4 | MEMSTICK_CAP_PAR8; | 835 | msh->caps = MEMSTICK_CAP_PAR4 | MEMSTICK_CAP_PAR8; |
| @@ -897,6 +941,8 @@ static void jmb38x_ms_remove(struct pci_dev *dev) | |||
| 897 | 941 | ||
| 898 | host = memstick_priv(jm->hosts[cnt]); | 942 | host = memstick_priv(jm->hosts[cnt]); |
| 899 | 943 | ||
| 944 | jm->hosts[cnt]->request = jmb38x_ms_dummy_submit; | ||
| 945 | tasklet_kill(&host->notify); | ||
| 900 | writel(0, host->addr + INT_SIGNAL_ENABLE); | 946 | writel(0, host->addr + INT_SIGNAL_ENABLE); |
| 901 | writel(0, host->addr + INT_STATUS_ENABLE); | 947 | writel(0, host->addr + INT_STATUS_ENABLE); |
| 902 | mmiowb(); | 948 | mmiowb(); |
diff --git a/drivers/memstick/host/tifm_ms.c b/drivers/memstick/host/tifm_ms.c index 8577de4ebb0e..d32d6ad8f3fc 100644 --- a/drivers/memstick/host/tifm_ms.c +++ b/drivers/memstick/host/tifm_ms.c | |||
| @@ -71,6 +71,7 @@ struct tifm_ms { | |||
| 71 | struct tifm_dev *dev; | 71 | struct tifm_dev *dev; |
| 72 | struct timer_list timer; | 72 | struct timer_list timer; |
| 73 | struct memstick_request *req; | 73 | struct memstick_request *req; |
| 74 | struct tasklet_struct notify; | ||
| 74 | unsigned int mode_mask; | 75 | unsigned int mode_mask; |
| 75 | unsigned int block_pos; | 76 | unsigned int block_pos; |
| 76 | unsigned long timeout_jiffies; | 77 | unsigned long timeout_jiffies; |
| @@ -455,49 +456,51 @@ static void tifm_ms_card_event(struct tifm_dev *sock) | |||
| 455 | return; | 456 | return; |
| 456 | } | 457 | } |
| 457 | 458 | ||
| 458 | static void tifm_ms_request(struct memstick_host *msh) | 459 | static void tifm_ms_req_tasklet(unsigned long data) |
| 459 | { | 460 | { |
| 461 | struct memstick_host *msh = (struct memstick_host *)data; | ||
| 460 | struct tifm_ms *host = memstick_priv(msh); | 462 | struct tifm_ms *host = memstick_priv(msh); |
| 461 | struct tifm_dev *sock = host->dev; | 463 | struct tifm_dev *sock = host->dev; |
| 462 | unsigned long flags; | 464 | unsigned long flags; |
| 463 | int rc; | 465 | int rc; |
| 464 | 466 | ||
| 465 | spin_lock_irqsave(&sock->lock, flags); | 467 | spin_lock_irqsave(&sock->lock, flags); |
| 466 | if (host->req) { | 468 | if (!host->req) { |
| 467 | printk(KERN_ERR "%s : unfinished request detected\n", | 469 | if (host->eject) { |
| 468 | sock->dev.bus_id); | 470 | do { |
| 469 | spin_unlock_irqrestore(&sock->lock, flags); | 471 | rc = memstick_next_req(msh, &host->req); |
| 470 | tifm_eject(host->dev); | 472 | if (!rc) |
| 471 | return; | 473 | host->req->error = -ETIME; |
| 472 | } | 474 | } while (!rc); |
| 475 | spin_unlock_irqrestore(&sock->lock, flags); | ||
| 476 | return; | ||
| 477 | } | ||
| 473 | 478 | ||
| 474 | if (host->eject) { | ||
| 475 | do { | 479 | do { |
| 476 | rc = memstick_next_req(msh, &host->req); | 480 | rc = memstick_next_req(msh, &host->req); |
| 477 | if (!rc) | 481 | } while (!rc && tifm_ms_issue_cmd(host)); |
| 478 | host->req->error = -ETIME; | ||
| 479 | } while (!rc); | ||
| 480 | spin_unlock_irqrestore(&sock->lock, flags); | ||
| 481 | return; | ||
| 482 | } | 482 | } |
| 483 | |||
| 484 | do { | ||
| 485 | rc = memstick_next_req(msh, &host->req); | ||
| 486 | } while (!rc && tifm_ms_issue_cmd(host)); | ||
| 487 | |||
| 488 | spin_unlock_irqrestore(&sock->lock, flags); | 483 | spin_unlock_irqrestore(&sock->lock, flags); |
| 484 | } | ||
| 485 | |||
| 486 | static void tifm_ms_dummy_submit(struct memstick_host *msh) | ||
| 487 | { | ||
| 489 | return; | 488 | return; |
| 490 | } | 489 | } |
| 491 | 490 | ||
| 492 | static void tifm_ms_set_param(struct memstick_host *msh, | 491 | static void tifm_ms_submit_req(struct memstick_host *msh) |
| 493 | enum memstick_param param, | ||
| 494 | int value) | ||
| 495 | { | 492 | { |
| 496 | struct tifm_ms *host = memstick_priv(msh); | 493 | struct tifm_ms *host = memstick_priv(msh); |
| 497 | struct tifm_dev *sock = host->dev; | ||
| 498 | unsigned long flags; | ||
| 499 | 494 | ||
| 500 | spin_lock_irqsave(&sock->lock, flags); | 495 | tasklet_schedule(&host->notify); |
| 496 | } | ||
| 497 | |||
| 498 | static int tifm_ms_set_param(struct memstick_host *msh, | ||
| 499 | enum memstick_param param, | ||
| 500 | int value) | ||
| 501 | { | ||
| 502 | struct tifm_ms *host = memstick_priv(msh); | ||
| 503 | struct tifm_dev *sock = host->dev; | ||
| 501 | 504 | ||
| 502 | switch (param) { | 505 | switch (param) { |
| 503 | case MEMSTICK_POWER: | 506 | case MEMSTICK_POWER: |
| @@ -512,7 +515,8 @@ static void tifm_ms_set_param(struct memstick_host *msh, | |||
| 512 | writel(TIFM_MS_SYS_FCLR | TIFM_MS_SYS_INTCLR, | 515 | writel(TIFM_MS_SYS_FCLR | TIFM_MS_SYS_INTCLR, |
| 513 | sock->addr + SOCK_MS_SYSTEM); | 516 | sock->addr + SOCK_MS_SYSTEM); |
| 514 | writel(0xffffffff, sock->addr + SOCK_MS_STATUS); | 517 | writel(0xffffffff, sock->addr + SOCK_MS_STATUS); |
| 515 | } | 518 | } else |
| 519 | return -EINVAL; | ||
| 516 | break; | 520 | break; |
| 517 | case MEMSTICK_INTERFACE: | 521 | case MEMSTICK_INTERFACE: |
| 518 | if (value == MEMSTICK_SERIAL) { | 522 | if (value == MEMSTICK_SERIAL) { |
| @@ -525,11 +529,12 @@ static void tifm_ms_set_param(struct memstick_host *msh, | |||
| 525 | writel(TIFM_CTRL_FAST_CLK | 529 | writel(TIFM_CTRL_FAST_CLK |
| 526 | | readl(sock->addr + SOCK_CONTROL), | 530 | | readl(sock->addr + SOCK_CONTROL), |
| 527 | sock->addr + SOCK_CONTROL); | 531 | sock->addr + SOCK_CONTROL); |
| 528 | } | 532 | } else |
| 533 | return -EINVAL; | ||
| 529 | break; | 534 | break; |
| 530 | }; | 535 | }; |
| 531 | 536 | ||
| 532 | spin_unlock_irqrestore(&sock->lock, flags); | 537 | return 0; |
| 533 | } | 538 | } |
| 534 | 539 | ||
| 535 | static void tifm_ms_abort(unsigned long data) | 540 | static void tifm_ms_abort(unsigned long data) |
| @@ -570,8 +575,9 @@ static int tifm_ms_probe(struct tifm_dev *sock) | |||
| 570 | host->timeout_jiffies = msecs_to_jiffies(1000); | 575 | host->timeout_jiffies = msecs_to_jiffies(1000); |
| 571 | 576 | ||
| 572 | setup_timer(&host->timer, tifm_ms_abort, (unsigned long)host); | 577 | setup_timer(&host->timer, tifm_ms_abort, (unsigned long)host); |
| 578 | tasklet_init(&host->notify, tifm_ms_req_tasklet, (unsigned long)msh); | ||
| 573 | 579 | ||
| 574 | msh->request = tifm_ms_request; | 580 | msh->request = tifm_ms_submit_req; |
| 575 | msh->set_param = tifm_ms_set_param; | 581 | msh->set_param = tifm_ms_set_param; |
| 576 | sock->card_event = tifm_ms_card_event; | 582 | sock->card_event = tifm_ms_card_event; |
| 577 | sock->data_event = tifm_ms_data_event; | 583 | sock->data_event = tifm_ms_data_event; |
| @@ -593,6 +599,8 @@ static void tifm_ms_remove(struct tifm_dev *sock) | |||
| 593 | int rc = 0; | 599 | int rc = 0; |
| 594 | unsigned long flags; | 600 | unsigned long flags; |
| 595 | 601 | ||
| 602 | msh->request = tifm_ms_dummy_submit; | ||
| 603 | tasklet_kill(&host->notify); | ||
| 596 | spin_lock_irqsave(&sock->lock, flags); | 604 | spin_lock_irqsave(&sock->lock, flags); |
| 597 | host->eject = 1; | 605 | host->eject = 1; |
| 598 | if (host->req) { | 606 | if (host->req) { |
diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt index 241592ab13ad..3f15fcfe4a2e 100644 --- a/drivers/message/fusion/lsi/mpi_history.txt +++ b/drivers/message/fusion/lsi/mpi_history.txt | |||
| @@ -127,7 +127,7 @@ mpi_ioc.h | |||
| 127 | * 08-08-01 01.02.01 Original release for v1.2 work. | 127 | * 08-08-01 01.02.01 Original release for v1.2 work. |
| 128 | * New format for FWVersion and ProductId in | 128 | * New format for FWVersion and ProductId in |
| 129 | * MSG_IOC_FACTS_REPLY and MPI_FW_HEADER. | 129 | * MSG_IOC_FACTS_REPLY and MPI_FW_HEADER. |
| 130 | * 08-31-01 01.02.02 Addded event MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE and | 130 | * 08-31-01 01.02.02 Added event MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE and |
| 131 | * related structure and defines. | 131 | * related structure and defines. |
| 132 | * Added event MPI_EVENT_ON_BUS_TIMER_EXPIRED. | 132 | * Added event MPI_EVENT_ON_BUS_TIMER_EXPIRED. |
| 133 | * Added MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE. | 133 | * Added MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE. |
| @@ -187,7 +187,7 @@ mpi_ioc.h | |||
| 187 | * 10-11-06 01.05.12 Added MPI_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED. | 187 | * 10-11-06 01.05.12 Added MPI_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED. |
| 188 | * Added MaxInitiators field to PortFacts reply. | 188 | * Added MaxInitiators field to PortFacts reply. |
| 189 | * Added SAS Device Status Change ReasonCode for | 189 | * Added SAS Device Status Change ReasonCode for |
| 190 | * asynchronous notificaiton. | 190 | * asynchronous notification. |
| 191 | * Added MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE and event | 191 | * Added MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE and event |
| 192 | * data structure. | 192 | * data structure. |
| 193 | * Added new ImageType values for FWDownload and FWUpload | 193 | * Added new ImageType values for FWDownload and FWUpload |
| @@ -213,7 +213,7 @@ mpi_cnfg.h | |||
| 213 | * Added _RESPONSE_ID_MASK definition to SCSI_PORT_1 | 213 | * Added _RESPONSE_ID_MASK definition to SCSI_PORT_1 |
| 214 | * page and updated the page version. | 214 | * page and updated the page version. |
| 215 | * Added Information field and _INFO_PARAMS_NEGOTIATED | 215 | * Added Information field and _INFO_PARAMS_NEGOTIATED |
| 216 | * definitionto SCSI_DEVICE_0 page. | 216 | * definition to SCSI_DEVICE_0 page. |
| 217 | * 06-22-00 01.00.03 Removed batch controls from LAN_0 page and updated the | 217 | * 06-22-00 01.00.03 Removed batch controls from LAN_0 page and updated the |
| 218 | * page version. | 218 | * page version. |
| 219 | * Added BucketsRemaining to LAN_1 page, redefined the | 219 | * Added BucketsRemaining to LAN_1 page, redefined the |
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 34402c47027e..d6a0074b9dc3 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c | |||
| @@ -273,12 +273,12 @@ mpt_fault_reset_work(struct work_struct *work) | |||
| 273 | ioc_raw_state = mpt_GetIocState(ioc, 0); | 273 | ioc_raw_state = mpt_GetIocState(ioc, 0); |
| 274 | if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { | 274 | if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { |
| 275 | printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n", | 275 | printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n", |
| 276 | ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); | 276 | ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); |
| 277 | printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n", | 277 | printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n", |
| 278 | ioc->name, __FUNCTION__); | 278 | ioc->name, __func__); |
| 279 | rc = mpt_HardResetHandler(ioc, CAN_SLEEP); | 279 | rc = mpt_HardResetHandler(ioc, CAN_SLEEP); |
| 280 | printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name, | 280 | printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name, |
| 281 | __FUNCTION__, (rc == 0) ? "success" : "failed"); | 281 | __func__, (rc == 0) ? "success" : "failed"); |
| 282 | ioc_raw_state = mpt_GetIocState(ioc, 0); | 282 | ioc_raw_state = mpt_GetIocState(ioc, 0); |
| 283 | if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) | 283 | if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) |
| 284 | printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after " | 284 | printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after " |
| @@ -356,7 +356,7 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa) | |||
| 356 | if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || | 356 | if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || |
| 357 | MptCallbacks[cb_idx] == NULL) { | 357 | MptCallbacks[cb_idx] == NULL) { |
| 358 | printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", | 358 | printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", |
| 359 | __FUNCTION__, ioc->name, cb_idx); | 359 | __func__, ioc->name, cb_idx); |
| 360 | goto out; | 360 | goto out; |
| 361 | } | 361 | } |
| 362 | 362 | ||
| @@ -420,7 +420,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) | |||
| 420 | if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || | 420 | if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || |
| 421 | MptCallbacks[cb_idx] == NULL) { | 421 | MptCallbacks[cb_idx] == NULL) { |
| 422 | printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", | 422 | printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", |
| 423 | __FUNCTION__, ioc->name, cb_idx); | 423 | __func__, ioc->name, cb_idx); |
| 424 | freeme = 0; | 424 | freeme = 0; |
| 425 | goto out; | 425 | goto out; |
| 426 | } | 426 | } |
| @@ -2434,7 +2434,7 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) | |||
| 2434 | 2434 | ||
| 2435 | if (ioc->cached_fw != NULL) { | 2435 | if (ioc->cached_fw != NULL) { |
| 2436 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto " | 2436 | ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto " |
| 2437 | "adapter\n", __FUNCTION__, ioc->name)); | 2437 | "adapter\n", __func__, ioc->name)); |
| 2438 | if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *) | 2438 | if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *) |
| 2439 | ioc->cached_fw, CAN_SLEEP)) < 0) { | 2439 | ioc->cached_fw, CAN_SLEEP)) < 0) { |
| 2440 | printk(MYIOC_s_WARN_FMT | 2440 | printk(MYIOC_s_WARN_FMT |
| @@ -3693,7 +3693,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) | |||
| 3693 | 3693 | ||
| 3694 | if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) { | 3694 | if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) { |
| 3695 | drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset " | 3695 | drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset " |
| 3696 | "address=%p\n", ioc->name, __FUNCTION__, | 3696 | "address=%p\n", ioc->name, __func__, |
| 3697 | &ioc->chip->Doorbell, &ioc->chip->Reset_1078)); | 3697 | &ioc->chip->Doorbell, &ioc->chip->Reset_1078)); |
| 3698 | CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07); | 3698 | CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07); |
| 3699 | if (sleepFlag == CAN_SLEEP) | 3699 | if (sleepFlag == CAN_SLEEP) |
| @@ -4742,12 +4742,12 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode) | |||
| 4742 | break; | 4742 | break; |
| 4743 | } | 4743 | } |
| 4744 | 4744 | ||
| 4745 | printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode); | 4745 | printk("%s: persist_opcode=%x\n",__func__, persist_opcode); |
| 4746 | 4746 | ||
| 4747 | /* Get a MF for this command. | 4747 | /* Get a MF for this command. |
| 4748 | */ | 4748 | */ |
| 4749 | if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { | 4749 | if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { |
| 4750 | printk("%s: no msg frames!\n",__FUNCTION__); | 4750 | printk("%s: no msg frames!\n",__func__); |
| 4751 | return -1; | 4751 | return -1; |
| 4752 | } | 4752 | } |
| 4753 | 4753 | ||
| @@ -4771,13 +4771,13 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode) | |||
| 4771 | (SasIoUnitControlReply_t *)ioc->persist_reply_frame; | 4771 | (SasIoUnitControlReply_t *)ioc->persist_reply_frame; |
| 4772 | if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) { | 4772 | if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) { |
| 4773 | printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", | 4773 | printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", |
| 4774 | __FUNCTION__, | 4774 | __func__, |
| 4775 | sasIoUnitCntrReply->IOCStatus, | 4775 | sasIoUnitCntrReply->IOCStatus, |
| 4776 | sasIoUnitCntrReply->IOCLogInfo); | 4776 | sasIoUnitCntrReply->IOCLogInfo); |
| 4777 | return -1; | 4777 | return -1; |
| 4778 | } | 4778 | } |
| 4779 | 4779 | ||
| 4780 | printk("%s: success\n",__FUNCTION__); | 4780 | printk("%s: success\n",__func__); |
| 4781 | return 0; | 4781 | return 0; |
| 4782 | } | 4782 | } |
| 4783 | 4783 | ||
| @@ -5784,7 +5784,7 @@ SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp) | |||
| 5784 | 5784 | ||
| 5785 | if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { | 5785 | if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { |
| 5786 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n", | 5786 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n", |
| 5787 | ioc->name,__FUNCTION__)); | 5787 | ioc->name,__func__)); |
| 5788 | return -1; | 5788 | return -1; |
| 5789 | } | 5789 | } |
| 5790 | 5790 | ||
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index a5920423e2b2..f5233f3d9eff 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c | |||
| @@ -505,7 +505,7 @@ mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) | |||
| 505 | event = le32_to_cpu(pEvReply->Event) & 0xFF; | 505 | event = le32_to_cpu(pEvReply->Event) & 0xFF; |
| 506 | 506 | ||
| 507 | dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s() called\n", | 507 | dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s() called\n", |
| 508 | ioc->name, __FUNCTION__)); | 508 | ioc->name, __func__)); |
| 509 | if(async_queue == NULL) | 509 | if(async_queue == NULL) |
| 510 | return 1; | 510 | return 1; |
| 511 | 511 | ||
| @@ -2482,7 +2482,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) | |||
| 2482 | */ | 2482 | */ |
| 2483 | if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { | 2483 | if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { |
| 2484 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n", | 2484 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n", |
| 2485 | ioc->name,__FUNCTION__)); | 2485 | ioc->name,__func__)); |
| 2486 | goto out; | 2486 | goto out; |
| 2487 | } | 2487 | } |
| 2488 | 2488 | ||
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index b36cae9ec6db..c3c24fdf9fb6 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c | |||
| @@ -231,28 +231,28 @@ static int | |||
| 231 | mptfc_abort(struct scsi_cmnd *SCpnt) | 231 | mptfc_abort(struct scsi_cmnd *SCpnt) |
| 232 | { | 232 | { |
| 233 | return | 233 | return |
| 234 | mptfc_block_error_handler(SCpnt, mptscsih_abort, __FUNCTION__); | 234 | mptfc_block_error_handler(SCpnt, mptscsih_abort, __func__); |
| 235 | } | 235 | } |
| 236 | 236 | ||
| 237 | static int | 237 | static int |
| 238 | mptfc_dev_reset(struct scsi_cmnd *SCpnt) | 238 | mptfc_dev_reset(struct scsi_cmnd *SCpnt) |
| 239 | { | 239 | { |
| 240 | return | 240 | return |
| 241 | mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __FUNCTION__); | 241 | mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __func__); |
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | static int | 244 | static int |
| 245 | mptfc_bus_reset(struct scsi_cmnd *SCpnt) | 245 | mptfc_bus_reset(struct scsi_cmnd *SCpnt) |
| 246 | { | 246 | { |
| 247 | return | 247 | return |
| 248 | mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __FUNCTION__); | 248 | mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __func__); |
| 249 | } | 249 | } |
| 250 | 250 | ||
| 251 | static int | 251 | static int |
| 252 | mptfc_host_reset(struct scsi_cmnd *SCpnt) | 252 | mptfc_host_reset(struct scsi_cmnd *SCpnt) |
| 253 | { | 253 | { |
| 254 | return | 254 | return |
| 255 | mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __FUNCTION__); | 255 | mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __func__); |
| 256 | } | 256 | } |
| 257 | 257 | ||
| 258 | static void | 258 | static void |
diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index d709d92b7b30..a1abf95cf751 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c | |||
| @@ -610,7 +610,7 @@ mpt_lan_send_turbo(struct net_device *dev, u32 tmsg) | |||
| 610 | 610 | ||
| 611 | dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n", | 611 | dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n", |
| 612 | IOC_AND_NETDEV_NAMES_s_s(dev), | 612 | IOC_AND_NETDEV_NAMES_s_s(dev), |
| 613 | __FUNCTION__, sent)); | 613 | __func__, sent)); |
| 614 | 614 | ||
| 615 | priv->SendCtl[ctx].skb = NULL; | 615 | priv->SendCtl[ctx].skb = NULL; |
| 616 | pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma, | 616 | pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma, |
| @@ -676,7 +676,7 @@ mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep) | |||
| 676 | 676 | ||
| 677 | dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n", | 677 | dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n", |
| 678 | IOC_AND_NETDEV_NAMES_s_s(dev), | 678 | IOC_AND_NETDEV_NAMES_s_s(dev), |
| 679 | __FUNCTION__, sent)); | 679 | __func__, sent)); |
| 680 | 680 | ||
| 681 | priv->SendCtl[ctx].skb = NULL; | 681 | priv->SendCtl[ctx].skb = NULL; |
| 682 | pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma, | 682 | pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma, |
| @@ -715,7 +715,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) | |||
| 715 | u16 cur_naa = 0x1000; | 715 | u16 cur_naa = 0x1000; |
| 716 | 716 | ||
| 717 | dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n", | 717 | dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n", |
| 718 | __FUNCTION__, skb)); | 718 | __func__, skb)); |
| 719 | 719 | ||
| 720 | spin_lock_irqsave(&priv->txfidx_lock, flags); | 720 | spin_lock_irqsave(&priv->txfidx_lock, flags); |
| 721 | if (priv->mpt_txfidx_tail < 0) { | 721 | if (priv->mpt_txfidx_tail < 0) { |
| @@ -723,7 +723,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) | |||
| 723 | spin_unlock_irqrestore(&priv->txfidx_lock, flags); | 723 | spin_unlock_irqrestore(&priv->txfidx_lock, flags); |
| 724 | 724 | ||
| 725 | printk (KERN_ERR "%s: no tx context available: %u\n", | 725 | printk (KERN_ERR "%s: no tx context available: %u\n", |
| 726 | __FUNCTION__, priv->mpt_txfidx_tail); | 726 | __func__, priv->mpt_txfidx_tail); |
| 727 | return 1; | 727 | return 1; |
| 728 | } | 728 | } |
| 729 | 729 | ||
| @@ -733,7 +733,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) | |||
| 733 | spin_unlock_irqrestore(&priv->txfidx_lock, flags); | 733 | spin_unlock_irqrestore(&priv->txfidx_lock, flags); |
| 734 | 734 | ||
| 735 | printk (KERN_ERR "%s: Unable to alloc request frame\n", | 735 | printk (KERN_ERR "%s: Unable to alloc request frame\n", |
| 736 | __FUNCTION__); | 736 | __func__); |
| 737 | return 1; | 737 | return 1; |
| 738 | } | 738 | } |
| 739 | 739 | ||
| @@ -1208,7 +1208,7 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv) | |||
| 1208 | 1208 | ||
| 1209 | dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, Start_buckets = %u, buckets_out = %u\n", | 1209 | dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, Start_buckets = %u, buckets_out = %u\n", |
| 1210 | IOC_AND_NETDEV_NAMES_s_s(dev), | 1210 | IOC_AND_NETDEV_NAMES_s_s(dev), |
| 1211 | __FUNCTION__, buckets, curr)); | 1211 | __func__, buckets, curr)); |
| 1212 | 1212 | ||
| 1213 | max = (mpt_dev->req_sz - MPT_LAN_RECEIVE_POST_REQUEST_SIZE) / | 1213 | max = (mpt_dev->req_sz - MPT_LAN_RECEIVE_POST_REQUEST_SIZE) / |
| 1214 | (MPT_LAN_TRANSACTION32_SIZE + sizeof(SGESimple64_t)); | 1214 | (MPT_LAN_TRANSACTION32_SIZE + sizeof(SGESimple64_t)); |
| @@ -1217,9 +1217,9 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv) | |||
| 1217 | mf = mpt_get_msg_frame(LanCtx, mpt_dev); | 1217 | mf = mpt_get_msg_frame(LanCtx, mpt_dev); |
| 1218 | if (mf == NULL) { | 1218 | if (mf == NULL) { |
| 1219 | printk (KERN_ERR "%s: Unable to alloc request frame\n", | 1219 | printk (KERN_ERR "%s: Unable to alloc request frame\n", |
| 1220 | __FUNCTION__); | 1220 | __func__); |
| 1221 | dioprintk((KERN_ERR "%s: %u buckets remaining\n", | 1221 | dioprintk((KERN_ERR "%s: %u buckets remaining\n", |
| 1222 | __FUNCTION__, buckets)); | 1222 | __func__, buckets)); |
| 1223 | goto out; | 1223 | goto out; |
| 1224 | } | 1224 | } |
| 1225 | pRecvReq = (LANReceivePostRequest_t *) mf; | 1225 | pRecvReq = (LANReceivePostRequest_t *) mf; |
| @@ -1244,7 +1244,7 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv) | |||
| 1244 | spin_lock_irqsave(&priv->rxfidx_lock, flags); | 1244 | spin_lock_irqsave(&priv->rxfidx_lock, flags); |
| 1245 | if (priv->mpt_rxfidx_tail < 0) { | 1245 | if (priv->mpt_rxfidx_tail < 0) { |
| 1246 | printk (KERN_ERR "%s: Can't alloc context\n", | 1246 | printk (KERN_ERR "%s: Can't alloc context\n", |
| 1247 | __FUNCTION__); | 1247 | __func__); |
| 1248 | spin_unlock_irqrestore(&priv->rxfidx_lock, | 1248 | spin_unlock_irqrestore(&priv->rxfidx_lock, |
| 1249 | flags); | 1249 | flags); |
| 1250 | break; | 1250 | break; |
| @@ -1267,7 +1267,7 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv) | |||
| 1267 | if (skb == NULL) { | 1267 | if (skb == NULL) { |
| 1268 | printk (KERN_WARNING | 1268 | printk (KERN_WARNING |
| 1269 | MYNAM "/%s: Can't alloc skb\n", | 1269 | MYNAM "/%s: Can't alloc skb\n", |
| 1270 | __FUNCTION__); | 1270 | __func__); |
| 1271 | priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; | 1271 | priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; |
| 1272 | spin_unlock_irqrestore(&priv->rxfidx_lock, flags); | 1272 | spin_unlock_irqrestore(&priv->rxfidx_lock, flags); |
| 1273 | break; | 1273 | break; |
| @@ -1305,7 +1305,7 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv) | |||
| 1305 | 1305 | ||
| 1306 | if (pSimple == NULL) { | 1306 | if (pSimple == NULL) { |
| 1307 | /**/ printk (KERN_WARNING MYNAM "/%s: No buckets posted\n", | 1307 | /**/ printk (KERN_WARNING MYNAM "/%s: No buckets posted\n", |
| 1308 | /**/ __FUNCTION__); | 1308 | /**/ __func__); |
| 1309 | mpt_free_msg_frame(mpt_dev, mf); | 1309 | mpt_free_msg_frame(mpt_dev, mf); |
| 1310 | goto out; | 1310 | goto out; |
| 1311 | } | 1311 | } |
| @@ -1329,9 +1329,9 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv) | |||
| 1329 | 1329 | ||
| 1330 | out: | 1330 | out: |
| 1331 | dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n", | 1331 | dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n", |
| 1332 | __FUNCTION__, buckets, atomic_read(&priv->buckets_out))); | 1332 | __func__, buckets, atomic_read(&priv->buckets_out))); |
| 1333 | dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n", | 1333 | dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n", |
| 1334 | __FUNCTION__, priv->total_posted, priv->total_received)); | 1334 | __func__, priv->total_posted, priv->total_received)); |
| 1335 | 1335 | ||
| 1336 | clear_bit(0, &priv->post_buckets_active); | 1336 | clear_bit(0, &priv->post_buckets_active); |
| 1337 | } | 1337 | } |
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index b1147aa7afde..12b732512e57 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c | |||
| @@ -300,7 +300,7 @@ mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_detai | |||
| 300 | phy_info = port_info->phy_info; | 300 | phy_info = port_info->phy_info; |
| 301 | 301 | ||
| 302 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d " | 302 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d " |
| 303 | "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, port_details, | 303 | "bitmask=0x%016llX\n", ioc->name, __func__, port_details, |
| 304 | port_details->num_phys, (unsigned long long) | 304 | port_details->num_phys, (unsigned long long) |
| 305 | port_details->phy_bitmask)); | 305 | port_details->phy_bitmask)); |
| 306 | 306 | ||
| @@ -411,7 +411,7 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) | |||
| 411 | */ | 411 | */ |
| 412 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 412 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
| 413 | "%s: [%p]: deleting phy = %d\n", | 413 | "%s: [%p]: deleting phy = %d\n", |
| 414 | ioc->name, __FUNCTION__, port_details, i)); | 414 | ioc->name, __func__, port_details, i)); |
| 415 | port_details->num_phys--; | 415 | port_details->num_phys--; |
| 416 | port_details->phy_bitmask &= ~ (1 << phy_info->phy_id); | 416 | port_details->phy_bitmask &= ~ (1 << phy_info->phy_id); |
| 417 | memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); | 417 | memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); |
| @@ -497,7 +497,7 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) | |||
| 497 | continue; | 497 | continue; |
| 498 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT | 498 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
| 499 | "%s: [%p]: phy_id=%02d num_phys=%02d " | 499 | "%s: [%p]: phy_id=%02d num_phys=%02d " |
| 500 | "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, | 500 | "bitmask=0x%016llX\n", ioc->name, __func__, |
| 501 | port_details, i, port_details->num_phys, | 501 | port_details, i, port_details->num_phys, |
| 502 | (unsigned long long)port_details->phy_bitmask)); | 502 | (unsigned long long)port_details->phy_bitmask)); |
| 503 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n", | 503 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n", |
| @@ -553,7 +553,7 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id) | |||
| 553 | 553 | ||
| 554 | if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) { | 554 | if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) { |
| 555 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n", | 555 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n", |
| 556 | ioc->name,__FUNCTION__, __LINE__)); | 556 | ioc->name,__func__, __LINE__)); |
| 557 | return 0; | 557 | return 0; |
| 558 | } | 558 | } |
| 559 | 559 | ||
| @@ -606,7 +606,7 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc, | |||
| 606 | GFP_ATOMIC); | 606 | GFP_ATOMIC); |
| 607 | if (!target_reset_list) { | 607 | if (!target_reset_list) { |
| 608 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n", | 608 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n", |
| 609 | ioc->name,__FUNCTION__, __LINE__)); | 609 | ioc->name,__func__, __LINE__)); |
| 610 | return; | 610 | return; |
| 611 | } | 611 | } |
| 612 | 612 | ||
| @@ -673,7 +673,7 @@ mptsas_dev_reset_complete(MPT_ADAPTER *ioc) | |||
| 673 | ev = kzalloc(sizeof(*ev), GFP_ATOMIC); | 673 | ev = kzalloc(sizeof(*ev), GFP_ATOMIC); |
| 674 | if (!ev) { | 674 | if (!ev) { |
| 675 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n", | 675 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n", |
| 676 | ioc->name,__FUNCTION__, __LINE__)); | 676 | ioc->name,__func__, __LINE__)); |
| 677 | return; | 677 | return; |
| 678 | } | 678 | } |
| 679 | 679 | ||
| @@ -1183,7 +1183,7 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) | |||
| 1183 | reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply; | 1183 | reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply; |
| 1184 | if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) { | 1184 | if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) { |
| 1185 | printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", | 1185 | printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", |
| 1186 | ioc->name, __FUNCTION__, reply->IOCStatus, reply->IOCLogInfo); | 1186 | ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo); |
| 1187 | error = -ENXIO; | 1187 | error = -ENXIO; |
| 1188 | goto out_unlock; | 1188 | goto out_unlock; |
| 1189 | } | 1189 | } |
| @@ -1270,14 +1270,14 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
| 1270 | 1270 | ||
| 1271 | if (!rsp) { | 1271 | if (!rsp) { |
| 1272 | printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n", | 1272 | printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n", |
| 1273 | ioc->name, __FUNCTION__); | 1273 | ioc->name, __func__); |
| 1274 | return -EINVAL; | 1274 | return -EINVAL; |
| 1275 | } | 1275 | } |
| 1276 | 1276 | ||
| 1277 | /* do we need to support multiple segments? */ | 1277 | /* do we need to support multiple segments? */ |
| 1278 | if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { | 1278 | if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { |
| 1279 | printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n", | 1279 | printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n", |
| 1280 | ioc->name, __FUNCTION__, req->bio->bi_vcnt, req->data_len, | 1280 | ioc->name, __func__, req->bio->bi_vcnt, req->data_len, |
| 1281 | rsp->bio->bi_vcnt, rsp->data_len); | 1281 | rsp->bio->bi_vcnt, rsp->data_len); |
| 1282 | return -EINVAL; | 1282 | return -EINVAL; |
| 1283 | } | 1283 | } |
| @@ -1343,7 +1343,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
| 1343 | 1343 | ||
| 1344 | timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); | 1344 | timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); |
| 1345 | if (!timeleft) { | 1345 | if (!timeleft) { |
| 1346 | printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __FUNCTION__); | 1346 | printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__); |
| 1347 | /* On timeout reset the board */ | 1347 | /* On timeout reset the board */ |
| 1348 | mpt_HardResetHandler(ioc, CAN_SLEEP); | 1348 | mpt_HardResetHandler(ioc, CAN_SLEEP); |
| 1349 | ret = -ETIMEDOUT; | 1349 | ret = -ETIMEDOUT; |
| @@ -1361,7 +1361,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
| 1361 | rsp->data_len -= smprep->ResponseDataLength; | 1361 | rsp->data_len -= smprep->ResponseDataLength; |
| 1362 | } else { | 1362 | } else { |
| 1363 | printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n", | 1363 | printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n", |
| 1364 | ioc->name, __FUNCTION__); | 1364 | ioc->name, __func__); |
| 1365 | ret = -ENXIO; | 1365 | ret = -ENXIO; |
| 1366 | } | 1366 | } |
| 1367 | unmap: | 1367 | unmap: |
| @@ -2006,7 +2006,7 @@ static int mptsas_probe_one_phy(struct device *dev, | |||
| 2006 | if (error) { | 2006 | if (error) { |
| 2007 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 2007 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
| 2008 | "%s: exit at line=%d\n", ioc->name, | 2008 | "%s: exit at line=%d\n", ioc->name, |
| 2009 | __FUNCTION__, __LINE__)); | 2009 | __func__, __LINE__)); |
| 2010 | goto out; | 2010 | goto out; |
| 2011 | } | 2011 | } |
| 2012 | mptsas_set_port(ioc, phy_info, port); | 2012 | mptsas_set_port(ioc, phy_info, port); |
| @@ -2076,7 +2076,7 @@ static int mptsas_probe_one_phy(struct device *dev, | |||
| 2076 | if (!rphy) { | 2076 | if (!rphy) { |
| 2077 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 2077 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
| 2078 | "%s: exit at line=%d\n", ioc->name, | 2078 | "%s: exit at line=%d\n", ioc->name, |
| 2079 | __FUNCTION__, __LINE__)); | 2079 | __func__, __LINE__)); |
| 2080 | goto out; | 2080 | goto out; |
| 2081 | } | 2081 | } |
| 2082 | 2082 | ||
| @@ -2085,7 +2085,7 @@ static int mptsas_probe_one_phy(struct device *dev, | |||
| 2085 | if (error) { | 2085 | if (error) { |
| 2086 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 2086 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
| 2087 | "%s: exit at line=%d\n", ioc->name, | 2087 | "%s: exit at line=%d\n", ioc->name, |
| 2088 | __FUNCTION__, __LINE__)); | 2088 | __func__, __LINE__)); |
| 2089 | sas_rphy_free(rphy); | 2089 | sas_rphy_free(rphy); |
| 2090 | goto out; | 2090 | goto out; |
| 2091 | } | 2091 | } |
| @@ -2613,7 +2613,7 @@ mptsas_hotplug_work(struct work_struct *work) | |||
| 2613 | (ev->channel << 8) + ev->id)) { | 2613 | (ev->channel << 8) + ev->id)) { |
| 2614 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 2614 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
| 2615 | "%s: exit at line=%d\n", ioc->name, | 2615 | "%s: exit at line=%d\n", ioc->name, |
| 2616 | __FUNCTION__, __LINE__)); | 2616 | __func__, __LINE__)); |
| 2617 | break; | 2617 | break; |
| 2618 | } | 2618 | } |
| 2619 | phy_info = mptsas_find_phyinfo_by_sas_address( | 2619 | phy_info = mptsas_find_phyinfo_by_sas_address( |
| @@ -2633,20 +2633,20 @@ mptsas_hotplug_work(struct work_struct *work) | |||
| 2633 | if (!phy_info){ | 2633 | if (!phy_info){ |
| 2634 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 2634 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
| 2635 | "%s: exit at line=%d\n", ioc->name, | 2635 | "%s: exit at line=%d\n", ioc->name, |
| 2636 | __FUNCTION__, __LINE__)); | 2636 | __func__, __LINE__)); |
| 2637 | break; | 2637 | break; |
| 2638 | } | 2638 | } |
| 2639 | if (!phy_info->port_details) { | 2639 | if (!phy_info->port_details) { |
| 2640 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 2640 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
| 2641 | "%s: exit at line=%d\n", ioc->name, | 2641 | "%s: exit at line=%d\n", ioc->name, |
| 2642 | __FUNCTION__, __LINE__)); | 2642 | __func__, __LINE__)); |
| 2643 | break; | 2643 | break; |
| 2644 | } | 2644 | } |
| 2645 | rphy = mptsas_get_rphy(phy_info); | 2645 | rphy = mptsas_get_rphy(phy_info); |
| 2646 | if (!rphy) { | 2646 | if (!rphy) { |
| 2647 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 2647 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
| 2648 | "%s: exit at line=%d\n", ioc->name, | 2648 | "%s: exit at line=%d\n", ioc->name, |
| 2649 | __FUNCTION__, __LINE__)); | 2649 | __func__, __LINE__)); |
| 2650 | break; | 2650 | break; |
| 2651 | } | 2651 | } |
| 2652 | 2652 | ||
| @@ -2654,7 +2654,7 @@ mptsas_hotplug_work(struct work_struct *work) | |||
| 2654 | if (!port) { | 2654 | if (!port) { |
| 2655 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 2655 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
| 2656 | "%s: exit at line=%d\n", ioc->name, | 2656 | "%s: exit at line=%d\n", ioc->name, |
| 2657 | __FUNCTION__, __LINE__)); | 2657 | __func__, __LINE__)); |
| 2658 | break; | 2658 | break; |
| 2659 | } | 2659 | } |
| 2660 | 2660 | ||
| @@ -2665,7 +2665,7 @@ mptsas_hotplug_work(struct work_struct *work) | |||
| 2665 | if (!vtarget) { | 2665 | if (!vtarget) { |
| 2666 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 2666 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
| 2667 | "%s: exit at line=%d\n", ioc->name, | 2667 | "%s: exit at line=%d\n", ioc->name, |
| 2668 | __FUNCTION__, __LINE__)); | 2668 | __func__, __LINE__)); |
| 2669 | break; | 2669 | break; |
| 2670 | } | 2670 | } |
| 2671 | 2671 | ||
| @@ -2720,7 +2720,7 @@ mptsas_hotplug_work(struct work_struct *work) | |||
| 2720 | (ev->channel << 8) + ev->id)) { | 2720 | (ev->channel << 8) + ev->id)) { |
| 2721 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 2721 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
| 2722 | "%s: exit at line=%d\n", ioc->name, | 2722 | "%s: exit at line=%d\n", ioc->name, |
| 2723 | __FUNCTION__, __LINE__)); | 2723 | __func__, __LINE__)); |
| 2724 | break; | 2724 | break; |
| 2725 | } | 2725 | } |
| 2726 | 2726 | ||
| @@ -2732,7 +2732,7 @@ mptsas_hotplug_work(struct work_struct *work) | |||
| 2732 | if (!phy_info || !phy_info->port_details) { | 2732 | if (!phy_info || !phy_info->port_details) { |
| 2733 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 2733 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
| 2734 | "%s: exit at line=%d\n", ioc->name, | 2734 | "%s: exit at line=%d\n", ioc->name, |
| 2735 | __FUNCTION__, __LINE__)); | 2735 | __func__, __LINE__)); |
| 2736 | break; | 2736 | break; |
| 2737 | } | 2737 | } |
| 2738 | 2738 | ||
| @@ -2744,7 +2744,7 @@ mptsas_hotplug_work(struct work_struct *work) | |||
| 2744 | if (!vtarget) { | 2744 | if (!vtarget) { |
| 2745 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 2745 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
| 2746 | "%s: exit at line=%d\n", ioc->name, | 2746 | "%s: exit at line=%d\n", ioc->name, |
| 2747 | __FUNCTION__, __LINE__)); | 2747 | __func__, __LINE__)); |
| 2748 | break; | 2748 | break; |
| 2749 | } | 2749 | } |
| 2750 | /* | 2750 | /* |
| @@ -2767,7 +2767,7 @@ mptsas_hotplug_work(struct work_struct *work) | |||
| 2767 | if (mptsas_get_rphy(phy_info)) { | 2767 | if (mptsas_get_rphy(phy_info)) { |
| 2768 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 2768 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
| 2769 | "%s: exit at line=%d\n", ioc->name, | 2769 | "%s: exit at line=%d\n", ioc->name, |
| 2770 | __FUNCTION__, __LINE__)); | 2770 | __func__, __LINE__)); |
| 2771 | if (ev->channel) printk("%d\n", __LINE__); | 2771 | if (ev->channel) printk("%d\n", __LINE__); |
| 2772 | break; | 2772 | break; |
| 2773 | } | 2773 | } |
| @@ -2776,7 +2776,7 @@ mptsas_hotplug_work(struct work_struct *work) | |||
| 2776 | if (!port) { | 2776 | if (!port) { |
| 2777 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 2777 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
| 2778 | "%s: exit at line=%d\n", ioc->name, | 2778 | "%s: exit at line=%d\n", ioc->name, |
| 2779 | __FUNCTION__, __LINE__)); | 2779 | __func__, __LINE__)); |
| 2780 | break; | 2780 | break; |
| 2781 | } | 2781 | } |
| 2782 | memcpy(&phy_info->attached, &sas_device, | 2782 | memcpy(&phy_info->attached, &sas_device, |
| @@ -2801,7 +2801,7 @@ mptsas_hotplug_work(struct work_struct *work) | |||
| 2801 | if (!rphy) { | 2801 | if (!rphy) { |
| 2802 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 2802 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
| 2803 | "%s: exit at line=%d\n", ioc->name, | 2803 | "%s: exit at line=%d\n", ioc->name, |
| 2804 | __FUNCTION__, __LINE__)); | 2804 | __func__, __LINE__)); |
| 2805 | break; /* non-fatal: an rphy can be added later */ | 2805 | break; /* non-fatal: an rphy can be added later */ |
| 2806 | } | 2806 | } |
| 2807 | 2807 | ||
| @@ -2809,7 +2809,7 @@ mptsas_hotplug_work(struct work_struct *work) | |||
| 2809 | if (sas_rphy_add(rphy)) { | 2809 | if (sas_rphy_add(rphy)) { |
| 2810 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT | 2810 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
| 2811 | "%s: exit at line=%d\n", ioc->name, | 2811 | "%s: exit at line=%d\n", ioc->name, |
| 2812 | __FUNCTION__, __LINE__)); | 2812 | __func__, __LINE__)); |
| 2813 | sas_rphy_free(rphy); | 2813 | sas_rphy_free(rphy); |
| 2814 | break; | 2814 | break; |
| 2815 | } | 2815 | } |
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index d142b6b4b976..9f9354fd3516 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c | |||
| @@ -461,7 +461,7 @@ mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget, | |||
| 461 | 461 | ||
| 462 | if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { | 462 | if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { |
| 463 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n", | 463 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n", |
| 464 | ioc->name,__FUNCTION__)); | 464 | ioc->name,__func__)); |
| 465 | return; | 465 | return; |
| 466 | } | 466 | } |
| 467 | 467 | ||
| @@ -2187,7 +2187,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m | |||
| 2187 | (ioc->debug_level & MPT_DEBUG_TM )) | 2187 | (ioc->debug_level & MPT_DEBUG_TM )) |
| 2188 | printk("%s: ha=%d [%d:%d:0] task_type=0x%02X " | 2188 | printk("%s: ha=%d [%d:%d:0] task_type=0x%02X " |
| 2189 | "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X " | 2189 | "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X " |
| 2190 | "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus, | 2190 | "term_cmnds=%d\n", __func__, ioc->id, pScsiTmReply->Bus, |
| 2191 | pScsiTmReply->TargetID, pScsiTmReq->TaskType, | 2191 | pScsiTmReply->TargetID, pScsiTmReq->TaskType, |
| 2192 | le16_to_cpu(pScsiTmReply->IOCStatus), | 2192 | le16_to_cpu(pScsiTmReply->IOCStatus), |
| 2193 | le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode, | 2193 | le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode, |
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 3b870e7fb3e1..c6408a62d95e 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c | |||
| @@ -256,28 +256,28 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type) | |||
| 256 | bank + ASIC3_GPIO_TRIGGER_TYPE); | 256 | bank + ASIC3_GPIO_TRIGGER_TYPE); |
| 257 | asic->irq_bothedge[(irq - asic->irq_base) >> 4] &= ~bit; | 257 | asic->irq_bothedge[(irq - asic->irq_base) >> 4] &= ~bit; |
| 258 | 258 | ||
| 259 | if (type == IRQT_RISING) { | 259 | if (type == IRQ_TYPE_EDGE_RISING) { |
| 260 | trigger |= bit; | 260 | trigger |= bit; |
| 261 | edge |= bit; | 261 | edge |= bit; |
| 262 | } else if (type == IRQT_FALLING) { | 262 | } else if (type == IRQ_TYPE_EDGE_FALLING) { |
| 263 | trigger |= bit; | 263 | trigger |= bit; |
| 264 | edge &= ~bit; | 264 | edge &= ~bit; |
| 265 | } else if (type == IRQT_BOTHEDGE) { | 265 | } else if (type == IRQ_TYPE_EDGE_BOTH) { |
| 266 | trigger |= bit; | 266 | trigger |= bit; |
| 267 | if (asic3_gpio_get(&asic->gpio, irq - asic->irq_base)) | 267 | if (asic3_gpio_get(&asic->gpio, irq - asic->irq_base)) |
| 268 | edge &= ~bit; | 268 | edge &= ~bit; |
| 269 | else | 269 | else |
| 270 | edge |= bit; | 270 | edge |= bit; |
| 271 | asic->irq_bothedge[(irq - asic->irq_base) >> 4] |= bit; | 271 | asic->irq_bothedge[(irq - asic->irq_base) >> 4] |= bit; |
| 272 | } else if (type == IRQT_LOW) { | 272 | } else if (type == IRQ_TYPE_LEVEL_LOW) { |
| 273 | trigger &= ~bit; | 273 | trigger &= ~bit; |
| 274 | level &= ~bit; | 274 | level &= ~bit; |
| 275 | } else if (type == IRQT_HIGH) { | 275 | } else if (type == IRQ_TYPE_LEVEL_HIGH) { |
| 276 | trigger &= ~bit; | 276 | trigger &= ~bit; |
| 277 | level |= bit; | 277 | level |= bit; |
| 278 | } else { | 278 | } else { |
| 279 | /* | 279 | /* |
| 280 | * if type == IRQT_NOEDGE, we should mask interrupts, but | 280 | * if type == IRQ_TYPE_NONE, we should mask interrupts, but |
| 281 | * be careful to not unmask them if mask was also called. | 281 | * be careful to not unmask them if mask was also called. |
| 282 | * Probably need internal state for mask. | 282 | * Probably need internal state for mask. |
| 283 | */ | 283 | */ |
| @@ -314,10 +314,12 @@ static int __init asic3_irq_probe(struct platform_device *pdev) | |||
| 314 | unsigned long clksel = 0; | 314 | unsigned long clksel = 0; |
| 315 | unsigned int irq, irq_base; | 315 | unsigned int irq, irq_base; |
| 316 | int map_size; | 316 | int map_size; |
| 317 | int ret; | ||
| 317 | 318 | ||
| 318 | asic->irq_nr = platform_get_irq(pdev, 0); | 319 | ret = platform_get_irq(pdev, 0); |
| 319 | if (asic->irq_nr < 0) | 320 | if (ret < 0) |
| 320 | return asic->irq_nr; | 321 | return ret; |
| 322 | asic->irq_nr = ret; | ||
| 321 | 323 | ||
| 322 | /* turn on clock to IRQ controller */ | 324 | /* turn on clock to IRQ controller */ |
| 323 | clksel |= CLOCK_SEL_CX; | 325 | clksel |= CLOCK_SEL_CX; |
| @@ -341,7 +343,7 @@ static int __init asic3_irq_probe(struct platform_device *pdev) | |||
| 341 | ASIC3_INTMASK_GINTMASK); | 343 | ASIC3_INTMASK_GINTMASK); |
| 342 | 344 | ||
| 343 | set_irq_chained_handler(asic->irq_nr, asic3_irq_demux); | 345 | set_irq_chained_handler(asic->irq_nr, asic3_irq_demux); |
| 344 | set_irq_type(asic->irq_nr, IRQT_RISING); | 346 | set_irq_type(asic->irq_nr, IRQ_TYPE_EDGE_RISING); |
| 345 | set_irq_data(asic->irq_nr, asic); | 347 | set_irq_data(asic->irq_nr, asic); |
| 346 | 348 | ||
| 347 | return 0; | 349 | return 0; |
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 2d87501b6fd4..94e55e8e7ce6 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c | |||
| @@ -324,7 +324,7 @@ static void tc6393xb_attach_irq(struct platform_device *dev) | |||
| 324 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 324 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | set_irq_type(tc6393xb->irq, IRQT_FALLING); | 327 | set_irq_type(tc6393xb->irq, IRQ_TYPE_EDGE_FALLING); |
| 328 | set_irq_data(tc6393xb->irq, tc6393xb); | 328 | set_irq_data(tc6393xb->irq, tc6393xb); |
| 329 | set_irq_chained_handler(tc6393xb->irq, tc6393xb_irq); | 329 | set_irq_chained_handler(tc6393xb->irq, tc6393xb_irq); |
| 330 | } | 330 | } |
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 321eb9134635..f5ade1904aad 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
| @@ -360,7 +360,7 @@ config THINKPAD_ACPI_VIDEO | |||
| 360 | If you are not sure, say Y here. | 360 | If you are not sure, say Y here. |
| 361 | 361 | ||
| 362 | config THINKPAD_ACPI_HOTKEY_POLL | 362 | config THINKPAD_ACPI_HOTKEY_POLL |
| 363 | bool "Suport NVRAM polling for hot keys" | 363 | bool "Support NVRAM polling for hot keys" |
| 364 | depends on THINKPAD_ACPI | 364 | depends on THINKPAD_ACPI |
| 365 | default y | 365 | default y |
| 366 | ---help--- | 366 | ---help--- |
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index e171650766ce..bf5e4d065436 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c | |||
| @@ -13,7 +13,6 @@ | |||
| 13 | #include <linux/clk.h> | 13 | #include <linux/clk.h> |
| 14 | #include <linux/err.h> | 14 | #include <linux/err.h> |
| 15 | #include <linux/io.h> | 15 | #include <linux/io.h> |
| 16 | #include <linux/list.h> | ||
| 17 | #include <linux/spinlock.h> | 16 | #include <linux/spinlock.h> |
| 18 | #include <linux/atmel-ssc.h> | 17 | #include <linux/atmel-ssc.h> |
| 19 | 18 | ||
diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 19a1a254a0c5..889e5f898f6f 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile | |||
| @@ -12,3 +12,4 @@ mmc_core-y := core.o bus.o host.o \ | |||
| 12 | sdio.o sdio_ops.o sdio_bus.o \ | 12 | sdio.o sdio_ops.o sdio_bus.o \ |
| 13 | sdio_cis.o sdio_io.o sdio_irq.o | 13 | sdio_cis.o sdio_io.o sdio_irq.o |
| 14 | 14 | ||
| 15 | mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o | ||
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index fd95b18e988b..0d9b2d6f9ebf 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c | |||
| @@ -252,6 +252,10 @@ int mmc_add_card(struct mmc_card *card) | |||
| 252 | if (ret) | 252 | if (ret) |
| 253 | return ret; | 253 | return ret; |
| 254 | 254 | ||
| 255 | #ifdef CONFIG_DEBUG_FS | ||
| 256 | mmc_add_card_debugfs(card); | ||
| 257 | #endif | ||
| 258 | |||
| 255 | mmc_card_set_present(card); | 259 | mmc_card_set_present(card); |
| 256 | 260 | ||
| 257 | return 0; | 261 | return 0; |
| @@ -263,6 +267,10 @@ int mmc_add_card(struct mmc_card *card) | |||
| 263 | */ | 267 | */ |
| 264 | void mmc_remove_card(struct mmc_card *card) | 268 | void mmc_remove_card(struct mmc_card *card) |
| 265 | { | 269 | { |
| 270 | #ifdef CONFIG_DEBUG_FS | ||
| 271 | mmc_remove_card_debugfs(card); | ||
| 272 | #endif | ||
| 273 | |||
| 266 | if (mmc_card_present(card)) { | 274 | if (mmc_card_present(card)) { |
| 267 | if (mmc_host_is_spi(card->host)) { | 275 | if (mmc_host_is_spi(card->host)) { |
| 268 | printk(KERN_INFO "%s: SPI card removed\n", | 276 | printk(KERN_INFO "%s: SPI card removed\n", |
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index cdb332b7dedc..c819effa1032 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h | |||
| @@ -52,5 +52,12 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr); | |||
| 52 | 52 | ||
| 53 | extern int use_spi_crc; | 53 | extern int use_spi_crc; |
| 54 | 54 | ||
| 55 | /* Debugfs information for hosts and cards */ | ||
| 56 | void mmc_add_host_debugfs(struct mmc_host *host); | ||
| 57 | void mmc_remove_host_debugfs(struct mmc_host *host); | ||
| 58 | |||
| 59 | void mmc_add_card_debugfs(struct mmc_card *card); | ||
| 60 | void mmc_remove_card_debugfs(struct mmc_card *card); | ||
| 61 | |||
| 55 | #endif | 62 | #endif |
| 56 | 63 | ||
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c new file mode 100644 index 000000000000..1237bb4c722b --- /dev/null +++ b/drivers/mmc/core/debugfs.c | |||
| @@ -0,0 +1,225 @@ | |||
| 1 | /* | ||
| 2 | * Debugfs support for hosts and cards | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 Atmel Corporation | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | #include <linux/debugfs.h> | ||
| 11 | #include <linux/fs.h> | ||
| 12 | #include <linux/seq_file.h> | ||
| 13 | #include <linux/stat.h> | ||
| 14 | |||
| 15 | #include <linux/mmc/card.h> | ||
| 16 | #include <linux/mmc/host.h> | ||
| 17 | |||
| 18 | #include "core.h" | ||
| 19 | #include "mmc_ops.h" | ||
| 20 | |||
| 21 | /* The debugfs functions are optimized away when CONFIG_DEBUG_FS isn't set. */ | ||
| 22 | static int mmc_ios_show(struct seq_file *s, void *data) | ||
| 23 | { | ||
| 24 | static const char *vdd_str[] = { | ||
| 25 | [8] = "2.0", | ||
| 26 | [9] = "2.1", | ||
| 27 | [10] = "2.2", | ||
| 28 | [11] = "2.3", | ||
| 29 | [12] = "2.4", | ||
| 30 | [13] = "2.5", | ||
| 31 | [14] = "2.6", | ||
| 32 | [15] = "2.7", | ||
| 33 | [16] = "2.8", | ||
| 34 | [17] = "2.9", | ||
| 35 | [18] = "3.0", | ||
| 36 | [19] = "3.1", | ||
| 37 | [20] = "3.2", | ||
| 38 | [21] = "3.3", | ||
| 39 | [22] = "3.4", | ||
| 40 | [23] = "3.5", | ||
| 41 | [24] = "3.6", | ||
| 42 | }; | ||
| 43 | struct mmc_host *host = s->private; | ||
| 44 | struct mmc_ios *ios = &host->ios; | ||
| 45 | const char *str; | ||
| 46 | |||
| 47 | seq_printf(s, "clock:\t\t%u Hz\n", ios->clock); | ||
| 48 | seq_printf(s, "vdd:\t\t%u ", ios->vdd); | ||
| 49 | if ((1 << ios->vdd) & MMC_VDD_165_195) | ||
| 50 | seq_printf(s, "(1.65 - 1.95 V)\n"); | ||
| 51 | else if (ios->vdd < (ARRAY_SIZE(vdd_str) - 1) | ||
| 52 | && vdd_str[ios->vdd] && vdd_str[ios->vdd + 1]) | ||
| 53 | seq_printf(s, "(%s ~ %s V)\n", vdd_str[ios->vdd], | ||
| 54 | vdd_str[ios->vdd + 1]); | ||
| 55 | else | ||
| 56 | seq_printf(s, "(invalid)\n"); | ||
| 57 | |||
| 58 | switch (ios->bus_mode) { | ||
| 59 | case MMC_BUSMODE_OPENDRAIN: | ||
| 60 | str = "open drain"; | ||
| 61 | break; | ||
| 62 | case MMC_BUSMODE_PUSHPULL: | ||
| 63 | str = "push-pull"; | ||
| 64 | break; | ||
| 65 | default: | ||
| 66 | str = "invalid"; | ||
| 67 | break; | ||
| 68 | } | ||
| 69 | seq_printf(s, "bus mode:\t%u (%s)\n", ios->bus_mode, str); | ||
| 70 | |||
| 71 | switch (ios->chip_select) { | ||
| 72 | case MMC_CS_DONTCARE: | ||
| 73 | str = "don't care"; | ||
| 74 | break; | ||
| 75 | case MMC_CS_HIGH: | ||
| 76 | str = "active high"; | ||
| 77 | break; | ||
| 78 | case MMC_CS_LOW: | ||
| 79 | str = "active low"; | ||
| 80 | break; | ||
| 81 | default: | ||
| 82 | str = "invalid"; | ||
| 83 | break; | ||
| 84 | } | ||
| 85 | seq_printf(s, "chip select:\t%u (%s)\n", ios->chip_select, str); | ||
| 86 | |||
| 87 | switch (ios->power_mode) { | ||
| 88 | case MMC_POWER_OFF: | ||
| 89 | str = "off"; | ||
| 90 | break; | ||
| 91 | case MMC_POWER_UP: | ||
| 92 | str = "up"; | ||
| 93 | break; | ||
| 94 | case MMC_POWER_ON: | ||
| 95 | str = "on"; | ||
| 96 | break; | ||
| 97 | default: | ||
| 98 | str = "invalid"; | ||
| 99 | break; | ||
| 100 | } | ||
| 101 | seq_printf(s, "power mode:\t%u (%s)\n", ios->power_mode, str); | ||
| 102 | seq_printf(s, "bus width:\t%u (%u bits)\n", | ||
| 103 | ios->bus_width, 1 << ios->bus_width); | ||
| 104 | |||
| 105 | switch (ios->timing) { | ||
| 106 | case MMC_TIMING_LEGACY: | ||
| 107 | str = "legacy"; | ||
| 108 | break; | ||
| 109 | case MMC_TIMING_MMC_HS: | ||
| 110 | str = "mmc high-speed"; | ||
| 111 | break; | ||
| 112 | case MMC_TIMING_SD_HS: | ||
| 113 | str = "sd high-speed"; | ||
| 114 | break; | ||
| 115 | default: | ||
| 116 | str = "invalid"; | ||
| 117 | break; | ||
| 118 | } | ||
| 119 | seq_printf(s, "timing spec:\t%u (%s)\n", ios->timing, str); | ||
| 120 | |||
| 121 | return 0; | ||
| 122 | } | ||
| 123 | |||
| 124 | static int mmc_ios_open(struct inode *inode, struct file *file) | ||
| 125 | { | ||
| 126 | return single_open(file, mmc_ios_show, inode->i_private); | ||
| 127 | } | ||
| 128 | |||
| 129 | static const struct file_operations mmc_ios_fops = { | ||
| 130 | .open = mmc_ios_open, | ||
| 131 | .read = seq_read, | ||
| 132 | .llseek = seq_lseek, | ||
| 133 | .release = single_release, | ||
| 134 | }; | ||
| 135 | |||
| 136 | void mmc_add_host_debugfs(struct mmc_host *host) | ||
| 137 | { | ||
| 138 | struct dentry *root; | ||
| 139 | |||
| 140 | root = debugfs_create_dir(mmc_hostname(host), NULL); | ||
| 141 | if (IS_ERR(root)) | ||
| 142 | /* Don't complain -- debugfs just isn't enabled */ | ||
| 143 | return; | ||
| 144 | if (!root) | ||
| 145 | /* Complain -- debugfs is enabled, but it failed to | ||
| 146 | * create the directory. */ | ||
| 147 | goto err_root; | ||
| 148 | |||
| 149 | host->debugfs_root = root; | ||
| 150 | |||
| 151 | if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops)) | ||
| 152 | goto err_ios; | ||
| 153 | |||
| 154 | return; | ||
| 155 | |||
| 156 | err_ios: | ||
| 157 | debugfs_remove_recursive(root); | ||
| 158 | host->debugfs_root = NULL; | ||
| 159 | err_root: | ||
| 160 | dev_err(&host->class_dev, "failed to initialize debugfs\n"); | ||
| 161 | } | ||
| 162 | |||
| 163 | void mmc_remove_host_debugfs(struct mmc_host *host) | ||
| 164 | { | ||
| 165 | debugfs_remove_recursive(host->debugfs_root); | ||
| 166 | } | ||
| 167 | |||
| 168 | static int mmc_dbg_card_status_get(void *data, u64 *val) | ||
| 169 | { | ||
| 170 | struct mmc_card *card = data; | ||
| 171 | u32 status; | ||
| 172 | int ret; | ||
| 173 | |||
| 174 | mmc_claim_host(card->host); | ||
| 175 | |||
| 176 | ret = mmc_send_status(data, &status); | ||
| 177 | if (!ret) | ||
| 178 | *val = status; | ||
| 179 | |||
| 180 | mmc_release_host(card->host); | ||
| 181 | |||
| 182 | return ret; | ||
| 183 | } | ||
| 184 | DEFINE_SIMPLE_ATTRIBUTE(mmc_dbg_card_status_fops, mmc_dbg_card_status_get, | ||
| 185 | NULL, "%08llx\n"); | ||
| 186 | |||
| 187 | void mmc_add_card_debugfs(struct mmc_card *card) | ||
| 188 | { | ||
| 189 | struct mmc_host *host = card->host; | ||
| 190 | struct dentry *root; | ||
| 191 | |||
| 192 | if (!host->debugfs_root) | ||
| 193 | return; | ||
| 194 | |||
| 195 | root = debugfs_create_dir(mmc_card_id(card), host->debugfs_root); | ||
| 196 | if (IS_ERR(root)) | ||
| 197 | /* Don't complain -- debugfs just isn't enabled */ | ||
| 198 | return; | ||
| 199 | if (!root) | ||
| 200 | /* Complain -- debugfs is enabled, but it failed to | ||
| 201 | * create the directory. */ | ||
| 202 | goto err; | ||
| 203 | |||
| 204 | card->debugfs_root = root; | ||
| 205 | |||
| 206 | if (!debugfs_create_x32("state", S_IRUSR, root, &card->state)) | ||
| 207 | goto err; | ||
| 208 | |||
| 209 | if (mmc_card_mmc(card) || mmc_card_sd(card)) | ||
| 210 | if (!debugfs_create_file("status", S_IRUSR, root, card, | ||
| 211 | &mmc_dbg_card_status_fops)) | ||
| 212 | goto err; | ||
| 213 | |||
| 214 | return; | ||
| 215 | |||
| 216 | err: | ||
| 217 | debugfs_remove_recursive(root); | ||
| 218 | card->debugfs_root = NULL; | ||
| 219 | dev_err(&card->dev, "failed to initialize debugfs\n"); | ||
| 220 | } | ||
| 221 | |||
| 222 | void mmc_remove_card_debugfs(struct mmc_card *card) | ||
| 223 | { | ||
| 224 | debugfs_remove_recursive(card->debugfs_root); | ||
| 225 | } | ||
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 1d795c5379b5..6da80fd4d974 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c | |||
| @@ -127,6 +127,10 @@ int mmc_add_host(struct mmc_host *host) | |||
| 127 | if (err) | 127 | if (err) |
| 128 | return err; | 128 | return err; |
| 129 | 129 | ||
| 130 | #ifdef CONFIG_DEBUG_FS | ||
| 131 | mmc_add_host_debugfs(host); | ||
| 132 | #endif | ||
| 133 | |||
| 130 | mmc_start_host(host); | 134 | mmc_start_host(host); |
| 131 | 135 | ||
| 132 | return 0; | 136 | return 0; |
| @@ -146,6 +150,10 @@ void mmc_remove_host(struct mmc_host *host) | |||
| 146 | { | 150 | { |
| 147 | mmc_stop_host(host); | 151 | mmc_stop_host(host); |
| 148 | 152 | ||
| 153 | #ifdef CONFIG_DEBUG_FS | ||
| 154 | mmc_remove_host_debugfs(host); | ||
| 155 | #endif | ||
| 156 | |||
| 149 | device_del(&host->class_dev); | 157 | device_del(&host->class_dev); |
| 150 | 158 | ||
| 151 | led_trigger_unregister_simple(host->led); | 159 | led_trigger_unregister_simple(host->led); |
diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h index a9a5657706c6..26bd80e65031 100644 --- a/drivers/mmc/host/atmel-mci-regs.h +++ b/drivers/mmc/host/atmel-mci-regs.h | |||
| @@ -82,6 +82,8 @@ | |||
| 82 | # define MCI_OVRE ( 1 << 30) /* RX Overrun Error */ | 82 | # define MCI_OVRE ( 1 << 30) /* RX Overrun Error */ |
| 83 | # define MCI_UNRE ( 1 << 31) /* TX Underrun Error */ | 83 | # define MCI_UNRE ( 1 << 31) /* TX Underrun Error */ |
| 84 | 84 | ||
| 85 | #define MCI_REGS_SIZE 0x100 | ||
| 86 | |||
| 85 | /* Register access macros */ | 87 | /* Register access macros */ |
| 86 | #define mci_readl(port,reg) \ | 88 | #define mci_readl(port,reg) \ |
| 87 | __raw_readl((port)->regs + MCI_##reg) | 89 | __raw_readl((port)->regs + MCI_##reg) |
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index cce873c5a149..992b4beb757c 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c | |||
| @@ -9,13 +9,18 @@ | |||
| 9 | */ | 9 | */ |
| 10 | #include <linux/blkdev.h> | 10 | #include <linux/blkdev.h> |
| 11 | #include <linux/clk.h> | 11 | #include <linux/clk.h> |
| 12 | #include <linux/debugfs.h> | ||
| 12 | #include <linux/device.h> | 13 | #include <linux/device.h> |
| 14 | #include <linux/err.h> | ||
| 15 | #include <linux/gpio.h> | ||
| 13 | #include <linux/init.h> | 16 | #include <linux/init.h> |
| 14 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
| 15 | #include <linux/ioport.h> | 18 | #include <linux/ioport.h> |
| 16 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 17 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
| 18 | #include <linux/scatterlist.h> | 21 | #include <linux/scatterlist.h> |
| 22 | #include <linux/seq_file.h> | ||
| 23 | #include <linux/stat.h> | ||
| 19 | 24 | ||
| 20 | #include <linux/mmc/host.h> | 25 | #include <linux/mmc/host.h> |
| 21 | 26 | ||
| @@ -24,7 +29,6 @@ | |||
| 24 | #include <asm/unaligned.h> | 29 | #include <asm/unaligned.h> |
| 25 | 30 | ||
| 26 | #include <asm/arch/board.h> | 31 | #include <asm/arch/board.h> |
| 27 | #include <asm/arch/gpio.h> | ||
| 28 | 32 | ||
| 29 | #include "atmel-mci-regs.h" | 33 | #include "atmel-mci-regs.h" |
| 30 | 34 | ||
| @@ -88,6 +92,188 @@ struct atmel_mci { | |||
| 88 | #define atmci_clear_pending(host, event) \ | 92 | #define atmci_clear_pending(host, event) \ |
| 89 | clear_bit(event, &host->pending_events) | 93 | clear_bit(event, &host->pending_events) |
| 90 | 94 | ||
| 95 | /* | ||
| 96 | * The debugfs stuff below is mostly optimized away when | ||
| 97 | * CONFIG_DEBUG_FS is not set. | ||
| 98 | */ | ||
| 99 | static int atmci_req_show(struct seq_file *s, void *v) | ||
| 100 | { | ||
| 101 | struct atmel_mci *host = s->private; | ||
| 102 | struct mmc_request *mrq = host->mrq; | ||
| 103 | struct mmc_command *cmd; | ||
| 104 | struct mmc_command *stop; | ||
| 105 | struct mmc_data *data; | ||
| 106 | |||
| 107 | /* Make sure we get a consistent snapshot */ | ||
| 108 | spin_lock_irq(&host->mmc->lock); | ||
| 109 | |||
| 110 | if (mrq) { | ||
| 111 | cmd = mrq->cmd; | ||
| 112 | data = mrq->data; | ||
| 113 | stop = mrq->stop; | ||
| 114 | |||
| 115 | if (cmd) | ||
| 116 | seq_printf(s, | ||
| 117 | "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", | ||
| 118 | cmd->opcode, cmd->arg, cmd->flags, | ||
| 119 | cmd->resp[0], cmd->resp[1], cmd->resp[2], | ||
| 120 | cmd->resp[2], cmd->error); | ||
| 121 | if (data) | ||
| 122 | seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", | ||
| 123 | data->bytes_xfered, data->blocks, | ||
| 124 | data->blksz, data->flags, data->error); | ||
| 125 | if (stop) | ||
| 126 | seq_printf(s, | ||
| 127 | "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", | ||
| 128 | stop->opcode, stop->arg, stop->flags, | ||
| 129 | stop->resp[0], stop->resp[1], stop->resp[2], | ||
| 130 | stop->resp[2], stop->error); | ||
| 131 | } | ||
| 132 | |||
| 133 | spin_unlock_irq(&host->mmc->lock); | ||
| 134 | |||
| 135 | return 0; | ||
| 136 | } | ||
| 137 | |||
| 138 | static int atmci_req_open(struct inode *inode, struct file *file) | ||
| 139 | { | ||
| 140 | return single_open(file, atmci_req_show, inode->i_private); | ||
| 141 | } | ||
| 142 | |||
| 143 | static const struct file_operations atmci_req_fops = { | ||
| 144 | .owner = THIS_MODULE, | ||
| 145 | .open = atmci_req_open, | ||
| 146 | .read = seq_read, | ||
| 147 | .llseek = seq_lseek, | ||
| 148 | .release = single_release, | ||
| 149 | }; | ||
| 150 | |||
| 151 | static void atmci_show_status_reg(struct seq_file *s, | ||
| 152 | const char *regname, u32 value) | ||
| 153 | { | ||
| 154 | static const char *sr_bit[] = { | ||
| 155 | [0] = "CMDRDY", | ||
| 156 | [1] = "RXRDY", | ||
| 157 | [2] = "TXRDY", | ||
| 158 | [3] = "BLKE", | ||
| 159 | [4] = "DTIP", | ||
| 160 | [5] = "NOTBUSY", | ||
| 161 | [8] = "SDIOIRQA", | ||
| 162 | [9] = "SDIOIRQB", | ||
| 163 | [16] = "RINDE", | ||
| 164 | [17] = "RDIRE", | ||
| 165 | [18] = "RCRCE", | ||
| 166 | [19] = "RENDE", | ||
| 167 | [20] = "RTOE", | ||
| 168 | [21] = "DCRCE", | ||
| 169 | [22] = "DTOE", | ||
| 170 | [30] = "OVRE", | ||
| 171 | [31] = "UNRE", | ||
| 172 | }; | ||
| 173 | unsigned int i; | ||
| 174 | |||
| 175 | seq_printf(s, "%s:\t0x%08x", regname, value); | ||
| 176 | for (i = 0; i < ARRAY_SIZE(sr_bit); i++) { | ||
| 177 | if (value & (1 << i)) { | ||
| 178 | if (sr_bit[i]) | ||
| 179 | seq_printf(s, " %s", sr_bit[i]); | ||
| 180 | else | ||
| 181 | seq_puts(s, " UNKNOWN"); | ||
| 182 | } | ||
| 183 | } | ||
| 184 | seq_putc(s, '\n'); | ||
| 185 | } | ||
| 186 | |||
| 187 | static int atmci_regs_show(struct seq_file *s, void *v) | ||
| 188 | { | ||
| 189 | struct atmel_mci *host = s->private; | ||
| 190 | u32 *buf; | ||
| 191 | |||
| 192 | buf = kmalloc(MCI_REGS_SIZE, GFP_KERNEL); | ||
| 193 | if (!buf) | ||
| 194 | return -ENOMEM; | ||
| 195 | |||
| 196 | /* Grab a more or less consistent snapshot */ | ||
| 197 | spin_lock_irq(&host->mmc->lock); | ||
| 198 | memcpy_fromio(buf, host->regs, MCI_REGS_SIZE); | ||
| 199 | spin_unlock_irq(&host->mmc->lock); | ||
| 200 | |||
| 201 | seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n", | ||
| 202 | buf[MCI_MR / 4], | ||
| 203 | buf[MCI_MR / 4] & MCI_MR_RDPROOF ? " RDPROOF" : "", | ||
| 204 | buf[MCI_MR / 4] & MCI_MR_WRPROOF ? " WRPROOF" : "", | ||
| 205 | buf[MCI_MR / 4] & 0xff); | ||
| 206 | seq_printf(s, "DTOR:\t0x%08x\n", buf[MCI_DTOR / 4]); | ||
| 207 | seq_printf(s, "SDCR:\t0x%08x\n", buf[MCI_SDCR / 4]); | ||
| 208 | seq_printf(s, "ARGR:\t0x%08x\n", buf[MCI_ARGR / 4]); | ||
| 209 | seq_printf(s, "BLKR:\t0x%08x BCNT=%u BLKLEN=%u\n", | ||
| 210 | buf[MCI_BLKR / 4], | ||
| 211 | buf[MCI_BLKR / 4] & 0xffff, | ||
| 212 | (buf[MCI_BLKR / 4] >> 16) & 0xffff); | ||
| 213 | |||
| 214 | /* Don't read RSPR and RDR; it will consume the data there */ | ||
| 215 | |||
| 216 | atmci_show_status_reg(s, "SR", buf[MCI_SR / 4]); | ||
| 217 | atmci_show_status_reg(s, "IMR", buf[MCI_IMR / 4]); | ||
| 218 | |||
| 219 | return 0; | ||
| 220 | } | ||
| 221 | |||
| 222 | static int atmci_regs_open(struct inode *inode, struct file *file) | ||
| 223 | { | ||
| 224 | return single_open(file, atmci_regs_show, inode->i_private); | ||
| 225 | } | ||
| 226 | |||
| 227 | static const struct file_operations atmci_regs_fops = { | ||
| 228 | .owner = THIS_MODULE, | ||
| 229 | .open = atmci_regs_open, | ||
| 230 | .read = seq_read, | ||
| 231 | .llseek = seq_lseek, | ||
| 232 | .release = single_release, | ||
| 233 | }; | ||
| 234 | |||
| 235 | static void atmci_init_debugfs(struct atmel_mci *host) | ||
| 236 | { | ||
| 237 | struct mmc_host *mmc; | ||
| 238 | struct dentry *root; | ||
| 239 | struct dentry *node; | ||
| 240 | struct resource *res; | ||
| 241 | |||
| 242 | mmc = host->mmc; | ||
| 243 | root = mmc->debugfs_root; | ||
| 244 | if (!root) | ||
| 245 | return; | ||
| 246 | |||
| 247 | node = debugfs_create_file("regs", S_IRUSR, root, host, | ||
| 248 | &atmci_regs_fops); | ||
| 249 | if (IS_ERR(node)) | ||
| 250 | return; | ||
| 251 | if (!node) | ||
| 252 | goto err; | ||
| 253 | |||
| 254 | res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0); | ||
| 255 | node->d_inode->i_size = res->end - res->start + 1; | ||
| 256 | |||
| 257 | node = debugfs_create_file("req", S_IRUSR, root, host, &atmci_req_fops); | ||
| 258 | if (!node) | ||
| 259 | goto err; | ||
| 260 | |||
| 261 | node = debugfs_create_x32("pending_events", S_IRUSR, root, | ||
| 262 | (u32 *)&host->pending_events); | ||
| 263 | if (!node) | ||
| 264 | goto err; | ||
| 265 | |||
| 266 | node = debugfs_create_x32("completed_events", S_IRUSR, root, | ||
| 267 | (u32 *)&host->completed_events); | ||
| 268 | if (!node) | ||
| 269 | goto err; | ||
| 270 | |||
| 271 | return; | ||
| 272 | |||
| 273 | err: | ||
| 274 | dev_err(&host->pdev->dev, | ||
| 275 | "failed to initialize debugfs for controller\n"); | ||
| 276 | } | ||
| 91 | 277 | ||
| 92 | static void atmci_enable(struct atmel_mci *host) | 278 | static void atmci_enable(struct atmel_mci *host) |
| 93 | { | 279 | { |
| @@ -388,7 +574,7 @@ static int atmci_get_ro(struct mmc_host *mmc) | |||
| 388 | int read_only = 0; | 574 | int read_only = 0; |
| 389 | struct atmel_mci *host = mmc_priv(mmc); | 575 | struct atmel_mci *host = mmc_priv(mmc); |
| 390 | 576 | ||
| 391 | if (host->wp_pin >= 0) { | 577 | if (gpio_is_valid(host->wp_pin)) { |
| 392 | read_only = gpio_get_value(host->wp_pin); | 578 | read_only = gpio_get_value(host->wp_pin); |
| 393 | dev_dbg(&mmc->class_dev, "card is %s\n", | 579 | dev_dbg(&mmc->class_dev, "card is %s\n", |
| 394 | read_only ? "read-only" : "read-write"); | 580 | read_only ? "read-only" : "read-write"); |
| @@ -450,7 +636,7 @@ static void atmci_detect_change(unsigned long data) | |||
| 450 | * been freed. | 636 | * been freed. |
| 451 | */ | 637 | */ |
| 452 | smp_rmb(); | 638 | smp_rmb(); |
| 453 | if (host->detect_pin < 0) | 639 | if (!gpio_is_valid(host->detect_pin)) |
| 454 | return; | 640 | return; |
| 455 | 641 | ||
| 456 | enable_irq(gpio_to_irq(host->detect_pin)); | 642 | enable_irq(gpio_to_irq(host->detect_pin)); |
| @@ -865,7 +1051,7 @@ static int __init atmci_probe(struct platform_device *pdev) | |||
| 865 | 1051 | ||
| 866 | /* Assume card is present if we don't have a detect pin */ | 1052 | /* Assume card is present if we don't have a detect pin */ |
| 867 | host->present = 1; | 1053 | host->present = 1; |
| 868 | if (host->detect_pin >= 0) { | 1054 | if (gpio_is_valid(host->detect_pin)) { |
| 869 | if (gpio_request(host->detect_pin, "mmc_detect")) { | 1055 | if (gpio_request(host->detect_pin, "mmc_detect")) { |
| 870 | dev_dbg(&mmc->class_dev, "no detect pin available\n"); | 1056 | dev_dbg(&mmc->class_dev, "no detect pin available\n"); |
| 871 | host->detect_pin = -1; | 1057 | host->detect_pin = -1; |
| @@ -873,7 +1059,7 @@ static int __init atmci_probe(struct platform_device *pdev) | |||
| 873 | host->present = !gpio_get_value(host->detect_pin); | 1059 | host->present = !gpio_get_value(host->detect_pin); |
| 874 | } | 1060 | } |
| 875 | } | 1061 | } |
| 876 | if (host->wp_pin >= 0) { | 1062 | if (gpio_is_valid(host->wp_pin)) { |
| 877 | if (gpio_request(host->wp_pin, "mmc_wp")) { | 1063 | if (gpio_request(host->wp_pin, "mmc_wp")) { |
| 878 | dev_dbg(&mmc->class_dev, "no WP pin available\n"); | 1064 | dev_dbg(&mmc->class_dev, "no WP pin available\n"); |
| 879 | host->wp_pin = -1; | 1065 | host->wp_pin = -1; |
| @@ -884,7 +1070,7 @@ static int __init atmci_probe(struct platform_device *pdev) | |||
| 884 | 1070 | ||
| 885 | mmc_add_host(mmc); | 1071 | mmc_add_host(mmc); |
| 886 | 1072 | ||
| 887 | if (host->detect_pin >= 0) { | 1073 | if (gpio_is_valid(host->detect_pin)) { |
| 888 | setup_timer(&host->detect_timer, atmci_detect_change, | 1074 | setup_timer(&host->detect_timer, atmci_detect_change, |
| 889 | (unsigned long)host); | 1075 | (unsigned long)host); |
| 890 | 1076 | ||
| @@ -905,6 +1091,8 @@ static int __init atmci_probe(struct platform_device *pdev) | |||
| 905 | "Atmel MCI controller at 0x%08lx irq %d\n", | 1091 | "Atmel MCI controller at 0x%08lx irq %d\n", |
| 906 | host->mapbase, irq); | 1092 | host->mapbase, irq); |
| 907 | 1093 | ||
| 1094 | atmci_init_debugfs(host); | ||
| 1095 | |||
| 908 | return 0; | 1096 | return 0; |
| 909 | 1097 | ||
| 910 | err_request_irq: | 1098 | err_request_irq: |
| @@ -923,7 +1111,9 @@ static int __exit atmci_remove(struct platform_device *pdev) | |||
| 923 | platform_set_drvdata(pdev, NULL); | 1111 | platform_set_drvdata(pdev, NULL); |
| 924 | 1112 | ||
| 925 | if (host) { | 1113 | if (host) { |
| 926 | if (host->detect_pin >= 0) { | 1114 | /* Debugfs stuff is cleaned up by mmc core */ |
| 1115 | |||
| 1116 | if (gpio_is_valid(host->detect_pin)) { | ||
| 927 | int pin = host->detect_pin; | 1117 | int pin = host->detect_pin; |
| 928 | 1118 | ||
| 929 | /* Make sure the timer doesn't enable the interrupt */ | 1119 | /* Make sure the timer doesn't enable the interrupt */ |
| @@ -943,7 +1133,7 @@ static int __exit atmci_remove(struct platform_device *pdev) | |||
| 943 | mci_readl(host, SR); | 1133 | mci_readl(host, SR); |
| 944 | clk_disable(host->mck); | 1134 | clk_disable(host->mck); |
| 945 | 1135 | ||
| 946 | if (host->wp_pin >= 0) | 1136 | if (gpio_is_valid(host->wp_pin)) |
| 947 | gpio_free(host->wp_pin); | 1137 | gpio_free(host->wp_pin); |
| 948 | 1138 | ||
| 949 | free_irq(platform_get_irq(pdev, 0), host->mmc); | 1139 | free_irq(platform_get_irq(pdev, 0), host->mmc); |
diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c index 5e880c0f1349..f61406da65d2 100644 --- a/drivers/mmc/host/imxmmc.c +++ b/drivers/mmc/host/imxmmc.c | |||
| @@ -26,12 +26,6 @@ | |||
| 26 | * | 26 | * |
| 27 | */ | 27 | */ |
| 28 | 28 | ||
| 29 | #ifdef CONFIG_MMC_DEBUG | ||
| 30 | #define DEBUG | ||
| 31 | #else | ||
| 32 | #undef DEBUG | ||
| 33 | #endif | ||
| 34 | |||
| 35 | #include <linux/module.h> | 29 | #include <linux/module.h> |
| 36 | #include <linux/init.h> | 30 | #include <linux/init.h> |
| 37 | #include <linux/ioport.h> | 31 | #include <linux/ioport.h> |
| @@ -907,31 +901,12 @@ static const struct mmc_host_ops imxmci_ops = { | |||
| 907 | .get_ro = imxmci_get_ro, | 901 | .get_ro = imxmci_get_ro, |
| 908 | }; | 902 | }; |
| 909 | 903 | ||
| 910 | static struct resource *platform_device_resource(struct platform_device *dev, unsigned int mask, int nr) | ||
| 911 | { | ||
| 912 | int i; | ||
| 913 | |||
| 914 | for (i = 0; i < dev->num_resources; i++) | ||
| 915 | if (dev->resource[i].flags == mask && nr-- == 0) | ||
| 916 | return &dev->resource[i]; | ||
| 917 | return NULL; | ||
| 918 | } | ||
| 919 | |||
| 920 | static int platform_device_irq(struct platform_device *dev, int nr) | ||
| 921 | { | ||
| 922 | int i; | ||
| 923 | |||
| 924 | for (i = 0; i < dev->num_resources; i++) | ||
| 925 | if (dev->resource[i].flags == IORESOURCE_IRQ && nr-- == 0) | ||
| 926 | return dev->resource[i].start; | ||
| 927 | return NO_IRQ; | ||
| 928 | } | ||
| 929 | |||
| 930 | static void imxmci_check_status(unsigned long data) | 904 | static void imxmci_check_status(unsigned long data) |
| 931 | { | 905 | { |
| 932 | struct imxmci_host *host = (struct imxmci_host *)data; | 906 | struct imxmci_host *host = (struct imxmci_host *)data; |
| 933 | 907 | ||
| 934 | if( host->pdata->card_present(mmc_dev(host->mmc)) != host->present ) { | 908 | if (host->pdata && host->pdata->card_present && |
| 909 | host->pdata->card_present(mmc_dev(host->mmc)) != host->present) { | ||
| 935 | host->present ^= 1; | 910 | host->present ^= 1; |
| 936 | dev_info(mmc_dev(host->mmc), "card %s\n", | 911 | dev_info(mmc_dev(host->mmc), "card %s\n", |
| 937 | host->present ? "inserted" : "removed"); | 912 | host->present ? "inserted" : "removed"); |
| @@ -962,13 +937,12 @@ static int imxmci_probe(struct platform_device *pdev) | |||
| 962 | 937 | ||
| 963 | printk(KERN_INFO "i.MX mmc driver\n"); | 938 | printk(KERN_INFO "i.MX mmc driver\n"); |
| 964 | 939 | ||
| 965 | r = platform_device_resource(pdev, IORESOURCE_MEM, 0); | 940 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 966 | irq = platform_device_irq(pdev, 0); | 941 | irq = platform_get_irq(pdev, 0); |
| 967 | if (!r || irq == NO_IRQ) | 942 | if (!r || irq < 0) |
| 968 | return -ENXIO; | 943 | return -ENXIO; |
| 969 | 944 | ||
| 970 | r = request_mem_region(r->start, 0x100, "IMXMCI"); | 945 | if (!request_mem_region(r->start, 0x100, pdev->name)) |
| 971 | if (!r) | ||
| 972 | return -EBUSY; | 946 | return -EBUSY; |
| 973 | 947 | ||
| 974 | mmc = mmc_alloc_host(sizeof(struct imxmci_host), &pdev->dev); | 948 | mmc = mmc_alloc_host(sizeof(struct imxmci_host), &pdev->dev); |
| @@ -995,6 +969,8 @@ static int imxmci_probe(struct platform_device *pdev) | |||
| 995 | host->mmc = mmc; | 969 | host->mmc = mmc; |
| 996 | host->dma_allocated = 0; | 970 | host->dma_allocated = 0; |
| 997 | host->pdata = pdev->dev.platform_data; | 971 | host->pdata = pdev->dev.platform_data; |
| 972 | if (!host->pdata) | ||
| 973 | dev_warn(&pdev->dev, "No platform data provided!\n"); | ||
| 998 | 974 | ||
| 999 | spin_lock_init(&host->lock); | 975 | spin_lock_init(&host->lock); |
| 1000 | host->res = r; | 976 | host->res = r; |
| @@ -1047,7 +1023,11 @@ static int imxmci_probe(struct platform_device *pdev) | |||
| 1047 | if (ret) | 1023 | if (ret) |
| 1048 | goto out; | 1024 | goto out; |
| 1049 | 1025 | ||
| 1050 | host->present = host->pdata->card_present(mmc_dev(mmc)); | 1026 | if (host->pdata && host->pdata->card_present) |
| 1027 | host->present = host->pdata->card_present(mmc_dev(mmc)); | ||
| 1028 | else /* if there is no way to detect assume that card is present */ | ||
| 1029 | host->present = 1; | ||
| 1030 | |||
| 1051 | init_timer(&host->timer); | 1031 | init_timer(&host->timer); |
| 1052 | host->timer.data = (unsigned long)host; | 1032 | host->timer.data = (unsigned long)host; |
| 1053 | host->timer.function = imxmci_check_status; | 1033 | host->timer.function = imxmci_check_status; |
| @@ -1073,7 +1053,7 @@ out: | |||
| 1073 | } | 1053 | } |
| 1074 | if (mmc) | 1054 | if (mmc) |
| 1075 | mmc_free_host(mmc); | 1055 | mmc_free_host(mmc); |
| 1076 | release_resource(r); | 1056 | release_mem_region(r->start, 0x100); |
| 1077 | return ret; | 1057 | return ret; |
| 1078 | } | 1058 | } |
| 1079 | 1059 | ||
| @@ -1102,7 +1082,7 @@ static int imxmci_remove(struct platform_device *pdev) | |||
| 1102 | clk_disable(host->clk); | 1082 | clk_disable(host->clk); |
| 1103 | clk_put(host->clk); | 1083 | clk_put(host->clk); |
| 1104 | 1084 | ||
| 1105 | release_resource(host->res); | 1085 | release_mem_region(host->res->start, 0x100); |
| 1106 | 1086 | ||
| 1107 | mmc_free_host(mmc); | 1087 | mmc_free_host(mmc); |
| 1108 | } | 1088 | } |
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 41cc63360e43..7503b81374e0 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c | |||
| @@ -1076,6 +1076,7 @@ static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
| 1076 | */ | 1076 | */ |
| 1077 | if (canpower && ios->power_mode == MMC_POWER_OFF) { | 1077 | if (canpower && ios->power_mode == MMC_POWER_OFF) { |
| 1078 | int mres; | 1078 | int mres; |
| 1079 | u8 nullbyte = 0; | ||
| 1079 | 1080 | ||
| 1080 | host->spi->mode &= ~(SPI_CPOL|SPI_CPHA); | 1081 | host->spi->mode &= ~(SPI_CPOL|SPI_CPHA); |
| 1081 | mres = spi_setup(host->spi); | 1082 | mres = spi_setup(host->spi); |
| @@ -1083,7 +1084,7 @@ static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
| 1083 | dev_dbg(&host->spi->dev, | 1084 | dev_dbg(&host->spi->dev, |
| 1084 | "switch to SPI mode 0 failed\n"); | 1085 | "switch to SPI mode 0 failed\n"); |
| 1085 | 1086 | ||
| 1086 | if (spi_w8r8(host->spi, 0x00) < 0) | 1087 | if (spi_write(host->spi, &nullbyte, 1) < 0) |
| 1087 | dev_dbg(&host->spi->dev, | 1088 | dev_dbg(&host->spi->dev, |
| 1088 | "put spi signals to low failed\n"); | 1089 | "put spi signals to low failed\n"); |
| 1089 | 1090 | ||
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index c3a5db72ddd7..5f95e10229b5 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
| @@ -337,7 +337,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, | |||
| 337 | 337 | ||
| 338 | host->align_addr = dma_map_single(mmc_dev(host->mmc), | 338 | host->align_addr = dma_map_single(mmc_dev(host->mmc), |
| 339 | host->align_buffer, 128 * 4, direction); | 339 | host->align_buffer, 128 * 4, direction); |
| 340 | if (dma_mapping_error(host->align_addr)) | 340 | if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr)) |
| 341 | goto fail; | 341 | goto fail; |
| 342 | BUG_ON(host->align_addr & 0x3); | 342 | BUG_ON(host->align_addr & 0x3); |
| 343 | 343 | ||
| @@ -439,7 +439,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, | |||
| 439 | 439 | ||
| 440 | host->adma_addr = dma_map_single(mmc_dev(host->mmc), | 440 | host->adma_addr = dma_map_single(mmc_dev(host->mmc), |
| 441 | host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE); | 441 | host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE); |
| 442 | if (dma_mapping_error(host->align_addr)) | 442 | if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr)) |
| 443 | goto unmap_entries; | 443 | goto unmap_entries; |
| 444 | BUG_ON(host->adma_addr & 0x3); | 444 | BUG_ON(host->adma_addr & 0x3); |
| 445 | 445 | ||
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index a06bf8b89343..e354faee5df0 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h | |||
| @@ -9,6 +9,8 @@ | |||
| 9 | * your option) any later version. | 9 | * your option) any later version. |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/scatterlist.h> | ||
| 13 | |||
| 12 | /* | 14 | /* |
| 13 | * Controller registers | 15 | * Controller registers |
| 14 | */ | 16 | */ |
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index eed06d068fd1..14f11f8b9e5f 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig | |||
| @@ -1,5 +1,3 @@ | |||
| 1 | # $Id: Kconfig,v 1.11 2005/11/07 11:14:19 gleixner Exp $ | ||
| 2 | |||
| 3 | menuconfig MTD | 1 | menuconfig MTD |
| 4 | tristate "Memory Technology Device (MTD) support" | 2 | tristate "Memory Technology Device (MTD) support" |
| 5 | depends on HAS_IOMEM | 3 | depends on HAS_IOMEM |
diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c index 52d51eb91c16..d072ca5be689 100644 --- a/drivers/mtd/afs.c +++ b/drivers/mtd/afs.c | |||
| @@ -21,8 +21,6 @@ | |||
| 21 | This is access code for flashes using ARM's flash partitioning | 21 | This is access code for flashes using ARM's flash partitioning |
| 22 | standards. | 22 | standards. |
| 23 | 23 | ||
| 24 | $Id: afs.c,v 1.15 2005/11/07 11:14:19 gleixner Exp $ | ||
| 25 | |||
| 26 | ======================================================================*/ | 24 | ======================================================================*/ |
| 27 | 25 | ||
| 28 | #include <linux/module.h> | 26 | #include <linux/module.h> |
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index fcd1aeccdf93..5f1b472137a0 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c | |||
| @@ -4,8 +4,6 @@ | |||
| 4 | * | 4 | * |
| 5 | * (C) 2000 Red Hat. GPL'd | 5 | * (C) 2000 Red Hat. GPL'd |
| 6 | * | 6 | * |
| 7 | * $Id: cfi_cmdset_0001.c,v 1.186 2005/11/23 22:07:52 nico Exp $ | ||
| 8 | * | ||
| 9 | * | 7 | * |
| 10 | * 10/10/2000 Nicolas Pitre <nico@cam.org> | 8 | * 10/10/2000 Nicolas Pitre <nico@cam.org> |
| 11 | * - completely revamped method functions so they are aware and | 9 | * - completely revamped method functions so they are aware and |
| @@ -50,6 +48,8 @@ | |||
| 50 | #define I82802AC 0x00ac | 48 | #define I82802AC 0x00ac |
| 51 | #define MANUFACTURER_ST 0x0020 | 49 | #define MANUFACTURER_ST 0x0020 |
| 52 | #define M50LPW080 0x002F | 50 | #define M50LPW080 0x002F |
| 51 | #define M50FLW080A 0x0080 | ||
| 52 | #define M50FLW080B 0x0081 | ||
| 53 | #define AT49BV640D 0x02de | 53 | #define AT49BV640D 0x02de |
| 54 | 54 | ||
| 55 | static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); | 55 | static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); |
| @@ -204,7 +204,7 @@ static void fixup_intel_strataflash(struct mtd_info *mtd, void* param) | |||
| 204 | { | 204 | { |
| 205 | struct map_info *map = mtd->priv; | 205 | struct map_info *map = mtd->priv; |
| 206 | struct cfi_private *cfi = map->fldrv_priv; | 206 | struct cfi_private *cfi = map->fldrv_priv; |
| 207 | struct cfi_pri_amdstd *extp = cfi->cmdset_priv; | 207 | struct cfi_pri_intelext *extp = cfi->cmdset_priv; |
| 208 | 208 | ||
| 209 | printk(KERN_WARNING "cfi_cmdset_0001: Suspend " | 209 | printk(KERN_WARNING "cfi_cmdset_0001: Suspend " |
| 210 | "erase on write disabled.\n"); | 210 | "erase on write disabled.\n"); |
| @@ -301,6 +301,8 @@ static struct cfi_fixup jedec_fixup_table[] = { | |||
| 301 | { MANUFACTURER_INTEL, I82802AB, fixup_use_fwh_lock, NULL, }, | 301 | { MANUFACTURER_INTEL, I82802AB, fixup_use_fwh_lock, NULL, }, |
| 302 | { MANUFACTURER_INTEL, I82802AC, fixup_use_fwh_lock, NULL, }, | 302 | { MANUFACTURER_INTEL, I82802AC, fixup_use_fwh_lock, NULL, }, |
| 303 | { MANUFACTURER_ST, M50LPW080, fixup_use_fwh_lock, NULL, }, | 303 | { MANUFACTURER_ST, M50LPW080, fixup_use_fwh_lock, NULL, }, |
| 304 | { MANUFACTURER_ST, M50FLW080A, fixup_use_fwh_lock, NULL, }, | ||
| 305 | { MANUFACTURER_ST, M50FLW080B, fixup_use_fwh_lock, NULL, }, | ||
| 304 | { 0, 0, NULL, NULL } | 306 | { 0, 0, NULL, NULL } |
| 305 | }; | 307 | }; |
| 306 | static struct cfi_fixup fixup_table[] = { | 308 | static struct cfi_fixup fixup_table[] = { |
| @@ -1147,7 +1149,7 @@ static int inval_cache_and_wait_for_operation( | |||
| 1147 | struct cfi_private *cfi = map->fldrv_priv; | 1149 | struct cfi_private *cfi = map->fldrv_priv; |
| 1148 | map_word status, status_OK = CMD(0x80); | 1150 | map_word status, status_OK = CMD(0x80); |
| 1149 | int chip_state = chip->state; | 1151 | int chip_state = chip->state; |
| 1150 | unsigned int timeo, sleep_time; | 1152 | unsigned int timeo, sleep_time, reset_timeo; |
| 1151 | 1153 | ||
| 1152 | spin_unlock(chip->mutex); | 1154 | spin_unlock(chip->mutex); |
| 1153 | if (inval_len) | 1155 | if (inval_len) |
| @@ -1158,6 +1160,7 @@ static int inval_cache_and_wait_for_operation( | |||
| 1158 | timeo = chip_op_time * 8; | 1160 | timeo = chip_op_time * 8; |
| 1159 | if (!timeo) | 1161 | if (!timeo) |
| 1160 | timeo = 500000; | 1162 | timeo = 500000; |
| 1163 | reset_timeo = timeo; | ||
| 1161 | sleep_time = chip_op_time / 2; | 1164 | sleep_time = chip_op_time / 2; |
| 1162 | 1165 | ||
| 1163 | for (;;) { | 1166 | for (;;) { |
| @@ -1199,6 +1202,12 @@ static int inval_cache_and_wait_for_operation( | |||
| 1199 | remove_wait_queue(&chip->wq, &wait); | 1202 | remove_wait_queue(&chip->wq, &wait); |
| 1200 | spin_lock(chip->mutex); | 1203 | spin_lock(chip->mutex); |
| 1201 | } | 1204 | } |
| 1205 | if (chip->erase_suspended || chip->write_suspended) { | ||
| 1206 | /* Suspend has occured while sleep: reset timeout */ | ||
| 1207 | timeo = reset_timeo; | ||
| 1208 | chip->erase_suspended = 0; | ||
| 1209 | chip->write_suspended = 0; | ||
| 1210 | } | ||
| 1202 | } | 1211 | } |
| 1203 | 1212 | ||
| 1204 | /* Done and happy. */ | 1213 | /* Done and happy. */ |
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index f7fcc6389533..a972cc6be436 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c | |||
| @@ -16,9 +16,6 @@ | |||
| 16 | * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com | 16 | * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com |
| 17 | * | 17 | * |
| 18 | * This code is GPL | 18 | * This code is GPL |
| 19 | * | ||
| 20 | * $Id: cfi_cmdset_0002.c,v 1.122 2005/11/07 11:14:22 gleixner Exp $ | ||
| 21 | * | ||
| 22 | */ | 19 | */ |
| 23 | 20 | ||
| 24 | #include <linux/module.h> | 21 | #include <linux/module.h> |
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index 1b720cc571f3..d4714dd9f7ab 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c | |||
| @@ -4,8 +4,6 @@ | |||
| 4 | * | 4 | * |
| 5 | * (C) 2000 Red Hat. GPL'd | 5 | * (C) 2000 Red Hat. GPL'd |
| 6 | * | 6 | * |
| 7 | * $Id: cfi_cmdset_0020.c,v 1.22 2005/11/07 11:14:22 gleixner Exp $ | ||
| 8 | * | ||
| 9 | * 10/10/2000 Nicolas Pitre <nico@cam.org> | 7 | * 10/10/2000 Nicolas Pitre <nico@cam.org> |
| 10 | * - completely revamped method functions so they are aware and | 8 | * - completely revamped method functions so they are aware and |
| 11 | * independent of the flash geometry (buswidth, interleave, etc.) | 9 | * independent of the flash geometry (buswidth, interleave, etc.) |
diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c index a4463a91ce31..c418e92e1d92 100644 --- a/drivers/mtd/chips/cfi_probe.c +++ b/drivers/mtd/chips/cfi_probe.c | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | Common Flash Interface probe code. | 2 | Common Flash Interface probe code. |
| 3 | (C) 2000 Red Hat. GPL'd. | 3 | (C) 2000 Red Hat. GPL'd. |
| 4 | $Id: cfi_probe.c,v 1.86 2005/11/29 14:48:31 gleixner Exp $ | ||
| 5 | */ | 4 | */ |
| 6 | 5 | ||
| 7 | #include <linux/module.h> | 6 | #include <linux/module.h> |
diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c index 72e0022a47bf..0ee457018016 100644 --- a/drivers/mtd/chips/cfi_util.c +++ b/drivers/mtd/chips/cfi_util.c | |||
| @@ -6,9 +6,6 @@ | |||
| 6 | * Copyright (C) 2003 STMicroelectronics Limited | 6 | * Copyright (C) 2003 STMicroelectronics Limited |
| 7 | * | 7 | * |
| 8 | * This code is covered by the GPL. | 8 | * This code is covered by the GPL. |
| 9 | * | ||
| 10 | * $Id: cfi_util.c,v 1.10 2005/11/07 11:14:23 gleixner Exp $ | ||
| 11 | * | ||
| 12 | */ | 9 | */ |
| 13 | 10 | ||
| 14 | #include <linux/module.h> | 11 | #include <linux/module.h> |
diff --git a/drivers/mtd/chips/chipreg.c b/drivers/mtd/chips/chipreg.c index 2174c97549f0..c85760968227 100644 --- a/drivers/mtd/chips/chipreg.c +++ b/drivers/mtd/chips/chipreg.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: chipreg.c,v 1.17 2004/11/16 18:29:00 dwmw2 Exp $ | ||
| 3 | * | ||
| 4 | * Registration for chip drivers | 2 | * Registration for chip drivers |
| 5 | * | 3 | * |
| 6 | */ | 4 | */ |
diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c index d338b8c92780..f061885b2812 100644 --- a/drivers/mtd/chips/gen_probe.c +++ b/drivers/mtd/chips/gen_probe.c | |||
| @@ -2,7 +2,6 @@ | |||
| 2 | * Routines common to all CFI-type probes. | 2 | * Routines common to all CFI-type probes. |
| 3 | * (C) 2001-2003 Red Hat, Inc. | 3 | * (C) 2001-2003 Red Hat, Inc. |
| 4 | * GPL'd | 4 | * GPL'd |
| 5 | * $Id: gen_probe.c,v 1.24 2005/11/07 11:14:23 gleixner Exp $ | ||
| 6 | */ | 5 | */ |
| 7 | 6 | ||
| 8 | #include <linux/kernel.h> | 7 | #include <linux/kernel.h> |
| @@ -71,8 +70,8 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi | |||
| 71 | interleave and device type, etc. */ | 70 | interleave and device type, etc. */ |
| 72 | if (!genprobe_new_chip(map, cp, &cfi)) { | 71 | if (!genprobe_new_chip(map, cp, &cfi)) { |
| 73 | /* The probe didn't like it */ | 72 | /* The probe didn't like it */ |
| 74 | printk(KERN_DEBUG "%s: Found no %s device at location zero\n", | 73 | pr_debug("%s: Found no %s device at location zero\n", |
| 75 | cp->name, map->name); | 74 | cp->name, map->name); |
| 76 | return NULL; | 75 | return NULL; |
| 77 | } | 76 | } |
| 78 | 77 | ||
diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index aa07575eb288..dbba5abf0db8 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | Common Flash Interface probe code. | 2 | Common Flash Interface probe code. |
| 3 | (C) 2000 Red Hat. GPL'd. | 3 | (C) 2000 Red Hat. GPL'd. |
| 4 | $Id: jedec_probe.c,v 1.66 2005/11/07 11:14:23 gleixner Exp $ | ||
| 5 | See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5) | 4 | See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5) |
| 6 | for the standard this probe goes back to. | 5 | for the standard this probe goes back to. |
| 7 | 6 | ||
| @@ -26,6 +25,7 @@ | |||
| 26 | /* Manufacturers */ | 25 | /* Manufacturers */ |
| 27 | #define MANUFACTURER_AMD 0x0001 | 26 | #define MANUFACTURER_AMD 0x0001 |
| 28 | #define MANUFACTURER_ATMEL 0x001f | 27 | #define MANUFACTURER_ATMEL 0x001f |
| 28 | #define MANUFACTURER_EON 0x001c | ||
| 29 | #define MANUFACTURER_FUJITSU 0x0004 | 29 | #define MANUFACTURER_FUJITSU 0x0004 |
| 30 | #define MANUFACTURER_HYUNDAI 0x00AD | 30 | #define MANUFACTURER_HYUNDAI 0x00AD |
| 31 | #define MANUFACTURER_INTEL 0x0089 | 31 | #define MANUFACTURER_INTEL 0x0089 |
| @@ -37,6 +37,7 @@ | |||
| 37 | #define MANUFACTURER_ST 0x0020 | 37 | #define MANUFACTURER_ST 0x0020 |
| 38 | #define MANUFACTURER_TOSHIBA 0x0098 | 38 | #define MANUFACTURER_TOSHIBA 0x0098 |
| 39 | #define MANUFACTURER_WINBOND 0x00da | 39 | #define MANUFACTURER_WINBOND 0x00da |
| 40 | #define CONTINUATION_CODE 0x007f | ||
| 40 | 41 | ||
| 41 | 42 | ||
| 42 | /* AMD */ | 43 | /* AMD */ |
| @@ -58,6 +59,8 @@ | |||
| 58 | #define AM29LV040B 0x004F | 59 | #define AM29LV040B 0x004F |
| 59 | #define AM29F032B 0x0041 | 60 | #define AM29F032B 0x0041 |
| 60 | #define AM29F002T 0x00B0 | 61 | #define AM29F002T 0x00B0 |
| 62 | #define AM29SL800DB 0x226B | ||
| 63 | #define AM29SL800DT 0x22EA | ||
| 61 | 64 | ||
| 62 | /* Atmel */ | 65 | /* Atmel */ |
| 63 | #define AT49BV512 0x0003 | 66 | #define AT49BV512 0x0003 |
| @@ -67,6 +70,10 @@ | |||
| 67 | #define AT49BV32X 0x00C8 | 70 | #define AT49BV32X 0x00C8 |
| 68 | #define AT49BV32XT 0x00C9 | 71 | #define AT49BV32XT 0x00C9 |
| 69 | 72 | ||
| 73 | /* Eon */ | ||
| 74 | #define EN29SL800BB 0x226B | ||
| 75 | #define EN29SL800BT 0x22EA | ||
| 76 | |||
| 70 | /* Fujitsu */ | 77 | /* Fujitsu */ |
| 71 | #define MBM29F040C 0x00A4 | 78 | #define MBM29F040C 0x00A4 |
| 72 | #define MBM29F800BA 0x2258 | 79 | #define MBM29F800BA 0x2258 |
| @@ -141,6 +148,8 @@ | |||
| 141 | #define M50FW080 0x002D | 148 | #define M50FW080 0x002D |
| 142 | #define M50FW016 0x002E | 149 | #define M50FW016 0x002E |
| 143 | #define M50LPW080 0x002F | 150 | #define M50LPW080 0x002F |
| 151 | #define M50FLW080A 0x0080 | ||
| 152 | #define M50FLW080B 0x0081 | ||
| 144 | 153 | ||
| 145 | /* SST */ | 154 | /* SST */ |
| 146 | #define SST29EE020 0x0010 | 155 | #define SST29EE020 0x0010 |
| @@ -191,6 +200,7 @@ enum uaddr { | |||
| 191 | MTD_UADDR_0x0555_0x0AAA, | 200 | MTD_UADDR_0x0555_0x0AAA, |
| 192 | MTD_UADDR_0x5555_0x2AAA, | 201 | MTD_UADDR_0x5555_0x2AAA, |
| 193 | MTD_UADDR_0x0AAA_0x0555, | 202 | MTD_UADDR_0x0AAA_0x0555, |
| 203 | MTD_UADDR_0xAAAA_0x5555, | ||
| 194 | MTD_UADDR_DONT_CARE, /* Requires an arbitrary address */ | 204 | MTD_UADDR_DONT_CARE, /* Requires an arbitrary address */ |
| 195 | MTD_UADDR_UNNECESSARY, /* Does not require any address */ | 205 | MTD_UADDR_UNNECESSARY, /* Does not require any address */ |
| 196 | }; | 206 | }; |
| @@ -238,6 +248,11 @@ static const struct unlock_addr unlock_addrs[] = { | |||
| 238 | .addr2 = 0x0555 | 248 | .addr2 = 0x0555 |
| 239 | }, | 249 | }, |
| 240 | 250 | ||
| 251 | [MTD_UADDR_0xAAAA_0x5555] = { | ||
| 252 | .addr1 = 0xaaaa, | ||
| 253 | .addr2 = 0x5555 | ||
| 254 | }, | ||
| 255 | |||
| 241 | [MTD_UADDR_DONT_CARE] = { | 256 | [MTD_UADDR_DONT_CARE] = { |
| 242 | .addr1 = 0x0000, /* Doesn't matter which address */ | 257 | .addr1 = 0x0000, /* Doesn't matter which address */ |
| 243 | .addr2 = 0x0000 /* is used - must be last entry */ | 258 | .addr2 = 0x0000 /* is used - must be last entry */ |
| @@ -522,6 +537,36 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 522 | ERASEINFO(0x04000,1), | 537 | ERASEINFO(0x04000,1), |
| 523 | } | 538 | } |
| 524 | }, { | 539 | }, { |
| 540 | .mfr_id = MANUFACTURER_AMD, | ||
| 541 | .dev_id = AM29SL800DT, | ||
| 542 | .name = "AMD AM29SL800DT", | ||
| 543 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, | ||
| 544 | .uaddr = MTD_UADDR_0x0AAA_0x0555, | ||
| 545 | .dev_size = SIZE_1MiB, | ||
| 546 | .cmd_set = P_ID_AMD_STD, | ||
| 547 | .nr_regions = 4, | ||
| 548 | .regions = { | ||
| 549 | ERASEINFO(0x10000,15), | ||
| 550 | ERASEINFO(0x08000,1), | ||
| 551 | ERASEINFO(0x02000,2), | ||
| 552 | ERASEINFO(0x04000,1), | ||
| 553 | } | ||
| 554 | }, { | ||
| 555 | .mfr_id = MANUFACTURER_AMD, | ||
| 556 | .dev_id = AM29SL800DB, | ||
| 557 | .name = "AMD AM29SL800DB", | ||
| 558 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, | ||
| 559 | .uaddr = MTD_UADDR_0x0AAA_0x0555, | ||
| 560 | .dev_size = SIZE_1MiB, | ||
| 561 | .cmd_set = P_ID_AMD_STD, | ||
| 562 | .nr_regions = 4, | ||
| 563 | .regions = { | ||
| 564 | ERASEINFO(0x04000,1), | ||
| 565 | ERASEINFO(0x02000,2), | ||
| 566 | ERASEINFO(0x08000,1), | ||
| 567 | ERASEINFO(0x10000,15), | ||
| 568 | } | ||
| 569 | }, { | ||
| 525 | .mfr_id = MANUFACTURER_ATMEL, | 570 | .mfr_id = MANUFACTURER_ATMEL, |
| 526 | .dev_id = AT49BV512, | 571 | .dev_id = AT49BV512, |
| 527 | .name = "Atmel AT49BV512", | 572 | .name = "Atmel AT49BV512", |
| @@ -599,6 +644,36 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 599 | ERASEINFO(0x02000,8) | 644 | ERASEINFO(0x02000,8) |
| 600 | } | 645 | } |
| 601 | }, { | 646 | }, { |
| 647 | .mfr_id = MANUFACTURER_EON, | ||
| 648 | .dev_id = EN29SL800BT, | ||
| 649 | .name = "Eon EN29SL800BT", | ||
| 650 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, | ||
| 651 | .uaddr = MTD_UADDR_0x0AAA_0x0555, | ||
| 652 | .dev_size = SIZE_1MiB, | ||
| 653 | .cmd_set = P_ID_AMD_STD, | ||
| 654 | .nr_regions = 4, | ||
| 655 | .regions = { | ||
| 656 | ERASEINFO(0x10000,15), | ||
| 657 | ERASEINFO(0x08000,1), | ||
| 658 | ERASEINFO(0x02000,2), | ||
| 659 | ERASEINFO(0x04000,1), | ||
| 660 | } | ||
| 661 | }, { | ||
| 662 | .mfr_id = MANUFACTURER_EON, | ||
| 663 | .dev_id = EN29SL800BB, | ||
| 664 | .name = "Eon EN29SL800BB", | ||
| 665 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, | ||
| 666 | .uaddr = MTD_UADDR_0x0AAA_0x0555, | ||
| 667 | .dev_size = SIZE_1MiB, | ||
| 668 | .cmd_set = P_ID_AMD_STD, | ||
| 669 | .nr_regions = 4, | ||
| 670 | .regions = { | ||
| 671 | ERASEINFO(0x04000,1), | ||
| 672 | ERASEINFO(0x02000,2), | ||
| 673 | ERASEINFO(0x08000,1), | ||
| 674 | ERASEINFO(0x10000,15), | ||
| 675 | } | ||
| 676 | }, { | ||
| 602 | .mfr_id = MANUFACTURER_FUJITSU, | 677 | .mfr_id = MANUFACTURER_FUJITSU, |
| 603 | .dev_id = MBM29F040C, | 678 | .dev_id = MBM29F040C, |
| 604 | .name = "Fujitsu MBM29F040C", | 679 | .name = "Fujitsu MBM29F040C", |
| @@ -1392,8 +1467,8 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1392 | .mfr_id = MANUFACTURER_SST, /* should be CFI */ | 1467 | .mfr_id = MANUFACTURER_SST, /* should be CFI */ |
| 1393 | .dev_id = SST39LF160, | 1468 | .dev_id = SST39LF160, |
| 1394 | .name = "SST 39LF160", | 1469 | .name = "SST 39LF160", |
| 1395 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, | 1470 | .devtypes = CFI_DEVICETYPE_X16, |
| 1396 | .uaddr = MTD_UADDR_0x5555_0x2AAA, /* ???? */ | 1471 | .uaddr = MTD_UADDR_0xAAAA_0x5555, |
| 1397 | .dev_size = SIZE_2MiB, | 1472 | .dev_size = SIZE_2MiB, |
| 1398 | .cmd_set = P_ID_AMD_STD, | 1473 | .cmd_set = P_ID_AMD_STD, |
| 1399 | .nr_regions = 2, | 1474 | .nr_regions = 2, |
| @@ -1405,8 +1480,8 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1405 | .mfr_id = MANUFACTURER_SST, /* should be CFI */ | 1480 | .mfr_id = MANUFACTURER_SST, /* should be CFI */ |
| 1406 | .dev_id = SST39VF1601, | 1481 | .dev_id = SST39VF1601, |
| 1407 | .name = "SST 39VF1601", | 1482 | .name = "SST 39VF1601", |
| 1408 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, | 1483 | .devtypes = CFI_DEVICETYPE_X16, |
| 1409 | .uaddr = MTD_UADDR_0x5555_0x2AAA, /* ???? */ | 1484 | .uaddr = MTD_UADDR_0xAAAA_0x5555, |
| 1410 | .dev_size = SIZE_2MiB, | 1485 | .dev_size = SIZE_2MiB, |
| 1411 | .cmd_set = P_ID_AMD_STD, | 1486 | .cmd_set = P_ID_AMD_STD, |
| 1412 | .nr_regions = 2, | 1487 | .nr_regions = 2, |
| @@ -1590,6 +1665,36 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1590 | .nr_regions = 1, | 1665 | .nr_regions = 1, |
| 1591 | .regions = { | 1666 | .regions = { |
| 1592 | ERASEINFO(0x10000,16), | 1667 | ERASEINFO(0x10000,16), |
| 1668 | }, | ||
| 1669 | }, { | ||
| 1670 | .mfr_id = MANUFACTURER_ST, | ||
| 1671 | .dev_id = M50FLW080A, | ||
| 1672 | .name = "ST M50FLW080A", | ||
| 1673 | .devtypes = CFI_DEVICETYPE_X8, | ||
| 1674 | .uaddr = MTD_UADDR_UNNECESSARY, | ||
| 1675 | .dev_size = SIZE_1MiB, | ||
| 1676 | .cmd_set = P_ID_INTEL_EXT, | ||
| 1677 | .nr_regions = 4, | ||
| 1678 | .regions = { | ||
| 1679 | ERASEINFO(0x1000,16), | ||
| 1680 | ERASEINFO(0x10000,13), | ||
| 1681 | ERASEINFO(0x1000,16), | ||
| 1682 | ERASEINFO(0x1000,16), | ||
| 1683 | } | ||
| 1684 | }, { | ||
| 1685 | .mfr_id = MANUFACTURER_ST, | ||
| 1686 | .dev_id = M50FLW080B, | ||
| 1687 | .name = "ST M50FLW080B", | ||
| 1688 | .devtypes = CFI_DEVICETYPE_X8, | ||
| 1689 | .uaddr = MTD_UADDR_UNNECESSARY, | ||
| 1690 | .dev_size = SIZE_1MiB, | ||
| 1691 | .cmd_set = P_ID_INTEL_EXT, | ||
| 1692 | .nr_regions = 4, | ||
| 1693 | .regions = { | ||
| 1694 | ERASEINFO(0x1000,16), | ||
| 1695 | ERASEINFO(0x1000,16), | ||
| 1696 | ERASEINFO(0x10000,13), | ||
| 1697 | ERASEINFO(0x1000,16), | ||
| 1593 | } | 1698 | } |
| 1594 | }, { | 1699 | }, { |
| 1595 | .mfr_id = MANUFACTURER_TOSHIBA, | 1700 | .mfr_id = MANUFACTURER_TOSHIBA, |
| @@ -1696,9 +1801,21 @@ static inline u32 jedec_read_mfr(struct map_info *map, uint32_t base, | |||
| 1696 | { | 1801 | { |
| 1697 | map_word result; | 1802 | map_word result; |
| 1698 | unsigned long mask; | 1803 | unsigned long mask; |
| 1699 | u32 ofs = cfi_build_cmd_addr(0, cfi_interleave(cfi), cfi->device_type); | 1804 | int bank = 0; |
| 1700 | mask = (1 << (cfi->device_type * 8)) -1; | 1805 | |
| 1701 | result = map_read(map, base + ofs); | 1806 | /* According to JEDEC "Standard Manufacturer's Identification Code" |
| 1807 | * (http://www.jedec.org/download/search/jep106W.pdf) | ||
| 1808 | * several first banks can contain 0x7f instead of actual ID | ||
| 1809 | */ | ||
| 1810 | do { | ||
| 1811 | uint32_t ofs = cfi_build_cmd_addr(0 + (bank << 8), | ||
| 1812 | cfi_interleave(cfi), | ||
| 1813 | cfi->device_type); | ||
| 1814 | mask = (1 << (cfi->device_type * 8)) - 1; | ||
| 1815 | result = map_read(map, base + ofs); | ||
| 1816 | bank++; | ||
| 1817 | } while ((result.x[0] & mask) == CONTINUATION_CODE); | ||
| 1818 | |||
| 1702 | return result.x[0] & mask; | 1819 | return result.x[0] & mask; |
| 1703 | } | 1820 | } |
| 1704 | 1821 | ||
diff --git a/drivers/mtd/chips/map_absent.c b/drivers/mtd/chips/map_absent.c index fc478c0f93f5..494d30d0631a 100644 --- a/drivers/mtd/chips/map_absent.c +++ b/drivers/mtd/chips/map_absent.c | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Common code to handle absent "placeholder" devices | 2 | * Common code to handle absent "placeholder" devices |
| 3 | * Copyright 2001 Resilience Corporation <ebrower@resilience.com> | 3 | * Copyright 2001 Resilience Corporation <ebrower@resilience.com> |
| 4 | * $Id: map_absent.c,v 1.6 2005/11/07 11:14:23 gleixner Exp $ | ||
| 5 | * | 4 | * |
| 6 | * This map driver is used to allocate "placeholder" MTD | 5 | * This map driver is used to allocate "placeholder" MTD |
| 7 | * devices on systems that have socketed/removable media. | 6 | * devices on systems that have socketed/removable media. |
diff --git a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c index 5cb6d5263661..072dd8abf33a 100644 --- a/drivers/mtd/chips/map_ram.c +++ b/drivers/mtd/chips/map_ram.c | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Common code to handle map devices which are simple RAM | 2 | * Common code to handle map devices which are simple RAM |
| 3 | * (C) 2000 Red Hat. GPL'd. | 3 | * (C) 2000 Red Hat. GPL'd. |
| 4 | * $Id: map_ram.c,v 1.22 2005/01/05 18:05:12 dwmw2 Exp $ | ||
| 5 | */ | 4 | */ |
| 6 | 5 | ||
| 7 | #include <linux/module.h> | 6 | #include <linux/module.h> |
diff --git a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c index cb27f855074c..821d0ed6bae3 100644 --- a/drivers/mtd/chips/map_rom.c +++ b/drivers/mtd/chips/map_rom.c | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Common code to handle map devices which are simple ROM | 2 | * Common code to handle map devices which are simple ROM |
| 3 | * (C) 2000 Red Hat. GPL'd. | 3 | * (C) 2000 Red Hat. GPL'd. |
| 4 | * $Id: map_rom.c,v 1.23 2005/01/05 18:05:12 dwmw2 Exp $ | ||
| 5 | */ | 4 | */ |
| 6 | 5 | ||
| 7 | #include <linux/module.h> | 6 | #include <linux/module.h> |
diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index e472a0e9de9d..71bc07f149b7 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: cmdlinepart.c,v 1.19 2005/11/07 11:14:19 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * Read flash partition table from command line | 2 | * Read flash partition table from command line |
| 5 | * | 3 | * |
| 6 | * Copyright 2002 SYSGO Real-Time Solutions GmbH | 4 | * Copyright 2002 SYSGO Real-Time Solutions GmbH |
| @@ -308,7 +306,7 @@ static int parse_cmdline_partitions(struct mtd_info *master, | |||
| 308 | unsigned long offset; | 306 | unsigned long offset; |
| 309 | int i; | 307 | int i; |
| 310 | struct cmdline_mtd_partition *part; | 308 | struct cmdline_mtd_partition *part; |
| 311 | char *mtd_id = master->name; | 309 | const char *mtd_id = master->name; |
| 312 | 310 | ||
| 313 | /* parse command line */ | 311 | /* parse command line */ |
| 314 | if (!cmdline_parsed) | 312 | if (!cmdline_parsed) |
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 35ed1103dbb2..9c613f06623c 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | # drivers/mtd/maps/Kconfig | 1 | # drivers/mtd/maps/Kconfig |
| 2 | # $Id: Kconfig,v 1.18 2005/11/07 11:14:24 gleixner Exp $ | ||
| 3 | 2 | ||
| 4 | menu "Self-contained MTD device drivers" | 3 | menu "Self-contained MTD device drivers" |
| 5 | depends on MTD!=n | 4 | depends on MTD!=n |
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index 0f788d5c4bf8..0993d5cf3923 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | # | 1 | # |
| 2 | # linux/drivers/devices/Makefile | 2 | # linux/drivers/devices/Makefile |
| 3 | # | 3 | # |
| 4 | # $Id: Makefile.common,v 1.7 2004/12/22 17:51:15 joern Exp $ | ||
| 5 | 4 | ||
| 6 | obj-$(CONFIG_MTD_DOC2000) += doc2000.o | 5 | obj-$(CONFIG_MTD_DOC2000) += doc2000.o |
| 7 | obj-$(CONFIG_MTD_DOC2001) += doc2001.o | 6 | obj-$(CONFIG_MTD_DOC2001) += doc2001.o |
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 7b72a1b36115..91fbba767635 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: block2mtd.c,v 1.30 2005/11/29 14:48:32 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * block2mtd.c - create an mtd from a block device | 2 | * block2mtd.c - create an mtd from a block device |
| 5 | * | 3 | * |
| 6 | * Copyright (C) 2001,2002 Simon Evans <spse@secret.org.uk> | 4 | * Copyright (C) 2001,2002 Simon Evans <spse@secret.org.uk> |
| @@ -20,9 +18,6 @@ | |||
| 20 | #include <linux/mutex.h> | 18 | #include <linux/mutex.h> |
| 21 | #include <linux/mount.h> | 19 | #include <linux/mount.h> |
| 22 | 20 | ||
| 23 | #define VERSION "$Revision: 1.30 $" | ||
| 24 | |||
| 25 | |||
| 26 | #define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args) | 21 | #define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args) |
| 27 | #define INFO(fmt, args...) printk(KERN_INFO "block2mtd: " fmt "\n" , ## args) | 22 | #define INFO(fmt, args...) printk(KERN_INFO "block2mtd: " fmt "\n" , ## args) |
| 28 | 23 | ||
| @@ -453,7 +448,6 @@ MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>]\""); | |||
| 453 | static int __init block2mtd_init(void) | 448 | static int __init block2mtd_init(void) |
| 454 | { | 449 | { |
| 455 | int ret = 0; | 450 | int ret = 0; |
| 456 | INFO("version " VERSION); | ||
| 457 | 451 | ||
| 458 | #ifndef MODULE | 452 | #ifndef MODULE |
| 459 | if (strlen(block2mtd_paramline)) | 453 | if (strlen(block2mtd_paramline)) |
diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c index 846989f292e3..50de839c77a9 100644 --- a/drivers/mtd/devices/doc2000.c +++ b/drivers/mtd/devices/doc2000.c | |||
| @@ -3,8 +3,6 @@ | |||
| 3 | * Linux driver for Disk-On-Chip 2000 and Millennium | 3 | * Linux driver for Disk-On-Chip 2000 and Millennium |
| 4 | * (c) 1999 Machine Vision Holdings, Inc. | 4 | * (c) 1999 Machine Vision Holdings, Inc. |
| 5 | * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> | 5 | * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> |
| 6 | * | ||
| 7 | * $Id: doc2000.c,v 1.67 2005/11/07 11:14:24 gleixner Exp $ | ||
| 8 | */ | 6 | */ |
| 9 | 7 | ||
| 10 | #include <linux/kernel.h> | 8 | #include <linux/kernel.h> |
diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c index 6413efc045e0..e32c568c1145 100644 --- a/drivers/mtd/devices/doc2001.c +++ b/drivers/mtd/devices/doc2001.c | |||
| @@ -3,8 +3,6 @@ | |||
| 3 | * Linux driver for Disk-On-Chip Millennium | 3 | * Linux driver for Disk-On-Chip Millennium |
| 4 | * (c) 1999 Machine Vision Holdings, Inc. | 4 | * (c) 1999 Machine Vision Holdings, Inc. |
| 5 | * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> | 5 | * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> |
| 6 | * | ||
| 7 | * $Id: doc2001.c,v 1.49 2005/11/07 11:14:24 gleixner Exp $ | ||
| 8 | */ | 6 | */ |
| 9 | 7 | ||
| 10 | #include <linux/kernel.h> | 8 | #include <linux/kernel.h> |
diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index 83be3461658f..d853f891b586 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c | |||
| @@ -6,8 +6,6 @@ | |||
| 6 | * (c) 1999 Machine Vision Holdings, Inc. | 6 | * (c) 1999 Machine Vision Holdings, Inc. |
| 7 | * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> | 7 | * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> |
| 8 | * | 8 | * |
| 9 | * $Id: doc2001plus.c,v 1.14 2005/11/07 11:14:24 gleixner Exp $ | ||
| 10 | * | ||
| 11 | * Released under GPL | 9 | * Released under GPL |
| 12 | */ | 10 | */ |
| 13 | 11 | ||
diff --git a/drivers/mtd/devices/docecc.c b/drivers/mtd/devices/docecc.c index fd8a8daba3a8..874e51b110a2 100644 --- a/drivers/mtd/devices/docecc.c +++ b/drivers/mtd/devices/docecc.c | |||
| @@ -7,8 +7,6 @@ | |||
| 7 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) | 7 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) |
| 8 | * Copyright (C) 2000 Netgem S.A. | 8 | * Copyright (C) 2000 Netgem S.A. |
| 9 | * | 9 | * |
| 10 | * $Id: docecc.c,v 1.7 2005/11/07 11:14:25 gleixner Exp $ | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
| 13 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
| 14 | * the Free Software Foundation; either version 2 of the License, or | 12 | * the Free Software Foundation; either version 2 of the License, or |
diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c index d8cc94ec4e50..6e62922942b1 100644 --- a/drivers/mtd/devices/docprobe.c +++ b/drivers/mtd/devices/docprobe.c | |||
| @@ -4,9 +4,6 @@ | |||
| 4 | /* (C) 1999 Machine Vision Holdings, Inc. */ | 4 | /* (C) 1999 Machine Vision Holdings, Inc. */ |
| 5 | /* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> */ | 5 | /* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> */ |
| 6 | 6 | ||
| 7 | /* $Id: docprobe.c,v 1.46 2005/11/07 11:14:25 gleixner Exp $ */ | ||
| 8 | |||
| 9 | |||
| 10 | 7 | ||
| 11 | /* DOC_PASSIVE_PROBE: | 8 | /* DOC_PASSIVE_PROBE: |
| 12 | In order to ensure that the BIOS checksum is correct at boot time, and | 9 | In order to ensure that the BIOS checksum is correct at boot time, and |
| @@ -79,8 +76,6 @@ static unsigned long __initdata doc_locations[] = { | |||
| 79 | 0xe0000, 0xe2000, 0xe4000, 0xe6000, | 76 | 0xe0000, 0xe2000, 0xe4000, 0xe6000, |
| 80 | 0xe8000, 0xea000, 0xec000, 0xee000, | 77 | 0xe8000, 0xea000, 0xec000, 0xee000, |
| 81 | #endif /* CONFIG_MTD_DOCPROBE_HIGH */ | 78 | #endif /* CONFIG_MTD_DOCPROBE_HIGH */ |
| 82 | #elif defined(__PPC__) | ||
| 83 | 0xe4000000, | ||
| 84 | #else | 79 | #else |
| 85 | #warning Unknown architecture for DiskOnChip. No default probe locations defined | 80 | #warning Unknown architecture for DiskOnChip. No default probe locations defined |
| 86 | #endif | 81 | #endif |
diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c index 1d324e5c412d..f4bda4cee495 100644 --- a/drivers/mtd/devices/lart.c +++ b/drivers/mtd/devices/lart.c | |||
| @@ -2,8 +2,6 @@ | |||
| 2 | /* | 2 | /* |
| 3 | * MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART. | 3 | * MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART. |
| 4 | * | 4 | * |
| 5 | * $Id: lart.c,v 1.9 2005/11/07 11:14:25 gleixner Exp $ | ||
| 6 | * | ||
| 7 | * Author: Abraham vd Merwe <abraham@2d3d.co.za> | 5 | * Author: Abraham vd Merwe <abraham@2d3d.co.za> |
| 8 | * | 6 | * |
| 9 | * Copyright (c) 2001, 2d3D, Inc. | 7 | * Copyright (c) 2001, 2d3D, Inc. |
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index b402269301f6..b35c3333e210 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | /* Flash opcodes. */ | 33 | /* Flash opcodes. */ |
| 34 | #define OPCODE_WREN 0x06 /* Write enable */ | 34 | #define OPCODE_WREN 0x06 /* Write enable */ |
| 35 | #define OPCODE_RDSR 0x05 /* Read status register */ | 35 | #define OPCODE_RDSR 0x05 /* Read status register */ |
| 36 | #define OPCODE_WRSR 0x01 /* Write status register 1 byte */ | ||
| 36 | #define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */ | 37 | #define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */ |
| 37 | #define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ | 38 | #define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ |
| 38 | #define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ | 39 | #define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ |
| @@ -112,6 +113,17 @@ static int read_sr(struct m25p *flash) | |||
| 112 | return val; | 113 | return val; |
| 113 | } | 114 | } |
| 114 | 115 | ||
| 116 | /* | ||
| 117 | * Write status register 1 byte | ||
| 118 | * Returns negative if error occurred. | ||
| 119 | */ | ||
| 120 | static int write_sr(struct m25p *flash, u8 val) | ||
| 121 | { | ||
| 122 | flash->command[0] = OPCODE_WRSR; | ||
| 123 | flash->command[1] = val; | ||
| 124 | |||
| 125 | return spi_write(flash->spi, flash->command, 2); | ||
| 126 | } | ||
| 115 | 127 | ||
| 116 | /* | 128 | /* |
| 117 | * Set write enable latch with Write Enable command. | 129 | * Set write enable latch with Write Enable command. |
| @@ -589,6 +601,16 @@ static int __devinit m25p_probe(struct spi_device *spi) | |||
| 589 | mutex_init(&flash->lock); | 601 | mutex_init(&flash->lock); |
| 590 | dev_set_drvdata(&spi->dev, flash); | 602 | dev_set_drvdata(&spi->dev, flash); |
| 591 | 603 | ||
| 604 | /* | ||
| 605 | * Atmel serial flash tend to power up | ||
| 606 | * with the software protection bits set | ||
| 607 | */ | ||
| 608 | |||
| 609 | if (info->jedec_id >> 16 == 0x1f) { | ||
| 610 | write_enable(flash); | ||
| 611 | write_sr(flash, 0); | ||
| 612 | } | ||
| 613 | |||
| 592 | if (data && data->name) | 614 | if (data && data->name) |
| 593 | flash->mtd.name = data->name; | 615 | flash->mtd.name = data->name; |
| 594 | else | 616 | else |
diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c index 9cff119a2024..6a9a24a80a6d 100644 --- a/drivers/mtd/devices/ms02-nv.c +++ b/drivers/mtd/devices/ms02-nv.c | |||
| @@ -5,8 +5,6 @@ | |||
| 5 | * modify it under the terms of the GNU General Public License | 5 | * modify it under the terms of the GNU General Public License |
| 6 | * as published by the Free Software Foundation; either version | 6 | * as published by the Free Software Foundation; either version |
| 7 | * 2 of the License, or (at your option) any later version. | 7 | * 2 of the License, or (at your option) any later version. |
| 8 | * | ||
| 9 | * $Id: ms02-nv.c,v 1.11 2005/11/14 13:41:47 macro Exp $ | ||
| 10 | */ | 8 | */ |
| 11 | 9 | ||
| 12 | #include <linux/init.h> | 10 | #include <linux/init.h> |
diff --git a/drivers/mtd/devices/ms02-nv.h b/drivers/mtd/devices/ms02-nv.h index 8a6eef7cfee3..04deafd3a771 100644 --- a/drivers/mtd/devices/ms02-nv.h +++ b/drivers/mtd/devices/ms02-nv.h | |||
| @@ -9,8 +9,6 @@ | |||
| 9 | * modify it under the terms of the GNU General Public License | 9 | * modify it under the terms of the GNU General Public License |
| 10 | * as published by the Free Software Foundation; either version | 10 | * as published by the Free Software Foundation; either version |
| 11 | * 2 of the License, or (at your option) any later version. | 11 | * 2 of the License, or (at your option) any later version. |
| 12 | * | ||
| 13 | * $Id: ms02-nv.h,v 1.3 2003/08/19 09:25:36 dwmw2 Exp $ | ||
| 14 | */ | 12 | */ |
| 15 | 13 | ||
| 16 | #include <linux/ioport.h> | 14 | #include <linux/ioport.h> |
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index b35e4813a3a5..54e36bfc2c3b 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c | |||
| @@ -82,7 +82,7 @@ | |||
| 82 | 82 | ||
| 83 | 83 | ||
| 84 | struct dataflash { | 84 | struct dataflash { |
| 85 | u8 command[4]; | 85 | uint8_t command[4]; |
| 86 | char name[24]; | 86 | char name[24]; |
| 87 | 87 | ||
| 88 | unsigned partitioned:1; | 88 | unsigned partitioned:1; |
| @@ -150,7 +150,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
| 150 | struct spi_transfer x = { .tx_dma = 0, }; | 150 | struct spi_transfer x = { .tx_dma = 0, }; |
| 151 | struct spi_message msg; | 151 | struct spi_message msg; |
| 152 | unsigned blocksize = priv->page_size << 3; | 152 | unsigned blocksize = priv->page_size << 3; |
| 153 | u8 *command; | 153 | uint8_t *command; |
| 154 | 154 | ||
| 155 | DEBUG(MTD_DEBUG_LEVEL2, "%s: erase addr=0x%x len 0x%x\n", | 155 | DEBUG(MTD_DEBUG_LEVEL2, "%s: erase addr=0x%x len 0x%x\n", |
| 156 | spi->dev.bus_id, | 156 | spi->dev.bus_id, |
| @@ -182,8 +182,8 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
| 182 | pageaddr = pageaddr << priv->page_offset; | 182 | pageaddr = pageaddr << priv->page_offset; |
| 183 | 183 | ||
| 184 | command[0] = do_block ? OP_ERASE_BLOCK : OP_ERASE_PAGE; | 184 | command[0] = do_block ? OP_ERASE_BLOCK : OP_ERASE_PAGE; |
| 185 | command[1] = (u8)(pageaddr >> 16); | 185 | command[1] = (uint8_t)(pageaddr >> 16); |
| 186 | command[2] = (u8)(pageaddr >> 8); | 186 | command[2] = (uint8_t)(pageaddr >> 8); |
| 187 | command[3] = 0; | 187 | command[3] = 0; |
| 188 | 188 | ||
| 189 | DEBUG(MTD_DEBUG_LEVEL3, "ERASE %s: (%x) %x %x %x [%i]\n", | 189 | DEBUG(MTD_DEBUG_LEVEL3, "ERASE %s: (%x) %x %x %x [%i]\n", |
| @@ -234,7 +234,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
| 234 | struct spi_transfer x[2] = { { .tx_dma = 0, }, }; | 234 | struct spi_transfer x[2] = { { .tx_dma = 0, }, }; |
| 235 | struct spi_message msg; | 235 | struct spi_message msg; |
| 236 | unsigned int addr; | 236 | unsigned int addr; |
| 237 | u8 *command; | 237 | uint8_t *command; |
| 238 | int status; | 238 | int status; |
| 239 | 239 | ||
| 240 | DEBUG(MTD_DEBUG_LEVEL2, "%s: read 0x%x..0x%x\n", | 240 | DEBUG(MTD_DEBUG_LEVEL2, "%s: read 0x%x..0x%x\n", |
| @@ -274,9 +274,9 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
| 274 | * fewer "don't care" bytes. Both buffers stay unchanged. | 274 | * fewer "don't care" bytes. Both buffers stay unchanged. |
| 275 | */ | 275 | */ |
| 276 | command[0] = OP_READ_CONTINUOUS; | 276 | command[0] = OP_READ_CONTINUOUS; |
| 277 | command[1] = (u8)(addr >> 16); | 277 | command[1] = (uint8_t)(addr >> 16); |
| 278 | command[2] = (u8)(addr >> 8); | 278 | command[2] = (uint8_t)(addr >> 8); |
| 279 | command[3] = (u8)(addr >> 0); | 279 | command[3] = (uint8_t)(addr >> 0); |
| 280 | /* plus 4 "don't care" bytes */ | 280 | /* plus 4 "don't care" bytes */ |
| 281 | 281 | ||
| 282 | status = spi_sync(priv->spi, &msg); | 282 | status = spi_sync(priv->spi, &msg); |
| @@ -311,7 +311,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
| 311 | size_t remaining = len; | 311 | size_t remaining = len; |
| 312 | u_char *writebuf = (u_char *) buf; | 312 | u_char *writebuf = (u_char *) buf; |
| 313 | int status = -EINVAL; | 313 | int status = -EINVAL; |
| 314 | u8 *command; | 314 | uint8_t *command; |
| 315 | 315 | ||
| 316 | DEBUG(MTD_DEBUG_LEVEL2, "%s: write 0x%x..0x%x\n", | 316 | DEBUG(MTD_DEBUG_LEVEL2, "%s: write 0x%x..0x%x\n", |
| 317 | spi->dev.bus_id, (unsigned)to, (unsigned)(to + len)); | 317 | spi->dev.bus_id, (unsigned)to, (unsigned)(to + len)); |
| @@ -487,7 +487,9 @@ add_dataflash(struct spi_device *spi, char *name, | |||
| 487 | device->write = dataflash_write; | 487 | device->write = dataflash_write; |
| 488 | device->priv = priv; | 488 | device->priv = priv; |
| 489 | 489 | ||
| 490 | dev_info(&spi->dev, "%s (%d KBytes)\n", name, device->size/1024); | 490 | dev_info(&spi->dev, "%s (%d KBytes) pagesize %d bytes, " |
| 491 | "erasesize %d bytes\n", name, device->size/1024, | ||
| 492 | pagesize, pagesize * 8); /* 8 pages = 1 block */ | ||
| 491 | dev_set_drvdata(&spi->dev, priv); | 493 | dev_set_drvdata(&spi->dev, priv); |
| 492 | 494 | ||
| 493 | if (mtd_has_partitions()) { | 495 | if (mtd_has_partitions()) { |
| @@ -521,7 +523,7 @@ add_dataflash(struct spi_device *spi, char *name, | |||
| 521 | * | 523 | * |
| 522 | * Device Density ID code #Pages PageSize Offset | 524 | * Device Density ID code #Pages PageSize Offset |
| 523 | * AT45DB011B 1Mbit (128K) xx0011xx (0x0c) 512 264 9 | 525 | * AT45DB011B 1Mbit (128K) xx0011xx (0x0c) 512 264 9 |
| 524 | * AT45DB021B 2Mbit (256K) xx0101xx (0x14) 1025 264 9 | 526 | * AT45DB021B 2Mbit (256K) xx0101xx (0x14) 1024 264 9 |
| 525 | * AT45DB041B 4Mbit (512K) xx0111xx (0x1c) 2048 264 9 | 527 | * AT45DB041B 4Mbit (512K) xx0111xx (0x1c) 2048 264 9 |
| 526 | * AT45DB081B 8Mbit (1M) xx1001xx (0x24) 4096 264 9 | 528 | * AT45DB081B 8Mbit (1M) xx1001xx (0x24) 4096 264 9 |
| 527 | * AT45DB0161B 16Mbit (2M) xx1011xx (0x2c) 4096 528 10 | 529 | * AT45DB0161B 16Mbit (2M) xx1011xx (0x2c) 4096 528 10 |
| @@ -529,9 +531,114 @@ add_dataflash(struct spi_device *spi, char *name, | |||
| 529 | * AT45DB0642 64Mbit (8M) xx111xxx (0x3c) 8192 1056 11 | 531 | * AT45DB0642 64Mbit (8M) xx111xxx (0x3c) 8192 1056 11 |
| 530 | * AT45DB1282 128Mbit (16M) xx0100xx (0x10) 16384 1056 11 | 532 | * AT45DB1282 128Mbit (16M) xx0100xx (0x10) 16384 1056 11 |
| 531 | */ | 533 | */ |
| 534 | |||
| 535 | struct flash_info { | ||
| 536 | char *name; | ||
| 537 | |||
| 538 | /* JEDEC id zero means "no ID" (most older chips); otherwise it has | ||
| 539 | * a high byte of zero plus three data bytes: the manufacturer id, | ||
| 540 | * then a two byte device id. | ||
| 541 | */ | ||
| 542 | uint32_t jedec_id; | ||
| 543 | |||
| 544 | /* The size listed here is what works with OPCODE_SE, which isn't | ||
| 545 | * necessarily called a "sector" by the vendor. | ||
| 546 | */ | ||
| 547 | unsigned nr_pages; | ||
| 548 | uint16_t pagesize; | ||
| 549 | uint16_t pageoffset; | ||
| 550 | |||
| 551 | uint16_t flags; | ||
| 552 | #define SUP_POW2PS 0x02 | ||
| 553 | #define IS_POW2PS 0x01 | ||
| 554 | }; | ||
| 555 | |||
| 556 | static struct flash_info __devinitdata dataflash_data [] = { | ||
| 557 | |||
| 558 | { "at45db011d", 0x1f2200, 512, 264, 9, SUP_POW2PS}, | ||
| 559 | { "at45db011d", 0x1f2200, 512, 256, 8, SUP_POW2PS | IS_POW2PS}, | ||
| 560 | |||
| 561 | { "at45db021d", 0x1f2300, 1024, 264, 9, SUP_POW2PS}, | ||
| 562 | { "at45db021d", 0x1f2300, 1024, 256, 8, SUP_POW2PS | IS_POW2PS}, | ||
| 563 | |||
| 564 | { "at45db041d", 0x1f2400, 2048, 264, 9, SUP_POW2PS}, | ||
| 565 | { "at45db041d", 0x1f2400, 2048, 256, 8, SUP_POW2PS | IS_POW2PS}, | ||
| 566 | |||
| 567 | { "at45db081d", 0x1f2500, 4096, 264, 9, SUP_POW2PS}, | ||
| 568 | { "at45db081d", 0x1f2500, 4096, 256, 8, SUP_POW2PS | IS_POW2PS}, | ||
| 569 | |||
| 570 | { "at45db161d", 0x1f2600, 4096, 528, 10, SUP_POW2PS}, | ||
| 571 | { "at45db161d", 0x1f2600, 4096, 512, 9, SUP_POW2PS | IS_POW2PS}, | ||
| 572 | |||
| 573 | { "at45db321c", 0x1f2700, 8192, 528, 10, }, | ||
| 574 | |||
| 575 | { "at45db321d", 0x1f2701, 8192, 528, 10, SUP_POW2PS}, | ||
| 576 | { "at45db321d", 0x1f2701, 8192, 512, 9, SUP_POW2PS | IS_POW2PS}, | ||
| 577 | |||
| 578 | { "at45db641d", 0x1f2800, 8192, 1056, 11, SUP_POW2PS}, | ||
| 579 | { "at45db641d", 0x1f2800, 8192, 1024, 10, SUP_POW2PS | IS_POW2PS}, | ||
| 580 | }; | ||
| 581 | |||
| 582 | static struct flash_info *__devinit jedec_probe(struct spi_device *spi) | ||
| 583 | { | ||
| 584 | int tmp; | ||
| 585 | uint8_t code = OP_READ_ID; | ||
| 586 | uint8_t id[3]; | ||
| 587 | uint32_t jedec; | ||
| 588 | struct flash_info *info; | ||
| 589 | int status; | ||
| 590 | |||
| 591 | |||
| 592 | /* JEDEC also defines an optional "extended device information" | ||
| 593 | * string for after vendor-specific data, after the three bytes | ||
| 594 | * we use here. Supporting some chips might require using it. | ||
| 595 | */ | ||
| 596 | tmp = spi_write_then_read(spi, &code, 1, id, 3); | ||
| 597 | if (tmp < 0) { | ||
| 598 | DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n", | ||
| 599 | spi->dev.bus_id, tmp); | ||
| 600 | return NULL; | ||
| 601 | } | ||
| 602 | jedec = id[0]; | ||
| 603 | jedec = jedec << 8; | ||
| 604 | jedec |= id[1]; | ||
| 605 | jedec = jedec << 8; | ||
| 606 | jedec |= id[2]; | ||
| 607 | |||
| 608 | for (tmp = 0, info = dataflash_data; | ||
| 609 | tmp < ARRAY_SIZE(dataflash_data); | ||
| 610 | tmp++, info++) { | ||
| 611 | if (info->jedec_id == jedec) { | ||
| 612 | if (info->flags & SUP_POW2PS) { | ||
| 613 | status = dataflash_status(spi); | ||
| 614 | if (status & 0x1) | ||
| 615 | /* return power of 2 pagesize */ | ||
| 616 | return ++info; | ||
| 617 | else | ||
| 618 | return info; | ||
| 619 | } | ||
| 620 | } | ||
| 621 | } | ||
| 622 | return NULL; | ||
| 623 | } | ||
| 624 | |||
| 532 | static int __devinit dataflash_probe(struct spi_device *spi) | 625 | static int __devinit dataflash_probe(struct spi_device *spi) |
| 533 | { | 626 | { |
| 534 | int status; | 627 | int status; |
| 628 | struct flash_info *info; | ||
| 629 | |||
| 630 | /* | ||
| 631 | * Try to detect dataflash by JEDEC ID. | ||
| 632 | * If it succeeds we know we have either a C or D part. | ||
| 633 | * D will support power of 2 pagesize option. | ||
| 634 | */ | ||
| 635 | |||
| 636 | info = jedec_probe(spi); | ||
| 637 | |||
| 638 | if (info != NULL) | ||
| 639 | return add_dataflash(spi, info->name, info->nr_pages, | ||
| 640 | info->pagesize, info->pageoffset); | ||
| 641 | |||
| 535 | 642 | ||
| 536 | status = dataflash_status(spi); | 643 | status = dataflash_status(spi); |
| 537 | if (status <= 0 || status == 0xff) { | 644 | if (status <= 0 || status == 0xff) { |
| @@ -551,16 +658,16 @@ static int __devinit dataflash_probe(struct spi_device *spi) | |||
| 551 | status = add_dataflash(spi, "AT45DB011B", 512, 264, 9); | 658 | status = add_dataflash(spi, "AT45DB011B", 512, 264, 9); |
| 552 | break; | 659 | break; |
| 553 | case 0x14: /* 0 1 0 1 x x */ | 660 | case 0x14: /* 0 1 0 1 x x */ |
| 554 | status = add_dataflash(spi, "AT45DB021B", 1025, 264, 9); | 661 | status = add_dataflash(spi, "AT45DB021B", 1024, 264, 9); |
| 555 | break; | 662 | break; |
| 556 | case 0x1c: /* 0 1 1 1 x x */ | 663 | case 0x1c: /* 0 1 1 1 x x */ |
| 557 | status = add_dataflash(spi, "AT45DB041x", 2048, 264, 9); | 664 | status = add_dataflash(spi, "AT45DB041B", 2048, 264, 9); |
| 558 | break; | 665 | break; |
| 559 | case 0x24: /* 1 0 0 1 x x */ | 666 | case 0x24: /* 1 0 0 1 x x */ |
| 560 | status = add_dataflash(spi, "AT45DB081B", 4096, 264, 9); | 667 | status = add_dataflash(spi, "AT45DB081B", 4096, 264, 9); |
| 561 | break; | 668 | break; |
| 562 | case 0x2c: /* 1 0 1 1 x x */ | 669 | case 0x2c: /* 1 0 1 1 x x */ |
| 563 | status = add_dataflash(spi, "AT45DB161x", 4096, 528, 10); | 670 | status = add_dataflash(spi, "AT45DB161B", 4096, 528, 10); |
| 564 | break; | 671 | break; |
| 565 | case 0x34: /* 1 1 0 1 x x */ | 672 | case 0x34: /* 1 1 0 1 x x */ |
| 566 | status = add_dataflash(spi, "AT45DB321x", 8192, 528, 10); | 673 | status = add_dataflash(spi, "AT45DB321x", 8192, 528, 10); |
diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c index 0399be178620..3aaca88847d3 100644 --- a/drivers/mtd/devices/mtdram.c +++ b/drivers/mtd/devices/mtdram.c | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * mtdram - a test mtd device | 2 | * mtdram - a test mtd device |
| 3 | * $Id: mtdram.c,v 1.37 2005/04/21 03:42:11 joern Exp $ | ||
| 4 | * Author: Alexander Larsson <alex@cendio.se> | 3 | * Author: Alexander Larsson <alex@cendio.se> |
| 5 | * | 4 | * |
| 6 | * Copyright (c) 1999 Alexander Larsson <alex@cendio.se> | 5 | * Copyright (c) 1999 Alexander Larsson <alex@cendio.se> |
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index c7987b1c5e01..088fbb7595b5 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /** | 1 | /** |
| 2 | * $Id: phram.c,v 1.16 2005/11/07 11:14:25 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * Copyright (c) ???? Jochen Schäuble <psionic@psionic.de> | 2 | * Copyright (c) ???? Jochen Schäuble <psionic@psionic.de> |
| 5 | * Copyright (c) 2003-2004 Joern Engel <joern@wh.fh-wedel.de> | 3 | * Copyright (c) 2003-2004 Joern Engel <joern@wh.fh-wedel.de> |
| 6 | * | 4 | * |
diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c index bc9981749064..d38bca64bb15 100644 --- a/drivers/mtd/devices/pmc551.c +++ b/drivers/mtd/devices/pmc551.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: pmc551.c,v 1.32 2005/11/07 11:14:25 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * PMC551 PCI Mezzanine Ram Device | 2 | * PMC551 PCI Mezzanine Ram Device |
| 5 | * | 3 | * |
| 6 | * Author: | 4 | * Author: |
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index cb86db746f28..a425d09f35a0 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c | |||
| @@ -1,7 +1,5 @@ | |||
| 1 | /*====================================================================== | 1 | /*====================================================================== |
| 2 | 2 | ||
| 3 | $Id: slram.c,v 1.36 2005/11/07 11:14:25 gleixner Exp $ | ||
| 4 | |||
| 5 | This driver provides a method to access memory not used by the kernel | 3 | This driver provides a method to access memory not used by the kernel |
| 6 | itself (i.e. if the kernel commandline mem=xxx is used). To actually | 4 | itself (i.e. if the kernel commandline mem=xxx is used). To actually |
| 7 | use slram at least mtdblock or mtdchar is required (for block or | 5 | use slram at least mtdblock or mtdchar is required (for block or |
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 5c29872184e6..f34f20c78911 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | /* This version ported to the Linux-MTD system by dwmw2@infradead.org | 1 | /* This version ported to the Linux-MTD system by dwmw2@infradead.org |
| 2 | * $Id: ftl.c,v 1.59 2005/11/29 14:48:31 gleixner Exp $ | ||
| 3 | * | 2 | * |
| 4 | * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br> | 3 | * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br> |
| 5 | * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups | 4 | * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups |
| @@ -1078,8 +1077,6 @@ static struct mtd_blktrans_ops ftl_tr = { | |||
| 1078 | 1077 | ||
| 1079 | static int init_ftl(void) | 1078 | static int init_ftl(void) |
| 1080 | { | 1079 | { |
| 1081 | DEBUG(0, "$Id: ftl.c,v 1.59 2005/11/29 14:48:31 gleixner Exp $\n"); | ||
| 1082 | |||
| 1083 | return register_mtd_blktrans(&ftl_tr); | 1080 | return register_mtd_blktrans(&ftl_tr); |
| 1084 | } | 1081 | } |
| 1085 | 1082 | ||
diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index b0e396504e67..c4f9d3378b24 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c | |||
| @@ -7,8 +7,6 @@ | |||
| 7 | * (c) 1999 Machine Vision Holdings, Inc. | 7 | * (c) 1999 Machine Vision Holdings, Inc. |
| 8 | * Author: David Woodhouse <dwmw2@infradead.org> | 8 | * Author: David Woodhouse <dwmw2@infradead.org> |
| 9 | * | 9 | * |
| 10 | * $Id: inftlcore.c,v 1.19 2005/11/07 11:14:20 gleixner Exp $ | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
| 13 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
| 14 | * the Free Software Foundation; either version 2 of the License, or | 12 | * the Free Software Foundation; either version 2 of the License, or |
| @@ -953,9 +951,6 @@ static struct mtd_blktrans_ops inftl_tr = { | |||
| 953 | 951 | ||
| 954 | static int __init init_inftl(void) | 952 | static int __init init_inftl(void) |
| 955 | { | 953 | { |
| 956 | printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.19 $, " | ||
| 957 | "inftlmount.c %s\n", inftlmountrev); | ||
| 958 | |||
| 959 | return register_mtd_blktrans(&inftl_tr); | 954 | return register_mtd_blktrans(&inftl_tr); |
| 960 | } | 955 | } |
| 961 | 956 | ||
diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index c551d2f0779c..9113628ed1ef 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c | |||
| @@ -8,8 +8,6 @@ | |||
| 8 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) | 8 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) |
| 9 | * Copyright (C) 2000 Netgem S.A. | 9 | * Copyright (C) 2000 Netgem S.A. |
| 10 | * | 10 | * |
| 11 | * $Id: inftlmount.c,v 1.18 2005/11/07 11:14:20 gleixner Exp $ | ||
| 12 | * | ||
| 13 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 14 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
| 15 | * the Free Software Foundation; either version 2 of the License, or | 13 | * the Free Software Foundation; either version 2 of the License, or |
| @@ -39,8 +37,6 @@ | |||
| 39 | #include <linux/mtd/inftl.h> | 37 | #include <linux/mtd/inftl.h> |
| 40 | #include <linux/mtd/compatmac.h> | 38 | #include <linux/mtd/compatmac.h> |
| 41 | 39 | ||
| 42 | char inftlmountrev[]="$Revision: 1.18 $"; | ||
| 43 | |||
| 44 | /* | 40 | /* |
| 45 | * find_boot_record: Find the INFTL Media Header and its Spare copy which | 41 | * find_boot_record: Find the INFTL Media Header and its Spare copy which |
| 46 | * contains the various device information of the INFTL partition and | 42 | * contains the various device information of the INFTL partition and |
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index d2fbc2964523..df8e00bba07b 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | # drivers/mtd/maps/Kconfig | 1 | # drivers/mtd/maps/Kconfig |
| 2 | # $Id: Kconfig,v 1.61 2005/11/07 11:14:26 gleixner Exp $ | ||
| 3 | 2 | ||
| 4 | menu "Mapping drivers for chip access" | 3 | menu "Mapping drivers for chip access" |
| 5 | depends on MTD!=n | 4 | depends on MTD!=n |
| @@ -510,6 +509,17 @@ config MTD_PCMCIA_ANONYMOUS | |||
| 510 | 509 | ||
| 511 | If unsure, say N. | 510 | If unsure, say N. |
| 512 | 511 | ||
| 512 | config MTD_BFIN_ASYNC | ||
| 513 | tristate "Blackfin BF533-STAMP Flash Chip Support" | ||
| 514 | depends on BFIN533_STAMP && MTD_CFI | ||
| 515 | select MTD_PARTITIONS | ||
| 516 | default y | ||
| 517 | help | ||
| 518 | Map driver which allows for simultaneous utilization of | ||
| 519 | ethernet and CFI parallel flash. | ||
| 520 | |||
| 521 | If compiled as a module, it will be called bfin-async-flash. | ||
| 522 | |||
| 513 | config MTD_UCLINUX | 523 | config MTD_UCLINUX |
| 514 | tristate "Generic uClinux RAM/ROM filesystem support" | 524 | tristate "Generic uClinux RAM/ROM filesystem support" |
| 515 | depends on MTD_PARTITIONS && !MMU | 525 | depends on MTD_PARTITIONS && !MMU |
| @@ -539,24 +549,6 @@ config MTD_DMV182 | |||
| 539 | help | 549 | help |
| 540 | Map driver for Dy-4 SVME/DMV-182 board. | 550 | Map driver for Dy-4 SVME/DMV-182 board. |
| 541 | 551 | ||
| 542 | config MTD_BAST | ||
| 543 | tristate "Map driver for Simtec BAST (EB2410ITX) or Thorcom VR1000" | ||
| 544 | depends on ARCH_BAST || MACH_VR1000 | ||
| 545 | select MTD_PARTITIONS | ||
| 546 | select MTD_MAP_BANK_WIDTH_16 | ||
| 547 | select MTD_JEDECPROBE | ||
| 548 | help | ||
| 549 | Map driver for NOR flash on the Simtec BAST (EB2410ITX), or the | ||
| 550 | Thorcom VR1000 | ||
| 551 | |||
| 552 | Note, this driver *cannot* over-ride the WP link on the | ||
| 553 | board, or currently detect the state of the link. | ||
| 554 | |||
| 555 | config MTD_BAST_MAXSIZE | ||
| 556 | int "Maximum size for BAST flash area (MiB)" | ||
| 557 | depends on MTD_BAST | ||
| 558 | default "4" | ||
| 559 | |||
| 560 | config MTD_SHARP_SL | 552 | config MTD_SHARP_SL |
| 561 | tristate "ROM mapped on Sharp SL Series" | 553 | tristate "ROM mapped on Sharp SL Series" |
| 562 | depends on ARCH_PXA | 554 | depends on ARCH_PXA |
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index c6ce8673dab2..6cda6df973e5 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | # | 1 | # |
| 2 | # linux/drivers/maps/Makefile | 2 | # linux/drivers/maps/Makefile |
| 3 | # | 3 | # |
| 4 | # $Id: Makefile.common,v 1.34 2005/11/07 11:14:26 gleixner Exp $ | ||
| 5 | 4 | ||
| 6 | ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y) | 5 | ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y) |
| 7 | obj-$(CONFIG_MTD) += map_funcs.o | 6 | obj-$(CONFIG_MTD) += map_funcs.o |
| @@ -10,7 +9,6 @@ endif | |||
| 10 | # Chip mappings | 9 | # Chip mappings |
| 11 | obj-$(CONFIG_MTD_CDB89712) += cdb89712.o | 10 | obj-$(CONFIG_MTD_CDB89712) += cdb89712.o |
| 12 | obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o | 11 | obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o |
| 13 | obj-$(CONFIG_MTD_BAST) += bast-flash.o | ||
| 14 | obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o | 12 | obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o |
| 15 | obj-$(CONFIG_MTD_DC21285) += dc21285.o | 13 | obj-$(CONFIG_MTD_DC21285) += dc21285.o |
| 16 | obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o | 14 | obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o |
| @@ -66,3 +64,4 @@ obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o | |||
| 66 | obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o | 64 | obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o |
| 67 | obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o | 65 | obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o |
| 68 | obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o | 66 | obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o |
| 67 | obj-$(CONFIG_MTD_BFIN_ASYNC) += bfin-async-flash.o | ||
diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c index 728aed6ad722..948b86f35ef4 100644 --- a/drivers/mtd/maps/amd76xrom.c +++ b/drivers/mtd/maps/amd76xrom.c | |||
| @@ -2,7 +2,6 @@ | |||
| 2 | * amd76xrom.c | 2 | * amd76xrom.c |
| 3 | * | 3 | * |
| 4 | * Normal mappings of chips in physical memory | 4 | * Normal mappings of chips in physical memory |
| 5 | * $Id: amd76xrom.c,v 1.21 2005/11/07 11:14:26 gleixner Exp $ | ||
| 6 | */ | 5 | */ |
| 7 | 6 | ||
| 8 | #include <linux/module.h> | 7 | #include <linux/module.h> |
diff --git a/drivers/mtd/maps/autcpu12-nvram.c b/drivers/mtd/maps/autcpu12-nvram.c index 7ed3424dd959..cf32267263df 100644 --- a/drivers/mtd/maps/autcpu12-nvram.c +++ b/drivers/mtd/maps/autcpu12-nvram.c | |||
| @@ -2,8 +2,6 @@ | |||
| 2 | * NV-RAM memory access on autcpu12 | 2 | * NV-RAM memory access on autcpu12 |
| 3 | * (C) 2002 Thomas Gleixner (gleixner@autronix.de) | 3 | * (C) 2002 Thomas Gleixner (gleixner@autronix.de) |
| 4 | * | 4 | * |
| 5 | * $Id: autcpu12-nvram.c,v 1.9 2005/11/07 11:14:26 gleixner Exp $ | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
| 9 | * the Free Software Foundation; either version 2 of the License, or | 7 | * the Free Software Foundation; either version 2 of the License, or |
diff --git a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c deleted file mode 100644 index 1f492062f8ca..000000000000 --- a/drivers/mtd/maps/bast-flash.c +++ /dev/null | |||
| @@ -1,226 +0,0 @@ | |||
| 1 | /* linux/drivers/mtd/maps/bast-flash.c | ||
| 2 | * | ||
| 3 | * Copyright (c) 2004-2005 Simtec Electronics | ||
| 4 | * Ben Dooks <ben@simtec.co.uk> | ||
| 5 | * | ||
| 6 | * Simtec Bast (EB2410ITX) NOR MTD Mapping driver | ||
| 7 | * | ||
| 8 | * Changelog: | ||
| 9 | * 20-Sep-2004 BJD Initial version | ||
| 10 | * 17-Jan-2005 BJD Add whole device if no partitions found | ||
| 11 | * | ||
| 12 | * $Id: bast-flash.c,v 1.5 2005/11/07 11:14:26 gleixner Exp $ | ||
| 13 | * | ||
| 14 | * This program is free software; you can redistribute it and/or modify | ||
| 15 | * it under the terms of the GNU General Public License as published by | ||
| 16 | * the Free Software Foundation; either version 2 of the License, or | ||
| 17 | * (at your option) any later version. | ||
| 18 | * | ||
| 19 | * This program is distributed in the hope that it will be useful, | ||
| 20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 22 | * GNU General Public License for more details. | ||
| 23 | * | ||
| 24 | * You should have received a copy of the GNU General Public License | ||
| 25 | * along with this program; if not, write to the Free Software | ||
| 26 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 27 | */ | ||
| 28 | |||
| 29 | #include <linux/module.h> | ||
| 30 | #include <linux/types.h> | ||
| 31 | #include <linux/init.h> | ||
| 32 | #include <linux/kernel.h> | ||
| 33 | #include <linux/string.h> | ||
| 34 | #include <linux/ioport.h> | ||
| 35 | #include <linux/device.h> | ||
| 36 | #include <linux/slab.h> | ||
| 37 | #include <linux/platform_device.h> | ||
| 38 | #include <linux/mtd/mtd.h> | ||
| 39 | #include <linux/mtd/map.h> | ||
| 40 | #include <linux/mtd/partitions.h> | ||
| 41 | |||
| 42 | #include <asm/io.h> | ||
| 43 | #include <asm/mach/flash.h> | ||
| 44 | |||
| 45 | #include <asm/arch/map.h> | ||
| 46 | #include <asm/arch/bast-map.h> | ||
| 47 | #include <asm/arch/bast-cpld.h> | ||
| 48 | |||
| 49 | #ifdef CONFIG_MTD_BAST_MAXSIZE | ||
| 50 | #define AREA_MAXSIZE (CONFIG_MTD_BAST_MAXSIZE * SZ_1M) | ||
| 51 | #else | ||
| 52 | #define AREA_MAXSIZE (32 * SZ_1M) | ||
| 53 | #endif | ||
| 54 | |||
| 55 | #define PFX "bast-flash: " | ||
| 56 | |||
| 57 | struct bast_flash_info { | ||
| 58 | struct mtd_info *mtd; | ||
| 59 | struct map_info map; | ||
| 60 | struct mtd_partition *partitions; | ||
| 61 | struct resource *area; | ||
| 62 | }; | ||
| 63 | |||
| 64 | static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; | ||
| 65 | |||
| 66 | static void bast_flash_setrw(int to) | ||
| 67 | { | ||
| 68 | unsigned int val; | ||
| 69 | unsigned long flags; | ||
| 70 | |||
| 71 | local_irq_save(flags); | ||
| 72 | val = __raw_readb(BAST_VA_CTRL3); | ||
| 73 | |||
| 74 | if (to) | ||
| 75 | val |= BAST_CPLD_CTRL3_ROMWEN; | ||
| 76 | else | ||
| 77 | val &= ~BAST_CPLD_CTRL3_ROMWEN; | ||
| 78 | |||
| 79 | pr_debug("new cpld ctrl3=%02x\n", val); | ||
| 80 | |||
| 81 | __raw_writeb(val, BAST_VA_CTRL3); | ||
| 82 | local_irq_restore(flags); | ||
| 83 | } | ||
| 84 | |||
| 85 | static int bast_flash_remove(struct platform_device *pdev) | ||
| 86 | { | ||
| 87 | struct bast_flash_info *info = platform_get_drvdata(pdev); | ||
| 88 | |||
| 89 | platform_set_drvdata(pdev, NULL); | ||
| 90 | |||
| 91 | if (info == NULL) | ||
| 92 | return 0; | ||
| 93 | |||
| 94 | if (info->map.virt != NULL) | ||
| 95 | iounmap(info->map.virt); | ||
| 96 | |||
| 97 | if (info->mtd) { | ||
| 98 | del_mtd_partitions(info->mtd); | ||
| 99 | map_destroy(info->mtd); | ||
| 100 | } | ||
| 101 | |||
| 102 | kfree(info->partitions); | ||
| 103 | |||
| 104 | if (info->area) { | ||
| 105 | release_resource(info->area); | ||
| 106 | kfree(info->area); | ||
| 107 | } | ||
| 108 | |||
| 109 | kfree(info); | ||
| 110 | |||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | static int bast_flash_probe(struct platform_device *pdev) | ||
| 115 | { | ||
| 116 | struct bast_flash_info *info; | ||
| 117 | struct resource *res; | ||
| 118 | int err = 0; | ||
| 119 | |||
| 120 | info = kmalloc(sizeof(*info), GFP_KERNEL); | ||
| 121 | if (info == NULL) { | ||
| 122 | printk(KERN_ERR PFX "no memory for flash info\n"); | ||
| 123 | err = -ENOMEM; | ||
| 124 | goto exit_error; | ||
| 125 | } | ||
| 126 | |||
| 127 | memzero(info, sizeof(*info)); | ||
| 128 | platform_set_drvdata(pdev, info); | ||
| 129 | |||
| 130 | res = pdev->resource; /* assume that the flash has one resource */ | ||
| 131 | |||
| 132 | info->map.phys = res->start; | ||
| 133 | info->map.size = res->end - res->start + 1; | ||
| 134 | info->map.name = pdev->dev.bus_id; | ||
| 135 | info->map.bankwidth = 2; | ||
| 136 | |||
| 137 | if (info->map.size > AREA_MAXSIZE) | ||
| 138 | info->map.size = AREA_MAXSIZE; | ||
| 139 | |||
| 140 | pr_debug("%s: area %08lx, size %ld\n", __func__, | ||
| 141 | info->map.phys, info->map.size); | ||
| 142 | |||
| 143 | info->area = request_mem_region(res->start, info->map.size, | ||
| 144 | pdev->name); | ||
| 145 | if (info->area == NULL) { | ||
| 146 | printk(KERN_ERR PFX "cannot reserve flash memory region\n"); | ||
| 147 | err = -ENOENT; | ||
| 148 | goto exit_error; | ||
| 149 | } | ||
| 150 | |||
| 151 | info->map.virt = ioremap(res->start, info->map.size); | ||
| 152 | pr_debug("%s: virt at %08x\n", __func__, (int)info->map.virt); | ||
| 153 | |||
| 154 | if (info->map.virt == 0) { | ||
| 155 | printk(KERN_ERR PFX "failed to ioremap() region\n"); | ||
| 156 | err = -EIO; | ||
| 157 | goto exit_error; | ||
| 158 | } | ||
| 159 | |||
| 160 | simple_map_init(&info->map); | ||
| 161 | |||
| 162 | /* enable the write to the flash area */ | ||
| 163 | |||
| 164 | bast_flash_setrw(1); | ||
| 165 | |||
| 166 | /* probe for the device(s) */ | ||
| 167 | |||
| 168 | info->mtd = do_map_probe("jedec_probe", &info->map); | ||
| 169 | if (info->mtd == NULL) | ||
| 170 | info->mtd = do_map_probe("cfi_probe", &info->map); | ||
| 171 | |||
| 172 | if (info->mtd == NULL) { | ||
| 173 | printk(KERN_ERR PFX "map_probe() failed\n"); | ||
| 174 | err = -ENXIO; | ||
| 175 | goto exit_error; | ||
| 176 | } | ||
| 177 | |||
| 178 | /* mark ourselves as the owner */ | ||
| 179 | info->mtd->owner = THIS_MODULE; | ||
| 180 | |||
| 181 | err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0); | ||
| 182 | if (err > 0) { | ||
| 183 | err = add_mtd_partitions(info->mtd, info->partitions, err); | ||
| 184 | if (err) | ||
| 185 | printk(KERN_ERR PFX "cannot add/parse partitions\n"); | ||
| 186 | } else { | ||
| 187 | err = add_mtd_device(info->mtd); | ||
| 188 | } | ||
| 189 | |||
| 190 | if (err == 0) | ||
| 191 | return 0; | ||
| 192 | |||
| 193 | /* fall through to exit error */ | ||
| 194 | |||
| 195 | exit_error: | ||
| 196 | bast_flash_remove(pdev); | ||
| 197 | return err; | ||
| 198 | } | ||
| 199 | |||
| 200 | static struct platform_driver bast_flash_driver = { | ||
| 201 | .probe = bast_flash_probe, | ||
| 202 | .remove = bast_flash_remove, | ||
| 203 | .driver = { | ||
| 204 | .name = "bast-nor", | ||
| 205 | .owner = THIS_MODULE, | ||
| 206 | }, | ||
| 207 | }; | ||
| 208 | |||
| 209 | static int __init bast_flash_init(void) | ||
| 210 | { | ||
| 211 | printk("BAST NOR-Flash Driver, (c) 2004 Simtec Electronics\n"); | ||
| 212 | return platform_driver_register(&bast_flash_driver); | ||
| 213 | } | ||
| 214 | |||
| 215 | static void __exit bast_flash_exit(void) | ||
| 216 | { | ||
| 217 | platform_driver_unregister(&bast_flash_driver); | ||
| 218 | } | ||
| 219 | |||
| 220 | module_init(bast_flash_init); | ||
| 221 | module_exit(bast_flash_exit); | ||
| 222 | |||
| 223 | MODULE_LICENSE("GPL"); | ||
| 224 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | ||
| 225 | MODULE_DESCRIPTION("BAST MTD Map driver"); | ||
| 226 | MODULE_ALIAS("platform:bast-nor"); | ||
diff --git a/drivers/mtd/maps/bfin-async-flash.c b/drivers/mtd/maps/bfin-async-flash.c new file mode 100644 index 000000000000..6fec86aaed7e --- /dev/null +++ b/drivers/mtd/maps/bfin-async-flash.c | |||
| @@ -0,0 +1,219 @@ | |||
| 1 | /* | ||
| 2 | * drivers/mtd/maps/bfin-async-flash.c | ||
| 3 | * | ||
| 4 | * Handle the case where flash memory and ethernet mac/phy are | ||
| 5 | * mapped onto the same async bank. The BF533-STAMP does this | ||
| 6 | * for example. All board-specific configuration goes in your | ||
| 7 | * board resources file. | ||
| 8 | * | ||
| 9 | * Copyright 2000 Nicolas Pitre <nico@cam.org> | ||
| 10 | * Copyright 2005-2008 Analog Devices Inc. | ||
| 11 | * | ||
| 12 | * Enter bugs at http://blackfin.uclinux.org/ | ||
| 13 | * | ||
| 14 | * Licensed under the GPL-2 or later. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/kernel.h> | ||
| 19 | #include <linux/module.h> | ||
| 20 | #include <linux/mtd/mtd.h> | ||
| 21 | #include <linux/mtd/map.h> | ||
| 22 | #include <linux/mtd/partitions.h> | ||
| 23 | #include <linux/mtd/physmap.h> | ||
| 24 | #include <linux/platform_device.h> | ||
| 25 | #include <linux/types.h> | ||
| 26 | |||
| 27 | #include <asm/blackfin.h> | ||
| 28 | #include <linux/gpio.h> | ||
| 29 | #include <linux/io.h> | ||
| 30 | #include <asm/unaligned.h> | ||
| 31 | |||
| 32 | #define pr_devinit(fmt, args...) ({ static const __devinitconst char __fmt[] = fmt; printk(__fmt, ## args); }) | ||
| 33 | |||
| 34 | #define DRIVER_NAME "bfin-async-flash" | ||
| 35 | |||
| 36 | struct async_state { | ||
| 37 | struct mtd_info *mtd; | ||
| 38 | struct map_info map; | ||
| 39 | int enet_flash_pin; | ||
| 40 | uint32_t flash_ambctl0, flash_ambctl1; | ||
| 41 | uint32_t save_ambctl0, save_ambctl1; | ||
| 42 | unsigned long irq_flags; | ||
| 43 | }; | ||
| 44 | |||
| 45 | static void switch_to_flash(struct async_state *state) | ||
| 46 | { | ||
| 47 | local_irq_save(state->irq_flags); | ||
| 48 | |||
| 49 | gpio_set_value(state->enet_flash_pin, 0); | ||
| 50 | |||
| 51 | state->save_ambctl0 = bfin_read_EBIU_AMBCTL0(); | ||
| 52 | state->save_ambctl1 = bfin_read_EBIU_AMBCTL1(); | ||
| 53 | bfin_write_EBIU_AMBCTL0(state->flash_ambctl0); | ||
| 54 | bfin_write_EBIU_AMBCTL1(state->flash_ambctl1); | ||
| 55 | SSYNC(); | ||
| 56 | } | ||
| 57 | |||
| 58 | static void switch_back(struct async_state *state) | ||
| 59 | { | ||
| 60 | bfin_write_EBIU_AMBCTL0(state->save_ambctl0); | ||
| 61 | bfin_write_EBIU_AMBCTL1(state->save_ambctl1); | ||
| 62 | SSYNC(); | ||
| 63 | |||
| 64 | gpio_set_value(state->enet_flash_pin, 1); | ||
| 65 | |||
| 66 | local_irq_restore(state->irq_flags); | ||
| 67 | } | ||
| 68 | |||
| 69 | static map_word bfin_read(struct map_info *map, unsigned long ofs) | ||
| 70 | { | ||
| 71 | struct async_state *state = (struct async_state *)map->map_priv_1; | ||
| 72 | uint16_t word; | ||
| 73 | map_word test; | ||
| 74 | |||
| 75 | switch_to_flash(state); | ||
| 76 | |||
| 77 | word = readw(map->virt + ofs); | ||
| 78 | |||
| 79 | switch_back(state); | ||
| 80 | |||
| 81 | test.x[0] = word; | ||
| 82 | return test; | ||
| 83 | } | ||
| 84 | |||
| 85 | static void bfin_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) | ||
| 86 | { | ||
| 87 | struct async_state *state = (struct async_state *)map->map_priv_1; | ||
| 88 | |||
| 89 | switch_to_flash(state); | ||
| 90 | |||
| 91 | memcpy(to, map->virt + from, len); | ||
| 92 | |||
| 93 | switch_back(state); | ||
| 94 | } | ||
| 95 | |||
| 96 | static void bfin_write(struct map_info *map, map_word d1, unsigned long ofs) | ||
| 97 | { | ||
| 98 | struct async_state *state = (struct async_state *)map->map_priv_1; | ||
| 99 | uint16_t d; | ||
| 100 | |||
| 101 | d = d1.x[0]; | ||
| 102 | |||
| 103 | switch_to_flash(state); | ||
| 104 | |||
| 105 | writew(d, map->virt + ofs); | ||
| 106 | SSYNC(); | ||
| 107 | |||
| 108 | switch_back(state); | ||
| 109 | } | ||
| 110 | |||
| 111 | static void bfin_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) | ||
| 112 | { | ||
| 113 | struct async_state *state = (struct async_state *)map->map_priv_1; | ||
| 114 | |||
| 115 | switch_to_flash(state); | ||
| 116 | |||
| 117 | memcpy(map->virt + to, from, len); | ||
| 118 | SSYNC(); | ||
| 119 | |||
| 120 | switch_back(state); | ||
| 121 | } | ||
| 122 | |||
| 123 | #ifdef CONFIG_MTD_PARTITIONS | ||
| 124 | static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; | ||
| 125 | #endif | ||
| 126 | |||
| 127 | static int __devinit bfin_flash_probe(struct platform_device *pdev) | ||
| 128 | { | ||
| 129 | int ret; | ||
| 130 | struct physmap_flash_data *pdata = pdev->dev.platform_data; | ||
| 131 | struct resource *memory = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 132 | struct resource *flash_ambctl = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
| 133 | struct async_state *state; | ||
| 134 | |||
| 135 | state = kzalloc(sizeof(*state), GFP_KERNEL); | ||
| 136 | if (!state) | ||
| 137 | return -ENOMEM; | ||
| 138 | |||
| 139 | state->map.name = DRIVER_NAME; | ||
| 140 | state->map.read = bfin_read; | ||
| 141 | state->map.copy_from = bfin_copy_from; | ||
| 142 | state->map.write = bfin_write; | ||
| 143 | state->map.copy_to = bfin_copy_to; | ||
| 144 | state->map.bankwidth = pdata->width; | ||
| 145 | state->map.size = memory->end - memory->start + 1; | ||
| 146 | state->map.virt = (void __iomem *)memory->start; | ||
| 147 | state->map.phys = memory->start; | ||
| 148 | state->map.map_priv_1 = (unsigned long)state; | ||
| 149 | state->enet_flash_pin = platform_get_irq(pdev, 0); | ||
| 150 | state->flash_ambctl0 = flash_ambctl->start; | ||
| 151 | state->flash_ambctl1 = flash_ambctl->end; | ||
| 152 | |||
| 153 | if (gpio_request(state->enet_flash_pin, DRIVER_NAME)) { | ||
| 154 | pr_devinit(KERN_ERR DRIVER_NAME ": Failed to request gpio %d\n", state->enet_flash_pin); | ||
| 155 | return -EBUSY; | ||
| 156 | } | ||
| 157 | gpio_direction_output(state->enet_flash_pin, 1); | ||
| 158 | |||
| 159 | pr_devinit(KERN_NOTICE DRIVER_NAME ": probing %d-bit flash bus\n", state->map.bankwidth * 8); | ||
| 160 | state->mtd = do_map_probe(memory->name, &state->map); | ||
| 161 | if (!state->mtd) | ||
| 162 | return -ENXIO; | ||
| 163 | |||
| 164 | #ifdef CONFIG_MTD_PARTITIONS | ||
| 165 | ret = parse_mtd_partitions(state->mtd, part_probe_types, &pdata->parts, 0); | ||
| 166 | if (ret > 0) { | ||
| 167 | pr_devinit(KERN_NOTICE DRIVER_NAME ": Using commandline partition definition\n"); | ||
| 168 | add_mtd_partitions(state->mtd, pdata->parts, ret); | ||
| 169 | |||
| 170 | } else if (pdata->nr_parts) { | ||
| 171 | pr_devinit(KERN_NOTICE DRIVER_NAME ": Using board partition definition\n"); | ||
| 172 | add_mtd_partitions(state->mtd, pdata->parts, pdata->nr_parts); | ||
| 173 | |||
| 174 | } else | ||
| 175 | #endif | ||
| 176 | { | ||
| 177 | pr_devinit(KERN_NOTICE DRIVER_NAME ": no partition info available, registering whole flash at once\n"); | ||
| 178 | add_mtd_device(state->mtd); | ||
| 179 | } | ||
| 180 | |||
| 181 | platform_set_drvdata(pdev, state); | ||
| 182 | |||
| 183 | return 0; | ||
| 184 | } | ||
| 185 | |||
| 186 | static int __devexit bfin_flash_remove(struct platform_device *pdev) | ||
| 187 | { | ||
| 188 | struct async_state *state = platform_get_drvdata(pdev); | ||
| 189 | gpio_free(state->enet_flash_pin); | ||
| 190 | #ifdef CONFIG_MTD_PARTITIONS | ||
| 191 | del_mtd_partitions(state->mtd); | ||
| 192 | #endif | ||
| 193 | map_destroy(state->mtd); | ||
| 194 | kfree(state); | ||
| 195 | return 0; | ||
| 196 | } | ||
| 197 | |||
| 198 | static struct platform_driver bfin_flash_driver = { | ||
| 199 | .probe = bfin_flash_probe, | ||
| 200 | .remove = __devexit_p(bfin_flash_remove), | ||
| 201 | .driver = { | ||
| 202 | .name = DRIVER_NAME, | ||
| 203 | }, | ||
| 204 | }; | ||
| 205 | |||
| 206 | static int __init bfin_flash_init(void) | ||
| 207 | { | ||
| 208 | return platform_driver_register(&bfin_flash_driver); | ||
| 209 | } | ||
| 210 | module_init(bfin_flash_init); | ||
| 211 | |||
| 212 | static void __exit bfin_flash_exit(void) | ||
| 213 | { | ||
| 214 | platform_driver_unregister(&bfin_flash_driver); | ||
| 215 | } | ||
| 216 | module_exit(bfin_flash_exit); | ||
| 217 | |||
| 218 | MODULE_LICENSE("GPL"); | ||
| 219 | MODULE_DESCRIPTION("MTD map driver for Blackfins with flash/ethernet on same async bank"); | ||
diff --git a/drivers/mtd/maps/cdb89712.c b/drivers/mtd/maps/cdb89712.c index 9f17bb6c5a9d..cb507da0a87d 100644 --- a/drivers/mtd/maps/cdb89712.c +++ b/drivers/mtd/maps/cdb89712.c | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Flash on Cirrus CDB89712 | 2 | * Flash on Cirrus CDB89712 |
| 3 | * | 3 | * |
| 4 | * $Id: cdb89712.c,v 1.11 2005/11/07 11:14:26 gleixner Exp $ | ||
| 5 | */ | 4 | */ |
| 6 | 5 | ||
| 7 | #include <linux/module.h> | 6 | #include <linux/module.h> |
diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c index 629e6e2641a8..6464d487eb1a 100644 --- a/drivers/mtd/maps/ceiva.c +++ b/drivers/mtd/maps/ceiva.c | |||
| @@ -11,7 +11,6 @@ | |||
| 11 | * | 11 | * |
| 12 | * (C) 2000 Nicolas Pitre <nico@cam.org> | 12 | * (C) 2000 Nicolas Pitre <nico@cam.org> |
| 13 | * | 13 | * |
| 14 | * $Id: ceiva.c,v 1.11 2004/09/16 23:27:12 gleixner Exp $ | ||
| 15 | */ | 14 | */ |
| 16 | 15 | ||
| 17 | #include <linux/module.h> | 16 | #include <linux/module.h> |
diff --git a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c index 65e5ee552010..0ecc3f6d735b 100644 --- a/drivers/mtd/maps/cfi_flagadm.c +++ b/drivers/mtd/maps/cfi_flagadm.c | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright © 2001 Flaga hf. Medical Devices, Kári DavÃðsson <kd@flaga.is> | 2 | * Copyright © 2001 Flaga hf. Medical Devices, Kári DavÃðsson <kd@flaga.is> |
| 3 | * | 3 | * |
| 4 | * $Id: cfi_flagadm.c,v 1.15 2005/11/07 11:14:26 gleixner Exp $ | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | 4 | * This program is free software; you can redistribute it and/or modify it |
| 7 | * under the terms of the GNU General Public License as published by the | 5 | * under the terms of the GNU General Public License as published by the |
| 8 | * Free Software Foundation; either version 2 of the License, or (at your | 6 | * Free Software Foundation; either version 2 of the License, or (at your |
diff --git a/drivers/mtd/maps/dbox2-flash.c b/drivers/mtd/maps/dbox2-flash.c index 92a9c7fac993..e115667bf1d0 100644 --- a/drivers/mtd/maps/dbox2-flash.c +++ b/drivers/mtd/maps/dbox2-flash.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: dbox2-flash.c,v 1.14 2005/11/07 11:14:26 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * D-Box 2 flash driver | 2 | * D-Box 2 flash driver |
| 5 | */ | 3 | */ |
| 6 | 4 | ||
diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c index b32bb9347d71..3aa018c092f8 100644 --- a/drivers/mtd/maps/dc21285.c +++ b/drivers/mtd/maps/dc21285.c | |||
| @@ -4,8 +4,6 @@ | |||
| 4 | * (C) 2000 Nicolas Pitre <nico@cam.org> | 4 | * (C) 2000 Nicolas Pitre <nico@cam.org> |
| 5 | * | 5 | * |
| 6 | * This code is GPL | 6 | * This code is GPL |
| 7 | * | ||
| 8 | * $Id: dc21285.c,v 1.24 2005/11/07 11:14:26 gleixner Exp $ | ||
| 9 | */ | 7 | */ |
| 10 | #include <linux/module.h> | 8 | #include <linux/module.h> |
| 11 | #include <linux/types.h> | 9 | #include <linux/types.h> |
diff --git a/drivers/mtd/maps/dilnetpc.c b/drivers/mtd/maps/dilnetpc.c index 1c3b34ad7325..0713e3a5a22c 100644 --- a/drivers/mtd/maps/dilnetpc.c +++ b/drivers/mtd/maps/dilnetpc.c | |||
| @@ -14,8 +14,6 @@ | |||
| 14 | * along with this program; if not, write to the Free Software | 14 | * along with this program; if not, write to the Free Software |
| 15 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | 15 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
| 16 | * | 16 | * |
| 17 | * $Id: dilnetpc.c,v 1.20 2005/11/07 11:14:26 gleixner Exp $ | ||
| 18 | * | ||
| 19 | * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems | 17 | * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems |
| 20 | * featuring the AMD Elan SC410 processor. There are two variants of this | 18 | * featuring the AMD Elan SC410 processor. There are two variants of this |
| 21 | * board: DNP/1486 and ADNP/1486. The DNP version has 2 megs of flash | 19 | * board: DNP/1486 and ADNP/1486. The DNP version has 2 megs of flash |
diff --git a/drivers/mtd/maps/dmv182.c b/drivers/mtd/maps/dmv182.c index e0558b0b2fe6..d171674eb2ed 100644 --- a/drivers/mtd/maps/dmv182.c +++ b/drivers/mtd/maps/dmv182.c | |||
| @@ -4,8 +4,6 @@ | |||
| 4 | * | 4 | * |
| 5 | * Flash map driver for the Dy4 SVME182 board | 5 | * Flash map driver for the Dy4 SVME182 board |
| 6 | * | 6 | * |
| 7 | * $Id: dmv182.c,v 1.6 2005/11/07 11:14:26 gleixner Exp $ | ||
| 8 | * | ||
| 9 | * Copyright 2003-2004, TimeSys Corporation | 7 | * Copyright 2003-2004, TimeSys Corporation |
| 10 | * | 8 | * |
| 11 | * Based on the SVME181 flash map, by Tom Nelson, Dot4, Inc. for TimeSys Corp. | 9 | * Based on the SVME181 flash map, by Tom Nelson, Dot4, Inc. for TimeSys Corp. |
diff --git a/drivers/mtd/maps/ebony.c b/drivers/mtd/maps/ebony.c index 1488bb92f26f..d92b7c70d3ed 100644 --- a/drivers/mtd/maps/ebony.c +++ b/drivers/mtd/maps/ebony.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: ebony.c,v 1.16 2005/11/07 11:14:26 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * Mapping for Ebony user flash | 2 | * Mapping for Ebony user flash |
| 5 | * | 3 | * |
| 6 | * Matt Porter <mporter@kernel.crashing.org> | 4 | * Matt Porter <mporter@kernel.crashing.org> |
diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c index 1c5b97c89685..9433738c1664 100644 --- a/drivers/mtd/maps/edb7312.c +++ b/drivers/mtd/maps/edb7312.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: edb7312.c,v 1.14 2005/11/07 11:14:27 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * Handle mapping of the NOR flash on Cogent EDB7312 boards | 2 | * Handle mapping of the NOR flash on Cogent EDB7312 boards |
| 5 | * | 3 | * |
| 6 | * Copyright 2002 SYSGO Real-Time Solutions GmbH | 4 | * Copyright 2002 SYSGO Real-Time Solutions GmbH |
diff --git a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c index 7c50c271651c..a8e3fde4cbd5 100644 --- a/drivers/mtd/maps/fortunet.c +++ b/drivers/mtd/maps/fortunet.c | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | /* fortunet.c memory map | 1 | /* fortunet.c memory map |
| 2 | * | 2 | * |
| 3 | * $Id: fortunet.c,v 1.11 2005/11/07 11:14:27 gleixner Exp $ | ||
| 4 | */ | 3 | */ |
| 5 | 4 | ||
| 6 | #include <linux/module.h> | 5 | #include <linux/module.h> |
diff --git a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c index 6dde3182d64a..ef8915474462 100644 --- a/drivers/mtd/maps/h720x-flash.c +++ b/drivers/mtd/maps/h720x-flash.c | |||
| @@ -2,8 +2,6 @@ | |||
| 2 | * Flash memory access on Hynix GMS30C7201/HMS30C7202 based | 2 | * Flash memory access on Hynix GMS30C7201/HMS30C7202 based |
| 3 | * evaluation boards | 3 | * evaluation boards |
| 4 | * | 4 | * |
| 5 | * $Id: h720x-flash.c,v 1.12 2005/11/07 11:14:27 gleixner Exp $ | ||
| 6 | * | ||
| 7 | * (C) 2002 Jungjun Kim <jungjun.kim@hynix.com> | 5 | * (C) 2002 Jungjun Kim <jungjun.kim@hynix.com> |
| 8 | * 2003 Thomas Gleixner <tglx@linutronix.de> | 6 | * 2003 Thomas Gleixner <tglx@linutronix.de> |
| 9 | */ | 7 | */ |
diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c index 2c884c49e84a..aeb6c916e23f 100644 --- a/drivers/mtd/maps/ichxrom.c +++ b/drivers/mtd/maps/ichxrom.c | |||
| @@ -2,7 +2,6 @@ | |||
| 2 | * ichxrom.c | 2 | * ichxrom.c |
| 3 | * | 3 | * |
| 4 | * Normal mappings of chips in physical memory | 4 | * Normal mappings of chips in physical memory |
| 5 | * $Id: ichxrom.c,v 1.19 2005/11/07 11:14:27 gleixner Exp $ | ||
| 6 | */ | 5 | */ |
| 7 | 6 | ||
| 8 | #include <linux/module.h> | 7 | #include <linux/module.h> |
diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c index a0b4dc7155dc..2682ab51a367 100644 --- a/drivers/mtd/maps/impa7.c +++ b/drivers/mtd/maps/impa7.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: impa7.c,v 1.14 2005/11/07 11:14:27 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * Handle mapping of the NOR flash on implementa A7 boards | 2 | * Handle mapping of the NOR flash on implementa A7 boards |
| 5 | * | 3 | * |
| 6 | * Copyright 2002 SYSGO Real-Time Solutions GmbH | 4 | * Copyright 2002 SYSGO Real-Time Solutions GmbH |
diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c index 325c8880c437..ee361aaadb1e 100644 --- a/drivers/mtd/maps/integrator-flash.c +++ b/drivers/mtd/maps/integrator-flash.c | |||
| @@ -22,8 +22,6 @@ | |||
| 22 | This is access code for flashes using ARM's flash partitioning | 22 | This is access code for flashes using ARM's flash partitioning |
| 23 | standards. | 23 | standards. |
| 24 | 24 | ||
| 25 | $Id: integrator-flash.c,v 1.20 2005/11/07 11:14:27 gleixner Exp $ | ||
| 26 | |||
| 27 | ======================================================================*/ | 25 | ======================================================================*/ |
| 28 | 26 | ||
| 29 | #include <linux/module.h> | 27 | #include <linux/module.h> |
diff --git a/drivers/mtd/maps/ipaq-flash.c b/drivers/mtd/maps/ipaq-flash.c index f27c132794c3..a806119797e0 100644 --- a/drivers/mtd/maps/ipaq-flash.c +++ b/drivers/mtd/maps/ipaq-flash.c | |||
| @@ -4,8 +4,6 @@ | |||
| 4 | * (C) 2000 Nicolas Pitre <nico@cam.org> | 4 | * (C) 2000 Nicolas Pitre <nico@cam.org> |
| 5 | * (C) 2002 Hewlett-Packard Company <jamey.hicks@hp.com> | 5 | * (C) 2002 Hewlett-Packard Company <jamey.hicks@hp.com> |
| 6 | * (C) 2003 Christian Pellegrin <chri@ascensit.com>, <chri@infis.univ.ts.it>: concatenation of multiple flashes | 6 | * (C) 2003 Christian Pellegrin <chri@ascensit.com>, <chri@infis.univ.ts.it>: concatenation of multiple flashes |
| 7 | * | ||
| 8 | * $Id: ipaq-flash.c,v 1.5 2005/11/07 11:14:27 gleixner Exp $ | ||
| 9 | */ | 7 | */ |
| 10 | 8 | ||
| 11 | #include <linux/module.h> | 9 | #include <linux/module.h> |
diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c index c8396b8574c4..c2264792a20b 100644 --- a/drivers/mtd/maps/ixp2000.c +++ b/drivers/mtd/maps/ixp2000.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: ixp2000.c,v 1.9 2005/11/07 11:14:27 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * drivers/mtd/maps/ixp2000.c | 2 | * drivers/mtd/maps/ixp2000.c |
| 5 | * | 3 | * |
| 6 | * Mapping for the Intel XScale IXP2000 based systems | 4 | * Mapping for the Intel XScale IXP2000 based systems |
diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index 01f19a4714b5..9c7a5fbd4e51 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: ixp4xx.c,v 1.13 2005/11/16 16:23:21 dvrabel Exp $ | ||
| 3 | * | ||
| 4 | * drivers/mtd/maps/ixp4xx.c | 2 | * drivers/mtd/maps/ixp4xx.c |
| 5 | * | 3 | * |
| 6 | * MTD Map file for IXP4XX based systems. Please do not make per-board | 4 | * MTD Map file for IXP4XX based systems. Please do not make per-board |
diff --git a/drivers/mtd/maps/l440gx.c b/drivers/mtd/maps/l440gx.c index 67620adf4811..9e054503c4cf 100644 --- a/drivers/mtd/maps/l440gx.c +++ b/drivers/mtd/maps/l440gx.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: l440gx.c,v 1.18 2005/11/07 11:14:27 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * BIOS Flash chip on Intel 440GX board. | 2 | * BIOS Flash chip on Intel 440GX board. |
| 5 | * | 3 | * |
| 6 | * Bugs this currently does not work under linuxBIOS. | 4 | * Bugs this currently does not work under linuxBIOS. |
diff --git a/drivers/mtd/maps/map_funcs.c b/drivers/mtd/maps/map_funcs.c index 9105e6ca0aa6..3f268370eeca 100644 --- a/drivers/mtd/maps/map_funcs.c +++ b/drivers/mtd/maps/map_funcs.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: map_funcs.c,v 1.10 2005/06/06 23:04:36 tpoynor Exp $ | ||
| 3 | * | ||
| 4 | * Out-of-line map I/O functions for simple maps when CONFIG_COMPLEX_MAPPINGS | 2 | * Out-of-line map I/O functions for simple maps when CONFIG_COMPLEX_MAPPINGS |
| 5 | * is enabled. | 3 | * is enabled. |
| 6 | */ | 4 | */ |
diff --git a/drivers/mtd/maps/mbx860.c b/drivers/mtd/maps/mbx860.c index 06b118727846..706f67394b07 100644 --- a/drivers/mtd/maps/mbx860.c +++ b/drivers/mtd/maps/mbx860.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: mbx860.c,v 1.9 2005/11/07 11:14:27 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * Handle mapping of the flash on MBX860 boards | 2 | * Handle mapping of the flash on MBX860 boards |
| 5 | * | 3 | * |
| 6 | * Author: Anton Todorov | 4 | * Author: Anton Todorov |
diff --git a/drivers/mtd/maps/netsc520.c b/drivers/mtd/maps/netsc520.c index 95dcab2146ad..c0cb319b2b70 100644 --- a/drivers/mtd/maps/netsc520.c +++ b/drivers/mtd/maps/netsc520.c | |||
| @@ -3,8 +3,6 @@ | |||
| 3 | * Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com) | 3 | * Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com) |
| 4 | * based on sc520cdp.c by Sysgo Real-Time Solutions GmbH | 4 | * based on sc520cdp.c by Sysgo Real-Time Solutions GmbH |
| 5 | * | 5 | * |
| 6 | * $Id: netsc520.c,v 1.14 2005/11/07 11:14:27 gleixner Exp $ | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
| 9 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
| 10 | * the Free Software Foundation; either version 2 of the License, or | 8 | * the Free Software Foundation; either version 2 of the License, or |
diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c index 0c9b305a72e0..965e6c6d6ab0 100644 --- a/drivers/mtd/maps/nettel.c +++ b/drivers/mtd/maps/nettel.c | |||
| @@ -5,8 +5,6 @@ | |||
| 5 | * | 5 | * |
| 6 | * (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com) | 6 | * (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com) |
| 7 | * (C) Copyright 2001-2002, SnapGear (www.snapgear.com) | 7 | * (C) Copyright 2001-2002, SnapGear (www.snapgear.com) |
| 8 | * | ||
| 9 | * $Id: nettel.c,v 1.12 2005/11/29 14:30:00 gleixner Exp $ | ||
| 10 | */ | 8 | */ |
| 11 | 9 | ||
| 12 | /****************************************************************************/ | 10 | /****************************************************************************/ |
diff --git a/drivers/mtd/maps/octagon-5066.c b/drivers/mtd/maps/octagon-5066.c index a6642db3d325..43e04c1d22a9 100644 --- a/drivers/mtd/maps/octagon-5066.c +++ b/drivers/mtd/maps/octagon-5066.c | |||
| @@ -1,4 +1,3 @@ | |||
| 1 | // $Id: octagon-5066.c,v 1.28 2005/11/07 11:14:27 gleixner Exp $ | ||
| 2 | /* ###################################################################### | 1 | /* ###################################################################### |
| 3 | 2 | ||
| 4 | Octagon 5066 MTD Driver. | 3 | Octagon 5066 MTD Driver. |
diff --git a/drivers/mtd/maps/omap-toto-flash.c b/drivers/mtd/maps/omap-toto-flash.c index e6e391efbeb6..0a60ebbc2175 100644 --- a/drivers/mtd/maps/omap-toto-flash.c +++ b/drivers/mtd/maps/omap-toto-flash.c | |||
| @@ -4,8 +4,6 @@ | |||
| 4 | * jzhang@ti.com (C) 2003 Texas Instruments. | 4 | * jzhang@ti.com (C) 2003 Texas Instruments. |
| 5 | * | 5 | * |
| 6 | * (C) 2002 MontVista Software, Inc. | 6 | * (C) 2002 MontVista Software, Inc. |
| 7 | * | ||
| 8 | * $Id: omap-toto-flash.c,v 1.5 2005/11/07 11:14:27 gleixner Exp $ | ||
| 9 | */ | 7 | */ |
| 10 | 8 | ||
| 11 | #include <linux/module.h> | 9 | #include <linux/module.h> |
diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c index d2ab1bae9c34..5c6a25c90380 100644 --- a/drivers/mtd/maps/pci.c +++ b/drivers/mtd/maps/pci.c | |||
| @@ -7,8 +7,6 @@ | |||
| 7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
| 8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
| 9 | * | 9 | * |
| 10 | * $Id: pci.c,v 1.14 2005/11/17 08:20:27 dwmw2 Exp $ | ||
| 11 | * | ||
| 12 | * Generic PCI memory map driver. We support the following boards: | 10 | * Generic PCI memory map driver. We support the following boards: |
| 13 | * - Intel IQ80310 ATU. | 11 | * - Intel IQ80310 ATU. |
| 14 | * - Intel EBSA285 (blank rom programming mode). Tested working 27/09/2001 | 12 | * - Intel EBSA285 (blank rom programming mode). Tested working 27/09/2001 |
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index 0cc31675aeb9..90924fb00481 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: pcmciamtd.c,v 1.55 2005/11/07 11:14:28 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * pcmciamtd.c - MTD driver for PCMCIA flash memory cards | 2 | * pcmciamtd.c - MTD driver for PCMCIA flash memory cards |
| 5 | * | 3 | * |
| 6 | * Author: Simon Evans <spse@secret.org.uk> | 4 | * Author: Simon Evans <spse@secret.org.uk> |
| @@ -48,7 +46,6 @@ static const int debug = 0; | |||
| 48 | 46 | ||
| 49 | 47 | ||
| 50 | #define DRIVER_DESC "PCMCIA Flash memory card driver" | 48 | #define DRIVER_DESC "PCMCIA Flash memory card driver" |
| 51 | #define DRIVER_VERSION "$Revision: 1.55 $" | ||
| 52 | 49 | ||
| 53 | /* Size of the PCMCIA address space: 26 bits = 64 MB */ | 50 | /* Size of the PCMCIA address space: 26 bits = 64 MB */ |
| 54 | #define MAX_PCMCIA_ADDR 0x4000000 | 51 | #define MAX_PCMCIA_ADDR 0x4000000 |
| @@ -785,7 +782,7 @@ static struct pcmcia_driver pcmciamtd_driver = { | |||
| 785 | 782 | ||
| 786 | static int __init init_pcmciamtd(void) | 783 | static int __init init_pcmciamtd(void) |
| 787 | { | 784 | { |
| 788 | info(DRIVER_DESC " " DRIVER_VERSION); | 785 | info(DRIVER_DESC); |
| 789 | 786 | ||
| 790 | if(bankwidth && bankwidth != 1 && bankwidth != 2) { | 787 | if(bankwidth && bankwidth != 1 && bankwidth != 2) { |
| 791 | info("bad bankwidth (%d), using default", bankwidth); | 788 | info("bad bankwidth (%d), using default", bankwidth); |
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index 183255fcfdcb..42d844f8f6bf 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: physmap.c,v 1.39 2005/11/29 14:49:36 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * Normal mappings of chips in physical memory | 2 | * Normal mappings of chips in physical memory |
| 5 | * | 3 | * |
| 6 | * Copyright (C) 2003 MontaVista Software Inc. | 4 | * Copyright (C) 2003 MontaVista Software Inc. |
| @@ -203,7 +201,19 @@ static int physmap_flash_suspend(struct platform_device *dev, pm_message_t state | |||
| 203 | int i; | 201 | int i; |
| 204 | 202 | ||
| 205 | for (i = 0; i < MAX_RESOURCES && info->mtd[i]; i++) | 203 | for (i = 0; i < MAX_RESOURCES && info->mtd[i]; i++) |
| 206 | ret |= info->mtd[i]->suspend(info->mtd[i]); | 204 | if (info->mtd[i]->suspend) { |
| 205 | ret = info->mtd[i]->suspend(info->mtd[i]); | ||
| 206 | if (ret) | ||
| 207 | goto fail; | ||
| 208 | } | ||
| 209 | |||
| 210 | return 0; | ||
| 211 | fail: | ||
| 212 | for (--i; i >= 0; --i) | ||
| 213 | if (info->mtd[i]->suspend) { | ||
| 214 | BUG_ON(!info->mtd[i]->resume); | ||
| 215 | info->mtd[i]->resume(info->mtd[i]); | ||
| 216 | } | ||
| 207 | 217 | ||
| 208 | return ret; | 218 | return ret; |
| 209 | } | 219 | } |
| @@ -214,7 +224,8 @@ static int physmap_flash_resume(struct platform_device *dev) | |||
| 214 | int i; | 224 | int i; |
| 215 | 225 | ||
| 216 | for (i = 0; i < MAX_RESOURCES && info->mtd[i]; i++) | 226 | for (i = 0; i < MAX_RESOURCES && info->mtd[i]; i++) |
| 217 | info->mtd[i]->resume(info->mtd[i]); | 227 | if (info->mtd[i]->resume) |
| 228 | info->mtd[i]->resume(info->mtd[i]); | ||
| 218 | 229 | ||
| 219 | return 0; | 230 | return 0; |
| 220 | } | 231 | } |
| @@ -225,8 +236,9 @@ static void physmap_flash_shutdown(struct platform_device *dev) | |||
| 225 | int i; | 236 | int i; |
| 226 | 237 | ||
| 227 | for (i = 0; i < MAX_RESOURCES && info->mtd[i]; i++) | 238 | for (i = 0; i < MAX_RESOURCES && info->mtd[i]; i++) |
| 228 | if (info->mtd[i]->suspend(info->mtd[i]) == 0) | 239 | if (info->mtd[i]->suspend && info->mtd[i]->resume) |
| 229 | info->mtd[i]->resume(info->mtd[i]); | 240 | if (info->mtd[i]->suspend(info->mtd[i]) == 0) |
| 241 | info->mtd[i]->resume(info->mtd[i]); | ||
| 230 | } | 242 | } |
| 231 | #else | 243 | #else |
| 232 | #define physmap_flash_suspend NULL | 244 | #define physmap_flash_suspend NULL |
diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 3eb2643b2328..e7dd9c8a965e 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c | |||
| @@ -6,8 +6,6 @@ | |||
| 6 | * | 6 | * |
| 7 | * Generic platfrom device based RAM map | 7 | * Generic platfrom device based RAM map |
| 8 | * | 8 | * |
| 9 | * $Id: plat-ram.c,v 1.7 2005/11/07 11:14:28 gleixner Exp $ | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
| 12 | * it under the terms of the GNU General Public License as published by | 10 | * it under the terms of the GNU General Public License as published by |
| 13 | * the Free Software Foundation; either version 2 of the License, or | 11 | * the Free Software Foundation; either version 2 of the License, or |
diff --git a/drivers/mtd/maps/redwood.c b/drivers/mtd/maps/redwood.c index 4d858b3d5f82..de002eb1a7fe 100644 --- a/drivers/mtd/maps/redwood.c +++ b/drivers/mtd/maps/redwood.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: redwood.c,v 1.11 2005/11/07 11:14:28 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * drivers/mtd/maps/redwood.c | 2 | * drivers/mtd/maps/redwood.c |
| 5 | * | 3 | * |
| 6 | * FLASH map for the IBM Redwood 4/5/6 boards. | 4 | * FLASH map for the IBM Redwood 4/5/6 boards. |
diff --git a/drivers/mtd/maps/rpxlite.c b/drivers/mtd/maps/rpxlite.c index 809a0c8e7aaf..14d90edb4430 100644 --- a/drivers/mtd/maps/rpxlite.c +++ b/drivers/mtd/maps/rpxlite.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: rpxlite.c,v 1.22 2004/11/04 13:24:15 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * Handle mapping of the flash on the RPX Lite and CLLF boards | 2 | * Handle mapping of the flash on the RPX Lite and CLLF boards |
| 5 | */ | 3 | */ |
| 6 | 4 | ||
diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index c7d5a52a2d55..e177a43dfff0 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c | |||
| @@ -2,8 +2,6 @@ | |||
| 2 | * Flash memory access on SA11x0 based devices | 2 | * Flash memory access on SA11x0 based devices |
| 3 | * | 3 | * |
| 4 | * (C) 2000 Nicolas Pitre <nico@cam.org> | 4 | * (C) 2000 Nicolas Pitre <nico@cam.org> |
| 5 | * | ||
| 6 | * $Id: sa1100-flash.c,v 1.51 2005/11/07 11:14:28 gleixner Exp $ | ||
| 7 | */ | 5 | */ |
| 8 | #include <linux/module.h> | 6 | #include <linux/module.h> |
| 9 | #include <linux/types.h> | 7 | #include <linux/types.h> |
diff --git a/drivers/mtd/maps/sbc8240.c b/drivers/mtd/maps/sbc8240.c index b8c1331b7a04..6e1e99cd2b59 100644 --- a/drivers/mtd/maps/sbc8240.c +++ b/drivers/mtd/maps/sbc8240.c | |||
| @@ -4,9 +4,6 @@ | |||
| 4 | * Carolyn Smith, Tektronix, Inc. | 4 | * Carolyn Smith, Tektronix, Inc. |
| 5 | * | 5 | * |
| 6 | * This code is GPLed | 6 | * This code is GPLed |
| 7 | * | ||
| 8 | * $Id: sbc8240.c,v 1.5 2005/11/07 11:14:28 gleixner Exp $ | ||
| 9 | * | ||
| 10 | */ | 7 | */ |
| 11 | 8 | ||
| 12 | /* | 9 | /* |
diff --git a/drivers/mtd/maps/sbc_gxx.c b/drivers/mtd/maps/sbc_gxx.c index 7cc4041d096d..1b1c0b7e11ef 100644 --- a/drivers/mtd/maps/sbc_gxx.c +++ b/drivers/mtd/maps/sbc_gxx.c | |||
| @@ -17,8 +17,6 @@ | |||
| 17 | along with this program; if not, write to the Free Software | 17 | along with this program; if not, write to the Free Software |
| 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
| 19 | 19 | ||
| 20 | $Id: sbc_gxx.c,v 1.35 2005/11/07 11:14:28 gleixner Exp $ | ||
| 21 | |||
| 22 | The SBC-MediaGX / SBC-GXx has up to 16 MiB of | 20 | The SBC-MediaGX / SBC-GXx has up to 16 MiB of |
| 23 | Intel StrataFlash (28F320/28F640) in x8 mode. | 21 | Intel StrataFlash (28F320/28F640) in x8 mode. |
| 24 | 22 | ||
diff --git a/drivers/mtd/maps/sc520cdp.c b/drivers/mtd/maps/sc520cdp.c index 4045e372b90d..85c1e56309ec 100644 --- a/drivers/mtd/maps/sc520cdp.c +++ b/drivers/mtd/maps/sc520cdp.c | |||
| @@ -16,8 +16,6 @@ | |||
| 16 | * along with this program; if not, write to the Free Software | 16 | * along with this program; if not, write to the Free Software |
| 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
| 18 | * | 18 | * |
| 19 | * $Id: sc520cdp.c,v 1.23 2005/11/17 08:20:27 dwmw2 Exp $ | ||
| 20 | * | ||
| 21 | * | 19 | * |
| 22 | * The SC520CDP is an evaluation board for the Elan SC520 processor available | 20 | * The SC520CDP is an evaluation board for the Elan SC520 processor available |
| 23 | * from AMD. It has two banks of 32-bit Flash ROM, each 8 Megabytes in size, | 21 | * from AMD. It has two banks of 32-bit Flash ROM, each 8 Megabytes in size, |
diff --git a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c index 0fc5584324e3..21169e6d646c 100644 --- a/drivers/mtd/maps/scb2_flash.c +++ b/drivers/mtd/maps/scb2_flash.c | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * MTD map driver for BIOS Flash on Intel SCB2 boards | 2 | * MTD map driver for BIOS Flash on Intel SCB2 boards |
| 3 | * $Id: scb2_flash.c,v 1.12 2005/03/18 14:04:35 gleixner Exp $ | ||
| 4 | * Copyright (C) 2002 Sun Microsystems, Inc. | 3 | * Copyright (C) 2002 Sun Microsystems, Inc. |
| 5 | * Tim Hockin <thockin@sun.com> | 4 | * Tim Hockin <thockin@sun.com> |
| 6 | * | 5 | * |
diff --git a/drivers/mtd/maps/scx200_docflash.c b/drivers/mtd/maps/scx200_docflash.c index 5e2bce22f37c..b5391ebb736e 100644 --- a/drivers/mtd/maps/scx200_docflash.c +++ b/drivers/mtd/maps/scx200_docflash.c | |||
| @@ -2,8 +2,6 @@ | |||
| 2 | 2 | ||
| 3 | Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> | 3 | Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> |
| 4 | 4 | ||
| 5 | $Id: scx200_docflash.c,v 1.12 2005/11/07 11:14:28 gleixner Exp $ | ||
| 6 | |||
| 7 | National Semiconductor SCx200 flash mapped with DOCCS | 5 | National Semiconductor SCx200 flash mapped with DOCCS |
| 8 | */ | 6 | */ |
| 9 | 7 | ||
diff --git a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c index 917dc778f24e..026eab028189 100644 --- a/drivers/mtd/maps/sharpsl-flash.c +++ b/drivers/mtd/maps/sharpsl-flash.c | |||
| @@ -4,8 +4,6 @@ | |||
| 4 | * Copyright (C) 2001 Lineo Japan, Inc. | 4 | * Copyright (C) 2001 Lineo Japan, Inc. |
| 5 | * Copyright (C) 2002 SHARP | 5 | * Copyright (C) 2002 SHARP |
| 6 | * | 6 | * |
| 7 | * $Id: sharpsl-flash.c,v 1.7 2005/11/07 11:14:28 gleixner Exp $ | ||
| 8 | * | ||
| 9 | * based on rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp | 7 | * based on rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp |
| 10 | * Handle mapping of the flash on the RPX Lite and CLLF boards | 8 | * Handle mapping of the flash on the RPX Lite and CLLF boards |
| 11 | * | 9 | * |
diff --git a/drivers/mtd/maps/solutionengine.c b/drivers/mtd/maps/solutionengine.c index d76ceef453ce..0eb41d9c6786 100644 --- a/drivers/mtd/maps/solutionengine.c +++ b/drivers/mtd/maps/solutionengine.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: solutionengine.c,v 1.15 2005/11/07 11:14:28 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * Flash and EPROM on Hitachi Solution Engine and similar boards. | 2 | * Flash and EPROM on Hitachi Solution Engine and similar boards. |
| 5 | * | 3 | * |
| 6 | * (C) 2001 Red Hat, Inc. | 4 | * (C) 2001 Red Hat, Inc. |
diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 001af7f7ddda..0d7c88396c88 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $Id: sun_uflash.c,v 1.13 2005/11/07 11:14:28 gleixner Exp $ | 1 | /* |
| 2 | * | 2 | * |
| 3 | * sun_uflash - Driver implementation for user-programmable flash | 3 | * sun_uflash - Driver implementation for user-programmable flash |
| 4 | * present on many Sun Microsystems SME boardsets. | 4 | * present on many Sun Microsystems SME boardsets. |
diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c index 521734057314..a5d3d8531faa 100644 --- a/drivers/mtd/maps/tqm8xxl.c +++ b/drivers/mtd/maps/tqm8xxl.c | |||
| @@ -2,8 +2,6 @@ | |||
| 2 | * Handle mapping of the flash memory access routines | 2 | * Handle mapping of the flash memory access routines |
| 3 | * on TQM8xxL based devices. | 3 | * on TQM8xxL based devices. |
| 4 | * | 4 | * |
| 5 | * $Id: tqm8xxl.c,v 1.15 2005/11/07 11:14:28 gleixner Exp $ | ||
| 6 | * | ||
| 7 | * based on rpxlite.c | 5 | * based on rpxlite.c |
| 8 | * | 6 | * |
| 9 | * Copyright(C) 2001 Kirk Lee <kirk@hpc.ee.ntu.edu.tw> | 7 | * Copyright(C) 2001 Kirk Lee <kirk@hpc.ee.ntu.edu.tw> |
diff --git a/drivers/mtd/maps/ts5500_flash.c b/drivers/mtd/maps/ts5500_flash.c index b47270e850bc..e2147bf11c88 100644 --- a/drivers/mtd/maps/ts5500_flash.c +++ b/drivers/mtd/maps/ts5500_flash.c | |||
| @@ -22,8 +22,6 @@ | |||
| 22 | * - Drive A and B use the resident flash disk (RFD) flash translation layer. | 22 | * - Drive A and B use the resident flash disk (RFD) flash translation layer. |
| 23 | * - If you have created your own jffs file system and the bios overwrites | 23 | * - If you have created your own jffs file system and the bios overwrites |
| 24 | * it during boot, try disabling Drive A: and B: in the boot order. | 24 | * it during boot, try disabling Drive A: and B: in the boot order. |
| 25 | * | ||
| 26 | * $Id: ts5500_flash.c,v 1.5 2005/11/07 11:14:28 gleixner Exp $ | ||
| 27 | */ | 25 | */ |
| 28 | 26 | ||
| 29 | #include <linux/init.h> | 27 | #include <linux/init.h> |
diff --git a/drivers/mtd/maps/tsunami_flash.c b/drivers/mtd/maps/tsunami_flash.c index 0f915ac3102e..77a8bfc02577 100644 --- a/drivers/mtd/maps/tsunami_flash.c +++ b/drivers/mtd/maps/tsunami_flash.c | |||
| @@ -2,7 +2,6 @@ | |||
| 2 | * tsunami_flash.c | 2 | * tsunami_flash.c |
| 3 | * | 3 | * |
| 4 | * flash chip on alpha ds10... | 4 | * flash chip on alpha ds10... |
| 5 | * $Id: tsunami_flash.c,v 1.10 2005/11/07 11:14:29 gleixner Exp $ | ||
| 6 | */ | 5 | */ |
| 7 | #include <asm/io.h> | 6 | #include <asm/io.h> |
| 8 | #include <asm/core_tsunami.h> | 7 | #include <asm/core_tsunami.h> |
diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c index 3fcf92130aa4..0dc645f8152f 100644 --- a/drivers/mtd/maps/uclinux.c +++ b/drivers/mtd/maps/uclinux.c | |||
| @@ -4,8 +4,6 @@ | |||
| 4 | * uclinux.c -- generic memory mapped MTD driver for uclinux | 4 | * uclinux.c -- generic memory mapped MTD driver for uclinux |
| 5 | * | 5 | * |
| 6 | * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) | 6 | * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) |
| 7 | * | ||
| 8 | * $Id: uclinux.c,v 1.12 2005/11/07 11:14:29 gleixner Exp $ | ||
| 9 | */ | 7 | */ |
| 10 | 8 | ||
| 11 | /****************************************************************************/ | 9 | /****************************************************************************/ |
diff --git a/drivers/mtd/maps/vmax301.c b/drivers/mtd/maps/vmax301.c index b3e487395435..5a0c9a353b0f 100644 --- a/drivers/mtd/maps/vmax301.c +++ b/drivers/mtd/maps/vmax301.c | |||
| @@ -1,4 +1,3 @@ | |||
| 1 | // $Id: vmax301.c,v 1.32 2005/11/07 11:14:29 gleixner Exp $ | ||
| 2 | /* ###################################################################### | 1 | /* ###################################################################### |
| 3 | 2 | ||
| 4 | Tempustech VMAX SBC301 MTD Driver. | 3 | Tempustech VMAX SBC301 MTD Driver. |
diff --git a/drivers/mtd/maps/walnut.c b/drivers/mtd/maps/walnut.c index ca932122fb64..e243476c8171 100644 --- a/drivers/mtd/maps/walnut.c +++ b/drivers/mtd/maps/walnut.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: walnut.c,v 1.3 2005/11/07 11:14:29 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * Mapping for Walnut flash | 2 | * Mapping for Walnut flash |
| 5 | * (used ebony.c as a "framework") | 3 | * (used ebony.c as a "framework") |
| 6 | * | 4 | * |
diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c index ac5b8105b6ef..413b0cf9bbd2 100644 --- a/drivers/mtd/maps/wr_sbc82xx_flash.c +++ b/drivers/mtd/maps/wr_sbc82xx_flash.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: wr_sbc82xx_flash.c,v 1.8 2005/11/07 11:14:29 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * Map for flash chips on Wind River PowerQUICC II SBC82xx board. | 2 | * Map for flash chips on Wind River PowerQUICC II SBC82xx board. |
| 5 | * | 3 | * |
| 6 | * Copyright (C) 2004 Red Hat, Inc. | 4 | * Copyright (C) 2004 Red Hat, Inc. |
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 839eed8430a2..9ff007c4962c 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: mtd_blkdevs.c,v 1.27 2005/11/07 11:14:20 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * (C) 2003 David Woodhouse <dwmw2@infradead.org> | 2 | * (C) 2003 David Woodhouse <dwmw2@infradead.org> |
| 5 | * | 3 | * |
| 6 | * Interface to Linux 2.5 block layer for MTD 'translation layers'. | 4 | * Interface to Linux 2.5 block layer for MTD 'translation layers'. |
| @@ -212,7 +210,7 @@ static struct block_device_operations mtd_blktrans_ops = { | |||
| 212 | int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) | 210 | int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) |
| 213 | { | 211 | { |
| 214 | struct mtd_blktrans_ops *tr = new->tr; | 212 | struct mtd_blktrans_ops *tr = new->tr; |
| 215 | struct list_head *this; | 213 | struct mtd_blktrans_dev *d; |
| 216 | int last_devnum = -1; | 214 | int last_devnum = -1; |
| 217 | struct gendisk *gd; | 215 | struct gendisk *gd; |
| 218 | 216 | ||
| @@ -221,8 +219,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) | |||
| 221 | BUG(); | 219 | BUG(); |
| 222 | } | 220 | } |
| 223 | 221 | ||
| 224 | list_for_each(this, &tr->devs) { | 222 | list_for_each_entry(d, &tr->devs, list) { |
| 225 | struct mtd_blktrans_dev *d = list_entry(this, struct mtd_blktrans_dev, list); | ||
| 226 | if (new->devnum == -1) { | 223 | if (new->devnum == -1) { |
| 227 | /* Use first free number */ | 224 | /* Use first free number */ |
| 228 | if (d->devnum != last_devnum+1) { | 225 | if (d->devnum != last_devnum+1) { |
| @@ -309,33 +306,24 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) | |||
| 309 | 306 | ||
| 310 | static void blktrans_notify_remove(struct mtd_info *mtd) | 307 | static void blktrans_notify_remove(struct mtd_info *mtd) |
| 311 | { | 308 | { |
| 312 | struct list_head *this, *this2, *next; | 309 | struct mtd_blktrans_ops *tr; |
| 313 | 310 | struct mtd_blktrans_dev *dev, *next; | |
| 314 | list_for_each(this, &blktrans_majors) { | ||
| 315 | struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list); | ||
| 316 | |||
| 317 | list_for_each_safe(this2, next, &tr->devs) { | ||
| 318 | struct mtd_blktrans_dev *dev = list_entry(this2, struct mtd_blktrans_dev, list); | ||
| 319 | 311 | ||
| 312 | list_for_each_entry(tr, &blktrans_majors, list) | ||
| 313 | list_for_each_entry_safe(dev, next, &tr->devs, list) | ||
| 320 | if (dev->mtd == mtd) | 314 | if (dev->mtd == mtd) |
| 321 | tr->remove_dev(dev); | 315 | tr->remove_dev(dev); |
| 322 | } | ||
| 323 | } | ||
| 324 | } | 316 | } |
| 325 | 317 | ||
| 326 | static void blktrans_notify_add(struct mtd_info *mtd) | 318 | static void blktrans_notify_add(struct mtd_info *mtd) |
| 327 | { | 319 | { |
| 328 | struct list_head *this; | 320 | struct mtd_blktrans_ops *tr; |
| 329 | 321 | ||
| 330 | if (mtd->type == MTD_ABSENT) | 322 | if (mtd->type == MTD_ABSENT) |
| 331 | return; | 323 | return; |
| 332 | 324 | ||
| 333 | list_for_each(this, &blktrans_majors) { | 325 | list_for_each_entry(tr, &blktrans_majors, list) |
| 334 | struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list); | ||
| 335 | |||
| 336 | tr->add_mtd(tr, mtd); | 326 | tr->add_mtd(tr, mtd); |
| 337 | } | ||
| 338 | |||
| 339 | } | 327 | } |
| 340 | 328 | ||
| 341 | static struct mtd_notifier blktrans_notifier = { | 329 | static struct mtd_notifier blktrans_notifier = { |
| @@ -406,7 +394,7 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) | |||
| 406 | 394 | ||
| 407 | int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr) | 395 | int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr) |
| 408 | { | 396 | { |
| 409 | struct list_head *this, *next; | 397 | struct mtd_blktrans_dev *dev, *next; |
| 410 | 398 | ||
| 411 | mutex_lock(&mtd_table_mutex); | 399 | mutex_lock(&mtd_table_mutex); |
| 412 | 400 | ||
| @@ -416,10 +404,8 @@ int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr) | |||
| 416 | /* Remove it from the list of active majors */ | 404 | /* Remove it from the list of active majors */ |
| 417 | list_del(&tr->list); | 405 | list_del(&tr->list); |
| 418 | 406 | ||
| 419 | list_for_each_safe(this, next, &tr->devs) { | 407 | list_for_each_entry_safe(dev, next, &tr->devs, list) |
| 420 | struct mtd_blktrans_dev *dev = list_entry(this, struct mtd_blktrans_dev, list); | ||
| 421 | tr->remove_dev(dev); | 408 | tr->remove_dev(dev); |
| 422 | } | ||
| 423 | 409 | ||
| 424 | blk_cleanup_queue(tr->blkcore_priv->rq); | 410 | blk_cleanup_queue(tr->blkcore_priv->rq); |
| 425 | unregister_blkdev(tr->major, tr->name); | 411 | unregister_blkdev(tr->major, tr->name); |
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 952da30b1745..208c6faa0358 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Direct MTD block device access | 2 | * Direct MTD block device access |
| 3 | * | 3 | * |
| 4 | * $Id: mtdblock.c,v 1.68 2005/11/07 11:14:20 gleixner Exp $ | ||
| 5 | * | ||
| 6 | * (C) 2000-2003 Nicolas Pitre <nico@cam.org> | 4 | * (C) 2000-2003 Nicolas Pitre <nico@cam.org> |
| 7 | * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> | 5 | * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> |
| 8 | */ | 6 | */ |
diff --git a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c index f79dbb49b1a2..852165f8b1c3 100644 --- a/drivers/mtd/mtdblock_ro.c +++ b/drivers/mtd/mtdblock_ro.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: mtdblock_ro.c,v 1.19 2004/11/16 18:28:59 dwmw2 Exp $ | ||
| 3 | * | ||
| 4 | * (C) 2003 David Woodhouse <dwmw2@infradead.org> | 2 | * (C) 2003 David Woodhouse <dwmw2@infradead.org> |
| 5 | * | 3 | * |
| 6 | * Simple read-only (writable only for RAM) mtdblock driver | 4 | * Simple read-only (writable only for RAM) mtdblock driver |
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index aef9f4b687c9..d2f331876e4c 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: mtdchar.c,v 1.76 2005/11/07 11:14:20 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * Character-device access to raw MTD devices. | 2 | * Character-device access to raw MTD devices. |
| 5 | * | 3 | * |
| 6 | */ | 4 | */ |
| @@ -494,6 +492,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
| 494 | { | 492 | { |
| 495 | struct mtd_oob_buf buf; | 493 | struct mtd_oob_buf buf; |
| 496 | struct mtd_oob_ops ops; | 494 | struct mtd_oob_ops ops; |
| 495 | struct mtd_oob_buf __user *user_buf = argp; | ||
| 497 | uint32_t retlen; | 496 | uint32_t retlen; |
| 498 | 497 | ||
| 499 | if(!(file->f_mode & 2)) | 498 | if(!(file->f_mode & 2)) |
| @@ -537,8 +536,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
| 537 | if (ops.oobretlen > 0xFFFFFFFFU) | 536 | if (ops.oobretlen > 0xFFFFFFFFU) |
| 538 | ret = -EOVERFLOW; | 537 | ret = -EOVERFLOW; |
| 539 | retlen = ops.oobretlen; | 538 | retlen = ops.oobretlen; |
| 540 | if (copy_to_user(&((struct mtd_oob_buf *)argp)->length, | 539 | if (copy_to_user(&user_buf->length, &retlen, sizeof(buf.length))) |
| 541 | &retlen, sizeof(buf.length))) | ||
| 542 | ret = -EFAULT; | 540 | ret = -EFAULT; |
| 543 | 541 | ||
| 544 | kfree(ops.oobbuf); | 542 | kfree(ops.oobbuf); |
| @@ -592,29 +590,29 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
| 592 | 590 | ||
| 593 | case MEMLOCK: | 591 | case MEMLOCK: |
| 594 | { | 592 | { |
| 595 | struct erase_info_user info; | 593 | struct erase_info_user einfo; |
| 596 | 594 | ||
| 597 | if (copy_from_user(&info, argp, sizeof(info))) | 595 | if (copy_from_user(&einfo, argp, sizeof(einfo))) |
| 598 | return -EFAULT; | 596 | return -EFAULT; |
| 599 | 597 | ||
| 600 | if (!mtd->lock) | 598 | if (!mtd->lock) |
| 601 | ret = -EOPNOTSUPP; | 599 | ret = -EOPNOTSUPP; |
| 602 | else | 600 | else |
| 603 | ret = mtd->lock(mtd, info.start, info.length); | 601 | ret = mtd->lock(mtd, einfo.start, einfo.length); |
| 604 | break; | 602 | break; |
| 605 | } | 603 | } |
| 606 | 604 | ||
| 607 | case MEMUNLOCK: | 605 | case MEMUNLOCK: |
| 608 | { | 606 | { |
| 609 | struct erase_info_user info; | 607 | struct erase_info_user einfo; |
| 610 | 608 | ||
| 611 | if (copy_from_user(&info, argp, sizeof(info))) | 609 | if (copy_from_user(&einfo, argp, sizeof(einfo))) |
| 612 | return -EFAULT; | 610 | return -EFAULT; |
| 613 | 611 | ||
| 614 | if (!mtd->unlock) | 612 | if (!mtd->unlock) |
| 615 | ret = -EOPNOTSUPP; | 613 | ret = -EOPNOTSUPP; |
| 616 | else | 614 | else |
| 617 | ret = mtd->unlock(mtd, info.start, info.length); | 615 | ret = mtd->unlock(mtd, einfo.start, einfo.length); |
| 618 | break; | 616 | break; |
| 619 | } | 617 | } |
| 620 | 618 | ||
| @@ -714,15 +712,15 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
| 714 | 712 | ||
| 715 | case OTPLOCK: | 713 | case OTPLOCK: |
| 716 | { | 714 | { |
| 717 | struct otp_info info; | 715 | struct otp_info oinfo; |
| 718 | 716 | ||
| 719 | if (mfi->mode != MTD_MODE_OTP_USER) | 717 | if (mfi->mode != MTD_MODE_OTP_USER) |
| 720 | return -EINVAL; | 718 | return -EINVAL; |
| 721 | if (copy_from_user(&info, argp, sizeof(info))) | 719 | if (copy_from_user(&oinfo, argp, sizeof(oinfo))) |
| 722 | return -EFAULT; | 720 | return -EFAULT; |
| 723 | if (!mtd->lock_user_prot_reg) | 721 | if (!mtd->lock_user_prot_reg) |
| 724 | return -EOPNOTSUPP; | 722 | return -EOPNOTSUPP; |
| 725 | ret = mtd->lock_user_prot_reg(mtd, info.start, info.length); | 723 | ret = mtd->lock_user_prot_reg(mtd, oinfo.start, oinfo.length); |
| 726 | break; | 724 | break; |
| 727 | } | 725 | } |
| 728 | #endif | 726 | #endif |
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index d563dcd4b264..2972a5edb73d 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c | |||
| @@ -6,8 +6,6 @@ | |||
| 6 | * NAND support by Christian Gan <cgan@iders.ca> | 6 | * NAND support by Christian Gan <cgan@iders.ca> |
| 7 | * | 7 | * |
| 8 | * This code is GPL | 8 | * This code is GPL |
| 9 | * | ||
| 10 | * $Id: mtdconcat.c,v 1.11 2005/11/07 11:14:20 gleixner Exp $ | ||
| 11 | */ | 9 | */ |
| 12 | 10 | ||
| 13 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index f7e7890e5bc6..a9d246949820 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: mtdcore.c,v 1.47 2005/11/07 11:14:20 gleixner Exp $ | ||
| 3 | * | ||
| 4 | * Core registration and callback routines for MTD | 2 | * Core registration and callback routines for MTD |
| 5 | * drivers and users. | 3 | * drivers and users. |
| 6 | * | 4 | * |
| @@ -53,7 +51,7 @@ int add_mtd_device(struct mtd_info *mtd) | |||
| 53 | 51 | ||
| 54 | for (i=0; i < MAX_MTD_DEVICES; i++) | 52 | for (i=0; i < MAX_MTD_DEVICES; i++) |
| 55 | if (!mtd_table[i]) { | 53 | if (!mtd_table[i]) { |
| 56 | struct list_head *this; | 54 | struct mtd_notifier *not; |
| 57 | 55 | ||
| 58 | mtd_table[i] = mtd; | 56 | mtd_table[i] = mtd; |
| 59 | mtd->index = i; | 57 | mtd->index = i; |
| @@ -72,10 +70,8 @@ int add_mtd_device(struct mtd_info *mtd) | |||
| 72 | DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name); | 70 | DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name); |
| 73 | /* No need to get a refcount on the module containing | 71 | /* No need to get a refcount on the module containing |
| 74 | the notifier, since we hold the mtd_table_mutex */ | 72 | the notifier, since we hold the mtd_table_mutex */ |
| 75 | list_for_each(this, &mtd_notifiers) { | 73 | list_for_each_entry(not, &mtd_notifiers, list) |
| 76 | struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list); | ||
| 77 | not->add(mtd); | 74 | not->add(mtd); |
| 78 | } | ||
| 79 | 75 | ||
| 80 | mutex_unlock(&mtd_table_mutex); | 76 | mutex_unlock(&mtd_table_mutex); |
| 81 | /* We _know_ we aren't being removed, because | 77 | /* We _know_ we aren't being removed, because |
| @@ -113,14 +109,12 @@ int del_mtd_device (struct mtd_info *mtd) | |||
| 113 | mtd->index, mtd->name, mtd->usecount); | 109 | mtd->index, mtd->name, mtd->usecount); |
| 114 | ret = -EBUSY; | 110 | ret = -EBUSY; |
| 115 | } else { | 111 | } else { |
| 116 | struct list_head *this; | 112 | struct mtd_notifier *not; |
| 117 | 113 | ||
| 118 | /* No need to get a refcount on the module containing | 114 | /* No need to get a refcount on the module containing |
| 119 | the notifier, since we hold the mtd_table_mutex */ | 115 | the notifier, since we hold the mtd_table_mutex */ |
| 120 | list_for_each(this, &mtd_notifiers) { | 116 | list_for_each_entry(not, &mtd_notifiers, list) |
| 121 | struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list); | ||
| 122 | not->remove(mtd); | 117 | not->remove(mtd); |
| 123 | } | ||
| 124 | 118 | ||
| 125 | mtd_table[mtd->index] = NULL; | 119 | mtd_table[mtd->index] = NULL; |
| 126 | 120 | ||
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 07c701169344..edb90b58a9b1 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c | |||
| @@ -5,8 +5,6 @@ | |||
| 5 | * | 5 | * |
| 6 | * This code is GPL | 6 | * This code is GPL |
| 7 | * | 7 | * |
| 8 | * $Id: mtdpart.c,v 1.55 2005/11/07 11:14:20 gleixner Exp $ | ||
| 9 | * | ||
| 10 | * 02-21-2002 Thomas Gleixner <gleixner@autronix.de> | 8 | * 02-21-2002 Thomas Gleixner <gleixner@autronix.de> |
| 11 | * added support for read_oob, write_oob | 9 | * added support for read_oob, write_oob |
| 12 | */ | 10 | */ |
| @@ -46,8 +44,8 @@ struct mtd_part { | |||
| 46 | * to the _real_ device. | 44 | * to the _real_ device. |
| 47 | */ | 45 | */ |
| 48 | 46 | ||
| 49 | static int part_read (struct mtd_info *mtd, loff_t from, size_t len, | 47 | static int part_read(struct mtd_info *mtd, loff_t from, size_t len, |
| 50 | size_t *retlen, u_char *buf) | 48 | size_t *retlen, u_char *buf) |
| 51 | { | 49 | { |
| 52 | struct mtd_part *part = PART(mtd); | 50 | struct mtd_part *part = PART(mtd); |
| 53 | int res; | 51 | int res; |
| @@ -56,7 +54,7 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len, | |||
| 56 | len = 0; | 54 | len = 0; |
| 57 | else if (from + len > mtd->size) | 55 | else if (from + len > mtd->size) |
| 58 | len = mtd->size - from; | 56 | len = mtd->size - from; |
| 59 | res = part->master->read (part->master, from + part->offset, | 57 | res = part->master->read(part->master, from + part->offset, |
| 60 | len, retlen, buf); | 58 | len, retlen, buf); |
| 61 | if (unlikely(res)) { | 59 | if (unlikely(res)) { |
| 62 | if (res == -EUCLEAN) | 60 | if (res == -EUCLEAN) |
| @@ -67,8 +65,8 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len, | |||
| 67 | return res; | 65 | return res; |
| 68 | } | 66 | } |
| 69 | 67 | ||
| 70 | static int part_point (struct mtd_info *mtd, loff_t from, size_t len, | 68 | static int part_point(struct mtd_info *mtd, loff_t from, size_t len, |
| 71 | size_t *retlen, void **virt, resource_size_t *phys) | 69 | size_t *retlen, void **virt, resource_size_t *phys) |
| 72 | { | 70 | { |
| 73 | struct mtd_part *part = PART(mtd); | 71 | struct mtd_part *part = PART(mtd); |
| 74 | if (from >= mtd->size) | 72 | if (from >= mtd->size) |
| @@ -87,7 +85,7 @@ static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len) | |||
| 87 | } | 85 | } |
| 88 | 86 | ||
| 89 | static int part_read_oob(struct mtd_info *mtd, loff_t from, | 87 | static int part_read_oob(struct mtd_info *mtd, loff_t from, |
| 90 | struct mtd_oob_ops *ops) | 88 | struct mtd_oob_ops *ops) |
| 91 | { | 89 | { |
| 92 | struct mtd_part *part = PART(mtd); | 90 | struct mtd_part *part = PART(mtd); |
| 93 | int res; | 91 | int res; |
| @@ -107,38 +105,38 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, | |||
| 107 | return res; | 105 | return res; |
| 108 | } | 106 | } |
| 109 | 107 | ||
| 110 | static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, | 108 | static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from, |
| 111 | size_t *retlen, u_char *buf) | 109 | size_t len, size_t *retlen, u_char *buf) |
| 112 | { | 110 | { |
| 113 | struct mtd_part *part = PART(mtd); | 111 | struct mtd_part *part = PART(mtd); |
| 114 | return part->master->read_user_prot_reg (part->master, from, | 112 | return part->master->read_user_prot_reg(part->master, from, |
| 115 | len, retlen, buf); | 113 | len, retlen, buf); |
| 116 | } | 114 | } |
| 117 | 115 | ||
| 118 | static int part_get_user_prot_info (struct mtd_info *mtd, | 116 | static int part_get_user_prot_info(struct mtd_info *mtd, |
| 119 | struct otp_info *buf, size_t len) | 117 | struct otp_info *buf, size_t len) |
| 120 | { | 118 | { |
| 121 | struct mtd_part *part = PART(mtd); | 119 | struct mtd_part *part = PART(mtd); |
| 122 | return part->master->get_user_prot_info (part->master, buf, len); | 120 | return part->master->get_user_prot_info(part->master, buf, len); |
| 123 | } | 121 | } |
| 124 | 122 | ||
| 125 | static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, | 123 | static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, |
| 126 | size_t *retlen, u_char *buf) | 124 | size_t len, size_t *retlen, u_char *buf) |
| 127 | { | 125 | { |
| 128 | struct mtd_part *part = PART(mtd); | 126 | struct mtd_part *part = PART(mtd); |
| 129 | return part->master->read_fact_prot_reg (part->master, from, | 127 | return part->master->read_fact_prot_reg(part->master, from, |
| 130 | len, retlen, buf); | 128 | len, retlen, buf); |
| 131 | } | 129 | } |
| 132 | 130 | ||
| 133 | static int part_get_fact_prot_info (struct mtd_info *mtd, | 131 | static int part_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf, |
| 134 | struct otp_info *buf, size_t len) | 132 | size_t len) |
| 135 | { | 133 | { |
| 136 | struct mtd_part *part = PART(mtd); | 134 | struct mtd_part *part = PART(mtd); |
| 137 | return part->master->get_fact_prot_info (part->master, buf, len); | 135 | return part->master->get_fact_prot_info(part->master, buf, len); |
| 138 | } | 136 | } |
| 139 | 137 | ||
| 140 | static int part_write (struct mtd_info *mtd, loff_t to, size_t len, | 138 | static int part_write(struct mtd_info *mtd, loff_t to, size_t len, |
| 141 | size_t *retlen, const u_char *buf) | 139 | size_t *retlen, const u_char *buf) |
| 142 | { | 140 | { |
| 143 | struct mtd_part *part = PART(mtd); | 141 | struct mtd_part *part = PART(mtd); |
| 144 | if (!(mtd->flags & MTD_WRITEABLE)) | 142 | if (!(mtd->flags & MTD_WRITEABLE)) |
| @@ -147,12 +145,12 @@ static int part_write (struct mtd_info *mtd, loff_t to, size_t len, | |||
| 147 | len = 0; | 145 | len = 0; |
| 148 | else if (to + len > mtd->size) | 146 | else if (to + len > mtd->size) |
| 149 | len = mtd->size - to; | 147 | len = mtd->size - to; |
| 150 | return part->master->write (part->master, to + part->offset, | 148 | return part->master->write(part->master, to + part->offset, |
| 151 | len, retlen, buf); | 149 | len, retlen, buf); |
| 152 | } | 150 | } |
| 153 | 151 | ||
| 154 | static int part_panic_write (struct mtd_info *mtd, loff_t to, size_t len, | 152 | static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len, |
| 155 | size_t *retlen, const u_char *buf) | 153 | size_t *retlen, const u_char *buf) |
| 156 | { | 154 | { |
| 157 | struct mtd_part *part = PART(mtd); | 155 | struct mtd_part *part = PART(mtd); |
| 158 | if (!(mtd->flags & MTD_WRITEABLE)) | 156 | if (!(mtd->flags & MTD_WRITEABLE)) |
| @@ -161,12 +159,12 @@ static int part_panic_write (struct mtd_info *mtd, loff_t to, size_t len, | |||
| 161 | len = 0; | 159 | len = 0; |
| 162 | else if (to + len > mtd->size) | 160 | else if (to + len > mtd->size) |
| 163 | len = mtd->size - to; | 161 | len = mtd->size - to; |
| 164 | return part->master->panic_write (part->master, to + part->offset, | 162 | return part->master->panic_write(part->master, to + part->offset, |
| 165 | len, retlen, buf); | 163 | len, retlen, buf); |
| 166 | } | 164 | } |
| 167 | 165 | ||
| 168 | static int part_write_oob(struct mtd_info *mtd, loff_t to, | 166 | static int part_write_oob(struct mtd_info *mtd, loff_t to, |
| 169 | struct mtd_oob_ops *ops) | 167 | struct mtd_oob_ops *ops) |
| 170 | { | 168 | { |
| 171 | struct mtd_part *part = PART(mtd); | 169 | struct mtd_part *part = PART(mtd); |
| 172 | 170 | ||
| @@ -180,31 +178,32 @@ static int part_write_oob(struct mtd_info *mtd, loff_t to, | |||
| 180 | return part->master->write_oob(part->master, to + part->offset, ops); | 178 | return part->master->write_oob(part->master, to + part->offset, ops); |
| 181 | } | 179 | } |
| 182 | 180 | ||
| 183 | static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, | 181 | static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from, |
| 184 | size_t *retlen, u_char *buf) | 182 | size_t len, size_t *retlen, u_char *buf) |
| 185 | { | 183 | { |
| 186 | struct mtd_part *part = PART(mtd); | 184 | struct mtd_part *part = PART(mtd); |
| 187 | return part->master->write_user_prot_reg (part->master, from, | 185 | return part->master->write_user_prot_reg(part->master, from, |
| 188 | len, retlen, buf); | 186 | len, retlen, buf); |
| 189 | } | 187 | } |
| 190 | 188 | ||
| 191 | static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len) | 189 | static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, |
| 190 | size_t len) | ||
| 192 | { | 191 | { |
| 193 | struct mtd_part *part = PART(mtd); | 192 | struct mtd_part *part = PART(mtd); |
| 194 | return part->master->lock_user_prot_reg (part->master, from, len); | 193 | return part->master->lock_user_prot_reg(part->master, from, len); |
| 195 | } | 194 | } |
| 196 | 195 | ||
| 197 | static int part_writev (struct mtd_info *mtd, const struct kvec *vecs, | 196 | static int part_writev(struct mtd_info *mtd, const struct kvec *vecs, |
| 198 | unsigned long count, loff_t to, size_t *retlen) | 197 | unsigned long count, loff_t to, size_t *retlen) |
| 199 | { | 198 | { |
| 200 | struct mtd_part *part = PART(mtd); | 199 | struct mtd_part *part = PART(mtd); |
| 201 | if (!(mtd->flags & MTD_WRITEABLE)) | 200 | if (!(mtd->flags & MTD_WRITEABLE)) |
| 202 | return -EROFS; | 201 | return -EROFS; |
| 203 | return part->master->writev (part->master, vecs, count, | 202 | return part->master->writev(part->master, vecs, count, |
| 204 | to + part->offset, retlen); | 203 | to + part->offset, retlen); |
| 205 | } | 204 | } |
| 206 | 205 | ||
| 207 | static int part_erase (struct mtd_info *mtd, struct erase_info *instr) | 206 | static int part_erase(struct mtd_info *mtd, struct erase_info *instr) |
| 208 | { | 207 | { |
| 209 | struct mtd_part *part = PART(mtd); | 208 | struct mtd_part *part = PART(mtd); |
| 210 | int ret; | 209 | int ret; |
| @@ -236,7 +235,7 @@ void mtd_erase_callback(struct erase_info *instr) | |||
| 236 | } | 235 | } |
| 237 | EXPORT_SYMBOL_GPL(mtd_erase_callback); | 236 | EXPORT_SYMBOL_GPL(mtd_erase_callback); |
| 238 | 237 | ||
| 239 | static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len) | 238 | static int part_lock(struct mtd_info *mtd, loff_t ofs, size_t len) |
| 240 | { | 239 | { |
| 241 | struct mtd_part *part = PART(mtd); | 240 | struct mtd_part *part = PART(mtd); |
| 242 | if ((len + ofs) > mtd->size) | 241 | if ((len + ofs) > mtd->size) |
| @@ -244,7 +243,7 @@ static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len) | |||
| 244 | return part->master->lock(part->master, ofs + part->offset, len); | 243 | return part->master->lock(part->master, ofs + part->offset, len); |
| 245 | } | 244 | } |
| 246 | 245 | ||
| 247 | static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len) | 246 | static int part_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) |
| 248 | { | 247 | { |
| 249 | struct mtd_part *part = PART(mtd); | 248 | struct mtd_part *part = PART(mtd); |
| 250 | if ((len + ofs) > mtd->size) | 249 | if ((len + ofs) > mtd->size) |
| @@ -270,7 +269,7 @@ static void part_resume(struct mtd_info *mtd) | |||
| 270 | part->master->resume(part->master); | 269 | part->master->resume(part->master); |
| 271 | } | 270 | } |
| 272 | 271 | ||
| 273 | static int part_block_isbad (struct mtd_info *mtd, loff_t ofs) | 272 | static int part_block_isbad(struct mtd_info *mtd, loff_t ofs) |
| 274 | { | 273 | { |
| 275 | struct mtd_part *part = PART(mtd); | 274 | struct mtd_part *part = PART(mtd); |
| 276 | if (ofs >= mtd->size) | 275 | if (ofs >= mtd->size) |
| @@ -279,7 +278,7 @@ static int part_block_isbad (struct mtd_info *mtd, loff_t ofs) | |||
| 279 | return part->master->block_isbad(part->master, ofs); | 278 | return part->master->block_isbad(part->master, ofs); |
| 280 | } | 279 | } |
| 281 | 280 | ||
| 282 | static int part_block_markbad (struct mtd_info *mtd, loff_t ofs) | 281 | static int part_block_markbad(struct mtd_info *mtd, loff_t ofs) |
| 283 | { | 282 | { |
| 284 | struct mtd_part *part = PART(mtd); | 283 | struct mtd_part *part = PART(mtd); |
| 285 | int res; | 284 | int res; |
| @@ -302,229 +301,237 @@ static int part_block_markbad (struct mtd_info *mtd, loff_t ofs) | |||
| 302 | 301 | ||
| 303 | int del_mtd_partitions(struct mtd_info *master) | 302 | int del_mtd_partitions(struct mtd_info *master) |
| 304 | { | 303 | { |
| 305 | struct list_head *node; | 304 | struct mtd_part *slave, *next; |
| 306 | struct mtd_part *slave; | ||
| 307 | 305 | ||
| 308 | for (node = mtd_partitions.next; | 306 | list_for_each_entry_safe(slave, next, &mtd_partitions, list) |
| 309 | node != &mtd_partitions; | ||
| 310 | node = node->next) { | ||
| 311 | slave = list_entry(node, struct mtd_part, list); | ||
| 312 | if (slave->master == master) { | 307 | if (slave->master == master) { |
| 313 | struct list_head *prev = node->prev; | 308 | list_del(&slave->list); |
| 314 | __list_del(prev, node->next); | 309 | if (slave->registered) |
| 315 | if(slave->registered) | ||
| 316 | del_mtd_device(&slave->mtd); | 310 | del_mtd_device(&slave->mtd); |
| 317 | kfree(slave); | 311 | kfree(slave); |
| 318 | node = prev; | ||
| 319 | } | 312 | } |
| 320 | } | ||
| 321 | 313 | ||
| 322 | return 0; | 314 | return 0; |
| 323 | } | 315 | } |
| 316 | EXPORT_SYMBOL(del_mtd_partitions); | ||
| 324 | 317 | ||
| 325 | /* | 318 | static struct mtd_part *add_one_partition(struct mtd_info *master, |
| 326 | * This function, given a master MTD object and a partition table, creates | 319 | const struct mtd_partition *part, int partno, |
| 327 | * and registers slave MTD objects which are bound to the master according to | 320 | u_int32_t cur_offset) |
| 328 | * the partition definitions. | ||
| 329 | * (Q: should we register the master MTD object as well?) | ||
| 330 | */ | ||
| 331 | |||
| 332 | int add_mtd_partitions(struct mtd_info *master, | ||
| 333 | const struct mtd_partition *parts, | ||
| 334 | int nbparts) | ||
| 335 | { | 321 | { |
| 336 | struct mtd_part *slave; | 322 | struct mtd_part *slave; |
| 337 | u_int32_t cur_offset = 0; | ||
| 338 | int i; | ||
| 339 | |||
| 340 | printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); | ||
| 341 | |||
| 342 | for (i = 0; i < nbparts; i++) { | ||
| 343 | 323 | ||
| 344 | /* allocate the partition structure */ | 324 | /* allocate the partition structure */ |
| 345 | slave = kzalloc (sizeof(*slave), GFP_KERNEL); | 325 | slave = kzalloc(sizeof(*slave), GFP_KERNEL); |
| 346 | if (!slave) { | 326 | if (!slave) { |
| 347 | printk ("memory allocation error while creating partitions for \"%s\"\n", | 327 | printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n", |
| 348 | master->name); | 328 | master->name); |
| 349 | del_mtd_partitions(master); | 329 | del_mtd_partitions(master); |
| 350 | return -ENOMEM; | 330 | return NULL; |
| 351 | } | 331 | } |
| 352 | list_add(&slave->list, &mtd_partitions); | 332 | list_add(&slave->list, &mtd_partitions); |
| 353 | 333 | ||
| 354 | /* set up the MTD object for this partition */ | 334 | /* set up the MTD object for this partition */ |
| 355 | slave->mtd.type = master->type; | 335 | slave->mtd.type = master->type; |
| 356 | slave->mtd.flags = master->flags & ~parts[i].mask_flags; | 336 | slave->mtd.flags = master->flags & ~part->mask_flags; |
| 357 | slave->mtd.size = parts[i].size; | 337 | slave->mtd.size = part->size; |
| 358 | slave->mtd.writesize = master->writesize; | 338 | slave->mtd.writesize = master->writesize; |
| 359 | slave->mtd.oobsize = master->oobsize; | 339 | slave->mtd.oobsize = master->oobsize; |
| 360 | slave->mtd.oobavail = master->oobavail; | 340 | slave->mtd.oobavail = master->oobavail; |
| 361 | slave->mtd.subpage_sft = master->subpage_sft; | 341 | slave->mtd.subpage_sft = master->subpage_sft; |
| 362 | 342 | ||
| 363 | slave->mtd.name = parts[i].name; | 343 | slave->mtd.name = part->name; |
| 364 | slave->mtd.owner = master->owner; | 344 | slave->mtd.owner = master->owner; |
| 365 | 345 | ||
| 366 | slave->mtd.read = part_read; | 346 | slave->mtd.read = part_read; |
| 367 | slave->mtd.write = part_write; | 347 | slave->mtd.write = part_write; |
| 368 | 348 | ||
| 369 | if (master->panic_write) | 349 | if (master->panic_write) |
| 370 | slave->mtd.panic_write = part_panic_write; | 350 | slave->mtd.panic_write = part_panic_write; |
| 371 | 351 | ||
| 372 | if(master->point && master->unpoint){ | 352 | if (master->point && master->unpoint) { |
| 373 | slave->mtd.point = part_point; | 353 | slave->mtd.point = part_point; |
| 374 | slave->mtd.unpoint = part_unpoint; | 354 | slave->mtd.unpoint = part_unpoint; |
| 375 | } | 355 | } |
| 376 | 356 | ||
| 377 | if (master->read_oob) | 357 | if (master->read_oob) |
| 378 | slave->mtd.read_oob = part_read_oob; | 358 | slave->mtd.read_oob = part_read_oob; |
| 379 | if (master->write_oob) | 359 | if (master->write_oob) |
| 380 | slave->mtd.write_oob = part_write_oob; | 360 | slave->mtd.write_oob = part_write_oob; |
| 381 | if(master->read_user_prot_reg) | 361 | if (master->read_user_prot_reg) |
| 382 | slave->mtd.read_user_prot_reg = part_read_user_prot_reg; | 362 | slave->mtd.read_user_prot_reg = part_read_user_prot_reg; |
| 383 | if(master->read_fact_prot_reg) | 363 | if (master->read_fact_prot_reg) |
| 384 | slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg; | 364 | slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg; |
| 385 | if(master->write_user_prot_reg) | 365 | if (master->write_user_prot_reg) |
| 386 | slave->mtd.write_user_prot_reg = part_write_user_prot_reg; | 366 | slave->mtd.write_user_prot_reg = part_write_user_prot_reg; |
| 387 | if(master->lock_user_prot_reg) | 367 | if (master->lock_user_prot_reg) |
| 388 | slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg; | 368 | slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg; |
| 389 | if(master->get_user_prot_info) | 369 | if (master->get_user_prot_info) |
| 390 | slave->mtd.get_user_prot_info = part_get_user_prot_info; | 370 | slave->mtd.get_user_prot_info = part_get_user_prot_info; |
| 391 | if(master->get_fact_prot_info) | 371 | if (master->get_fact_prot_info) |
| 392 | slave->mtd.get_fact_prot_info = part_get_fact_prot_info; | 372 | slave->mtd.get_fact_prot_info = part_get_fact_prot_info; |
| 393 | if (master->sync) | 373 | if (master->sync) |
| 394 | slave->mtd.sync = part_sync; | 374 | slave->mtd.sync = part_sync; |
| 395 | if (!i && master->suspend && master->resume) { | 375 | if (!partno && master->suspend && master->resume) { |
| 396 | slave->mtd.suspend = part_suspend; | 376 | slave->mtd.suspend = part_suspend; |
| 397 | slave->mtd.resume = part_resume; | 377 | slave->mtd.resume = part_resume; |
| 378 | } | ||
| 379 | if (master->writev) | ||
| 380 | slave->mtd.writev = part_writev; | ||
| 381 | if (master->lock) | ||
| 382 | slave->mtd.lock = part_lock; | ||
| 383 | if (master->unlock) | ||
| 384 | slave->mtd.unlock = part_unlock; | ||
| 385 | if (master->block_isbad) | ||
| 386 | slave->mtd.block_isbad = part_block_isbad; | ||
| 387 | if (master->block_markbad) | ||
| 388 | slave->mtd.block_markbad = part_block_markbad; | ||
| 389 | slave->mtd.erase = part_erase; | ||
| 390 | slave->master = master; | ||
| 391 | slave->offset = part->offset; | ||
| 392 | slave->index = partno; | ||
| 393 | |||
| 394 | if (slave->offset == MTDPART_OFS_APPEND) | ||
| 395 | slave->offset = cur_offset; | ||
| 396 | if (slave->offset == MTDPART_OFS_NXTBLK) { | ||
| 397 | slave->offset = cur_offset; | ||
| 398 | if ((cur_offset % master->erasesize) != 0) { | ||
| 399 | /* Round up to next erasesize */ | ||
| 400 | slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize; | ||
| 401 | printk(KERN_NOTICE "Moving partition %d: " | ||
| 402 | "0x%08x -> 0x%08x\n", partno, | ||
| 403 | cur_offset, slave->offset); | ||
| 398 | } | 404 | } |
| 399 | if (master->writev) | 405 | } |
| 400 | slave->mtd.writev = part_writev; | 406 | if (slave->mtd.size == MTDPART_SIZ_FULL) |
| 401 | if (master->lock) | 407 | slave->mtd.size = master->size - slave->offset; |
| 402 | slave->mtd.lock = part_lock; | 408 | |
| 403 | if (master->unlock) | 409 | printk(KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, |
| 404 | slave->mtd.unlock = part_unlock; | 410 | slave->offset + slave->mtd.size, slave->mtd.name); |
| 405 | if (master->block_isbad) | 411 | |
| 406 | slave->mtd.block_isbad = part_block_isbad; | 412 | /* let's do some sanity checks */ |
| 407 | if (master->block_markbad) | 413 | if (slave->offset >= master->size) { |
| 408 | slave->mtd.block_markbad = part_block_markbad; | 414 | /* let's register it anyway to preserve ordering */ |
| 409 | slave->mtd.erase = part_erase; | 415 | slave->offset = 0; |
| 410 | slave->master = master; | 416 | slave->mtd.size = 0; |
| 411 | slave->offset = parts[i].offset; | 417 | printk(KERN_ERR"mtd: partition \"%s\" is out of reach -- disabled\n", |
| 412 | slave->index = i; | 418 | part->name); |
| 413 | 419 | goto out_register; | |
| 414 | if (slave->offset == MTDPART_OFS_APPEND) | 420 | } |
| 415 | slave->offset = cur_offset; | 421 | if (slave->offset + slave->mtd.size > master->size) { |
| 416 | if (slave->offset == MTDPART_OFS_NXTBLK) { | 422 | slave->mtd.size = master->size - slave->offset; |
| 417 | slave->offset = cur_offset; | 423 | printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n", |
| 418 | if ((cur_offset % master->erasesize) != 0) { | 424 | part->name, master->name, slave->mtd.size); |
| 419 | /* Round up to next erasesize */ | 425 | } |
| 420 | slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize; | 426 | if (master->numeraseregions > 1) { |
| 421 | printk(KERN_NOTICE "Moving partition %d: " | 427 | /* Deal with variable erase size stuff */ |
| 422 | "0x%08x -> 0x%08x\n", i, | 428 | int i, max = master->numeraseregions; |
| 423 | cur_offset, slave->offset); | 429 | u32 end = slave->offset + slave->mtd.size; |
| 430 | struct mtd_erase_region_info *regions = master->eraseregions; | ||
| 431 | |||
| 432 | /* Find the first erase regions which is part of this | ||
| 433 | * partition. */ | ||
| 434 | for (i = 0; i < max && regions[i].offset <= slave->offset; i++) | ||
| 435 | ; | ||
| 436 | /* The loop searched for the region _behind_ the first one */ | ||
| 437 | i--; | ||
| 438 | |||
| 439 | /* Pick biggest erasesize */ | ||
| 440 | for (; i < max && regions[i].offset < end; i++) { | ||
| 441 | if (slave->mtd.erasesize < regions[i].erasesize) { | ||
| 442 | slave->mtd.erasesize = regions[i].erasesize; | ||
| 424 | } | 443 | } |
| 425 | } | 444 | } |
| 426 | if (slave->mtd.size == MTDPART_SIZ_FULL) | 445 | BUG_ON(slave->mtd.erasesize == 0); |
| 427 | slave->mtd.size = master->size - slave->offset; | 446 | } else { |
| 428 | cur_offset = slave->offset + slave->mtd.size; | 447 | /* Single erase size */ |
| 448 | slave->mtd.erasesize = master->erasesize; | ||
| 449 | } | ||
| 429 | 450 | ||
| 430 | printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, | 451 | if ((slave->mtd.flags & MTD_WRITEABLE) && |
| 431 | slave->offset + slave->mtd.size, slave->mtd.name); | 452 | (slave->offset % slave->mtd.erasesize)) { |
| 453 | /* Doesn't start on a boundary of major erase size */ | ||
| 454 | /* FIXME: Let it be writable if it is on a boundary of | ||
| 455 | * _minor_ erase size though */ | ||
| 456 | slave->mtd.flags &= ~MTD_WRITEABLE; | ||
| 457 | printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n", | ||
| 458 | part->name); | ||
| 459 | } | ||
| 460 | if ((slave->mtd.flags & MTD_WRITEABLE) && | ||
| 461 | (slave->mtd.size % slave->mtd.erasesize)) { | ||
| 462 | slave->mtd.flags &= ~MTD_WRITEABLE; | ||
| 463 | printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", | ||
| 464 | part->name); | ||
| 465 | } | ||
| 432 | 466 | ||
| 433 | /* let's do some sanity checks */ | 467 | slave->mtd.ecclayout = master->ecclayout; |
| 434 | if (slave->offset >= master->size) { | 468 | if (master->block_isbad) { |
| 435 | /* let's register it anyway to preserve ordering */ | 469 | uint32_t offs = 0; |
| 436 | slave->offset = 0; | ||
| 437 | slave->mtd.size = 0; | ||
| 438 | printk ("mtd: partition \"%s\" is out of reach -- disabled\n", | ||
| 439 | parts[i].name); | ||
| 440 | } | ||
| 441 | if (slave->offset + slave->mtd.size > master->size) { | ||
| 442 | slave->mtd.size = master->size - slave->offset; | ||
| 443 | printk ("mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n", | ||
| 444 | parts[i].name, master->name, slave->mtd.size); | ||
| 445 | } | ||
| 446 | if (master->numeraseregions>1) { | ||
| 447 | /* Deal with variable erase size stuff */ | ||
| 448 | int i; | ||
| 449 | struct mtd_erase_region_info *regions = master->eraseregions; | ||
| 450 | |||
| 451 | /* Find the first erase regions which is part of this partition. */ | ||
| 452 | for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++) | ||
| 453 | ; | ||
| 454 | |||
| 455 | for (i--; i < master->numeraseregions && slave->offset + slave->mtd.size > regions[i].offset; i++) { | ||
| 456 | if (slave->mtd.erasesize < regions[i].erasesize) { | ||
| 457 | slave->mtd.erasesize = regions[i].erasesize; | ||
| 458 | } | ||
| 459 | } | ||
| 460 | } else { | ||
| 461 | /* Single erase size */ | ||
| 462 | slave->mtd.erasesize = master->erasesize; | ||
| 463 | } | ||
| 464 | 470 | ||
| 465 | if ((slave->mtd.flags & MTD_WRITEABLE) && | 471 | while (offs < slave->mtd.size) { |
| 466 | (slave->offset % slave->mtd.erasesize)) { | 472 | if (master->block_isbad(master, |
| 467 | /* Doesn't start on a boundary of major erase size */ | 473 | offs + slave->offset)) |
| 468 | /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */ | 474 | slave->mtd.ecc_stats.badblocks++; |
| 469 | slave->mtd.flags &= ~MTD_WRITEABLE; | 475 | offs += slave->mtd.erasesize; |
| 470 | printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n", | ||
| 471 | parts[i].name); | ||
| 472 | } | ||
| 473 | if ((slave->mtd.flags & MTD_WRITEABLE) && | ||
| 474 | (slave->mtd.size % slave->mtd.erasesize)) { | ||
| 475 | slave->mtd.flags &= ~MTD_WRITEABLE; | ||
| 476 | printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", | ||
| 477 | parts[i].name); | ||
| 478 | } | 476 | } |
| 477 | } | ||
| 479 | 478 | ||
| 480 | slave->mtd.ecclayout = master->ecclayout; | 479 | out_register: |
| 481 | if (master->block_isbad) { | 480 | if (part->mtdp) { |
| 482 | uint32_t offs = 0; | 481 | /* store the object pointer (caller may or may not register it*/ |
| 482 | *part->mtdp = &slave->mtd; | ||
| 483 | slave->registered = 0; | ||
| 484 | } else { | ||
| 485 | /* register our partition */ | ||
| 486 | add_mtd_device(&slave->mtd); | ||
| 487 | slave->registered = 1; | ||
| 488 | } | ||
| 489 | return slave; | ||
| 490 | } | ||
| 483 | 491 | ||
| 484 | while(offs < slave->mtd.size) { | 492 | /* |
| 485 | if (master->block_isbad(master, | 493 | * This function, given a master MTD object and a partition table, creates |
| 486 | offs + slave->offset)) | 494 | * and registers slave MTD objects which are bound to the master according to |
| 487 | slave->mtd.ecc_stats.badblocks++; | 495 | * the partition definitions. |
| 488 | offs += slave->mtd.erasesize; | 496 | * (Q: should we register the master MTD object as well?) |
| 489 | } | 497 | */ |
| 490 | } | ||
| 491 | 498 | ||
| 492 | if(parts[i].mtdp) | 499 | int add_mtd_partitions(struct mtd_info *master, |
| 493 | { /* store the object pointer (caller may or may not register it */ | 500 | const struct mtd_partition *parts, |
| 494 | *parts[i].mtdp = &slave->mtd; | 501 | int nbparts) |
| 495 | slave->registered = 0; | 502 | { |
| 496 | } | 503 | struct mtd_part *slave; |
| 497 | else | 504 | u_int32_t cur_offset = 0; |
| 498 | { | 505 | int i; |
| 499 | /* register our partition */ | 506 | |
| 500 | add_mtd_device(&slave->mtd); | 507 | printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); |
| 501 | slave->registered = 1; | 508 | |
| 502 | } | 509 | for (i = 0; i < nbparts; i++) { |
| 510 | slave = add_one_partition(master, parts + i, i, cur_offset); | ||
| 511 | if (!slave) | ||
| 512 | return -ENOMEM; | ||
| 513 | cur_offset = slave->offset + slave->mtd.size; | ||
| 503 | } | 514 | } |
| 504 | 515 | ||
| 505 | return 0; | 516 | return 0; |
| 506 | } | 517 | } |
| 507 | |||
| 508 | EXPORT_SYMBOL(add_mtd_partitions); | 518 | EXPORT_SYMBOL(add_mtd_partitions); |
| 509 | EXPORT_SYMBOL(del_mtd_partitions); | ||
| 510 | 519 | ||
| 511 | static DEFINE_SPINLOCK(part_parser_lock); | 520 | static DEFINE_SPINLOCK(part_parser_lock); |
| 512 | static LIST_HEAD(part_parsers); | 521 | static LIST_HEAD(part_parsers); |
| 513 | 522 | ||
| 514 | static struct mtd_part_parser *get_partition_parser(const char *name) | 523 | static struct mtd_part_parser *get_partition_parser(const char *name) |
| 515 | { | 524 | { |
| 516 | struct list_head *this; | 525 | struct mtd_part_parser *p, *ret = NULL; |
| 517 | void *ret = NULL; | ||
| 518 | spin_lock(&part_parser_lock); | ||
| 519 | 526 | ||
| 520 | list_for_each(this, &part_parsers) { | 527 | spin_lock(&part_parser_lock); |
| 521 | struct mtd_part_parser *p = list_entry(this, struct mtd_part_parser, list); | ||
| 522 | 528 | ||
| 529 | list_for_each_entry(p, &part_parsers, list) | ||
| 523 | if (!strcmp(p->name, name) && try_module_get(p->owner)) { | 530 | if (!strcmp(p->name, name) && try_module_get(p->owner)) { |
| 524 | ret = p; | 531 | ret = p; |
| 525 | break; | 532 | break; |
| 526 | } | 533 | } |
| 527 | } | 534 | |
| 528 | spin_unlock(&part_parser_lock); | 535 | spin_unlock(&part_parser_lock); |
| 529 | 536 | ||
| 530 | return ret; | 537 | return ret; |
| @@ -538,6 +545,7 @@ int register_mtd_parser(struct mtd_part_parser *p) | |||
| 538 | 545 | ||
| 539 | return 0; | 546 | return 0; |
| 540 | } | 547 | } |
| 548 | EXPORT_SYMBOL_GPL(register_mtd_parser); | ||
| 541 | 549 | ||
| 542 | int deregister_mtd_parser(struct mtd_part_parser *p) | 550 | int deregister_mtd_parser(struct mtd_part_parser *p) |
| 543 | { | 551 | { |
| @@ -546,6 +554,7 @@ int deregister_mtd_parser(struct mtd_part_parser *p) | |||
| 546 | spin_unlock(&part_parser_lock); | 554 | spin_unlock(&part_parser_lock); |
| 547 | return 0; | 555 | return 0; |
| 548 | } | 556 | } |
| 557 | EXPORT_SYMBOL_GPL(deregister_mtd_parser); | ||
| 549 | 558 | ||
| 550 | int parse_mtd_partitions(struct mtd_info *master, const char **types, | 559 | int parse_mtd_partitions(struct mtd_info *master, const char **types, |
| 551 | struct mtd_partition **pparts, unsigned long origin) | 560 | struct mtd_partition **pparts, unsigned long origin) |
| @@ -573,7 +582,4 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types, | |||
| 573 | } | 582 | } |
| 574 | return ret; | 583 | return ret; |
| 575 | } | 584 | } |
| 576 | |||
| 577 | EXPORT_SYMBOL_GPL(parse_mtd_partitions); | 585 | EXPORT_SYMBOL_GPL(parse_mtd_partitions); |
| 578 | EXPORT_SYMBOL_GPL(register_mtd_parser); | ||
| 579 | EXPORT_SYMBOL_GPL(deregister_mtd_parser); | ||
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 5076faf9ca66..71406e517857 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | # drivers/mtd/nand/Kconfig | 1 | # drivers/mtd/nand/Kconfig |
| 2 | # $Id: Kconfig,v 1.35 2005/11/07 11:14:30 gleixner Exp $ | ||
| 3 | 2 | ||
| 4 | menuconfig MTD_NAND | 3 | menuconfig MTD_NAND |
| 5 | tristate "NAND Device Support" | 4 | tristate "NAND Device Support" |
| @@ -272,22 +271,23 @@ config MTD_NAND_CS553X | |||
| 272 | 271 | ||
| 273 | If you say "m", the module will be called "cs553x_nand.ko". | 272 | If you say "m", the module will be called "cs553x_nand.ko". |
| 274 | 273 | ||
| 275 | config MTD_NAND_AT91 | 274 | config MTD_NAND_ATMEL |
| 276 | bool "Support for NAND Flash / SmartMedia on AT91" | 275 | tristate "Support for NAND Flash / SmartMedia on AT91 and AVR32" |
| 277 | depends on ARCH_AT91 | 276 | depends on ARCH_AT91 || AVR32 |
| 278 | help | 277 | help |
| 279 | Enables support for NAND Flash / Smart Media Card interface | 278 | Enables support for NAND Flash / Smart Media Card interface |
| 280 | on Atmel AT91 processors. | 279 | on Atmel AT91 and AVR32 processors. |
| 281 | choice | 280 | choice |
| 282 | prompt "ECC management for NAND Flash / SmartMedia on AT91" | 281 | prompt "ECC management for NAND Flash / SmartMedia on AT91 / AVR32" |
| 283 | depends on MTD_NAND_AT91 | 282 | depends on MTD_NAND_ATMEL |
| 284 | 283 | ||
| 285 | config MTD_NAND_AT91_ECC_HW | 284 | config MTD_NAND_ATMEL_ECC_HW |
| 286 | bool "Hardware ECC" | 285 | bool "Hardware ECC" |
| 287 | depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 | 286 | depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 || AVR32 |
| 288 | help | 287 | help |
| 289 | Uses hardware ECC provided by the at91sam9260/at91sam9263 chip | 288 | Use hardware ECC instead of software ECC when the chip |
| 290 | instead of software ECC. | 289 | supports it. |
| 290 | |||
| 291 | The hardware ECC controller is capable of single bit error | 291 | The hardware ECC controller is capable of single bit error |
| 292 | correction and 2-bit random detection per page. | 292 | correction and 2-bit random detection per page. |
| 293 | 293 | ||
| @@ -297,16 +297,16 @@ config MTD_NAND_AT91_ECC_HW | |||
| 297 | 297 | ||
| 298 | If unsure, say Y | 298 | If unsure, say Y |
| 299 | 299 | ||
| 300 | config MTD_NAND_AT91_ECC_SOFT | 300 | config MTD_NAND_ATMEL_ECC_SOFT |
| 301 | bool "Software ECC" | 301 | bool "Software ECC" |
| 302 | help | 302 | help |
| 303 | Uses software ECC. | 303 | Use software ECC. |
| 304 | 304 | ||
| 305 | NB : hardware and software ECC schemes are incompatible. | 305 | NB : hardware and software ECC schemes are incompatible. |
| 306 | If you switch from one to another, you'll have to erase your | 306 | If you switch from one to another, you'll have to erase your |
| 307 | mtd partition. | 307 | mtd partition. |
| 308 | 308 | ||
| 309 | config MTD_NAND_AT91_ECC_NONE | 309 | config MTD_NAND_ATMEL_ECC_NONE |
| 310 | bool "No ECC (testing only, DANGEROUS)" | 310 | bool "No ECC (testing only, DANGEROUS)" |
| 311 | depends on DEBUG_KERNEL | 311 | depends on DEBUG_KERNEL |
| 312 | help | 312 | help |
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index a6e74a46992a..d772581de573 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | # | 1 | # |
| 2 | # linux/drivers/nand/Makefile | 2 | # linux/drivers/nand/Makefile |
| 3 | # | 3 | # |
| 4 | # $Id: Makefile.common,v 1.15 2004/11/26 12:28:22 dedekind Exp $ | ||
| 5 | 4 | ||
| 6 | obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o | 5 | obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o |
| 7 | obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o | 6 | obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o |
| @@ -24,7 +23,7 @@ obj-$(CONFIG_MTD_NAND_TS7250) += ts7250.o | |||
| 24 | obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o | 23 | obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o |
| 25 | obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o | 24 | obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o |
| 26 | obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o | 25 | obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o |
| 27 | obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o | 26 | obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o |
| 28 | obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o | 27 | obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o |
| 29 | obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o | 28 | obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o |
| 30 | obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o | 29 | obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o |
diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/atmel_nand.c index 0adb287027a2..99aec46e2145 100644 --- a/drivers/mtd/nand/at91_nand.c +++ b/drivers/mtd/nand/atmel_nand.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * drivers/mtd/nand/at91_nand.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2003 Rick Bronson | 2 | * Copyright (C) 2003 Rick Bronson |
| 5 | * | 3 | * |
| 6 | * Derived from drivers/mtd/nand/autcpu12.c | 4 | * Derived from drivers/mtd/nand/autcpu12.c |
| @@ -31,20 +29,19 @@ | |||
| 31 | #include <linux/mtd/nand.h> | 29 | #include <linux/mtd/nand.h> |
| 32 | #include <linux/mtd/partitions.h> | 30 | #include <linux/mtd/partitions.h> |
| 33 | 31 | ||
| 34 | #include <asm/io.h> | 32 | #include <linux/gpio.h> |
| 35 | #include <asm/sizes.h> | 33 | #include <linux/io.h> |
| 36 | 34 | ||
| 37 | #include <asm/hardware.h> | ||
| 38 | #include <asm/arch/board.h> | 35 | #include <asm/arch/board.h> |
| 39 | #include <asm/arch/gpio.h> | 36 | #include <asm/arch/cpu.h> |
| 40 | 37 | ||
| 41 | #ifdef CONFIG_MTD_NAND_AT91_ECC_HW | 38 | #ifdef CONFIG_MTD_NAND_ATMEL_ECC_HW |
| 42 | #define hard_ecc 1 | 39 | #define hard_ecc 1 |
| 43 | #else | 40 | #else |
| 44 | #define hard_ecc 0 | 41 | #define hard_ecc 0 |
| 45 | #endif | 42 | #endif |
| 46 | 43 | ||
| 47 | #ifdef CONFIG_MTD_NAND_AT91_ECC_NONE | 44 | #ifdef CONFIG_MTD_NAND_ATMEL_ECC_NONE |
| 48 | #define no_ecc 1 | 45 | #define no_ecc 1 |
| 49 | #else | 46 | #else |
| 50 | #define no_ecc 0 | 47 | #define no_ecc 0 |
| @@ -52,18 +49,18 @@ | |||
| 52 | 49 | ||
| 53 | /* Register access macros */ | 50 | /* Register access macros */ |
| 54 | #define ecc_readl(add, reg) \ | 51 | #define ecc_readl(add, reg) \ |
| 55 | __raw_readl(add + AT91_ECC_##reg) | 52 | __raw_readl(add + ATMEL_ECC_##reg) |
| 56 | #define ecc_writel(add, reg, value) \ | 53 | #define ecc_writel(add, reg, value) \ |
| 57 | __raw_writel((value), add + AT91_ECC_##reg) | 54 | __raw_writel((value), add + ATMEL_ECC_##reg) |
| 58 | 55 | ||
| 59 | #include <asm/arch/at91_ecc.h> /* AT91SAM9260/3 ECC registers */ | 56 | #include "atmel_nand_ecc.h" /* Hardware ECC registers */ |
| 60 | 57 | ||
| 61 | /* oob layout for large page size | 58 | /* oob layout for large page size |
| 62 | * bad block info is on bytes 0 and 1 | 59 | * bad block info is on bytes 0 and 1 |
| 63 | * the bytes have to be consecutives to avoid | 60 | * the bytes have to be consecutives to avoid |
| 64 | * several NAND_CMD_RNDOUT during read | 61 | * several NAND_CMD_RNDOUT during read |
| 65 | */ | 62 | */ |
| 66 | static struct nand_ecclayout at91_oobinfo_large = { | 63 | static struct nand_ecclayout atmel_oobinfo_large = { |
| 67 | .eccbytes = 4, | 64 | .eccbytes = 4, |
| 68 | .eccpos = {60, 61, 62, 63}, | 65 | .eccpos = {60, 61, 62, 63}, |
| 69 | .oobfree = { | 66 | .oobfree = { |
| @@ -76,7 +73,7 @@ static struct nand_ecclayout at91_oobinfo_large = { | |||
| 76 | * the bytes have to be consecutives to avoid | 73 | * the bytes have to be consecutives to avoid |
| 77 | * several NAND_CMD_RNDOUT during read | 74 | * several NAND_CMD_RNDOUT during read |
| 78 | */ | 75 | */ |
| 79 | static struct nand_ecclayout at91_oobinfo_small = { | 76 | static struct nand_ecclayout atmel_oobinfo_small = { |
| 80 | .eccbytes = 4, | 77 | .eccbytes = 4, |
| 81 | .eccpos = {0, 1, 2, 3}, | 78 | .eccpos = {0, 1, 2, 3}, |
| 82 | .oobfree = { | 79 | .oobfree = { |
| @@ -84,11 +81,11 @@ static struct nand_ecclayout at91_oobinfo_small = { | |||
| 84 | }, | 81 | }, |
| 85 | }; | 82 | }; |
| 86 | 83 | ||
| 87 | struct at91_nand_host { | 84 | struct atmel_nand_host { |
| 88 | struct nand_chip nand_chip; | 85 | struct nand_chip nand_chip; |
| 89 | struct mtd_info mtd; | 86 | struct mtd_info mtd; |
| 90 | void __iomem *io_base; | 87 | void __iomem *io_base; |
| 91 | struct at91_nand_data *board; | 88 | struct atmel_nand_data *board; |
| 92 | struct device *dev; | 89 | struct device *dev; |
| 93 | void __iomem *ecc; | 90 | void __iomem *ecc; |
| 94 | }; | 91 | }; |
| @@ -96,34 +93,34 @@ struct at91_nand_host { | |||
| 96 | /* | 93 | /* |
| 97 | * Enable NAND. | 94 | * Enable NAND. |
| 98 | */ | 95 | */ |
| 99 | static void at91_nand_enable(struct at91_nand_host *host) | 96 | static void atmel_nand_enable(struct atmel_nand_host *host) |
| 100 | { | 97 | { |
| 101 | if (host->board->enable_pin) | 98 | if (host->board->enable_pin) |
| 102 | at91_set_gpio_value(host->board->enable_pin, 0); | 99 | gpio_set_value(host->board->enable_pin, 0); |
| 103 | } | 100 | } |
| 104 | 101 | ||
| 105 | /* | 102 | /* |
| 106 | * Disable NAND. | 103 | * Disable NAND. |
| 107 | */ | 104 | */ |
| 108 | static void at91_nand_disable(struct at91_nand_host *host) | 105 | static void atmel_nand_disable(struct atmel_nand_host *host) |
| 109 | { | 106 | { |
| 110 | if (host->board->enable_pin) | 107 | if (host->board->enable_pin) |
| 111 | at91_set_gpio_value(host->board->enable_pin, 1); | 108 | gpio_set_value(host->board->enable_pin, 1); |
| 112 | } | 109 | } |
| 113 | 110 | ||
| 114 | /* | 111 | /* |
| 115 | * Hardware specific access to control-lines | 112 | * Hardware specific access to control-lines |
| 116 | */ | 113 | */ |
| 117 | static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) | 114 | static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) |
| 118 | { | 115 | { |
| 119 | struct nand_chip *nand_chip = mtd->priv; | 116 | struct nand_chip *nand_chip = mtd->priv; |
| 120 | struct at91_nand_host *host = nand_chip->priv; | 117 | struct atmel_nand_host *host = nand_chip->priv; |
| 121 | 118 | ||
| 122 | if (ctrl & NAND_CTRL_CHANGE) { | 119 | if (ctrl & NAND_CTRL_CHANGE) { |
| 123 | if (ctrl & NAND_NCE) | 120 | if (ctrl & NAND_NCE) |
| 124 | at91_nand_enable(host); | 121 | atmel_nand_enable(host); |
| 125 | else | 122 | else |
| 126 | at91_nand_disable(host); | 123 | atmel_nand_disable(host); |
| 127 | } | 124 | } |
| 128 | if (cmd == NAND_CMD_NONE) | 125 | if (cmd == NAND_CMD_NONE) |
| 129 | return; | 126 | return; |
| @@ -137,18 +134,49 @@ static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) | |||
| 137 | /* | 134 | /* |
| 138 | * Read the Device Ready pin. | 135 | * Read the Device Ready pin. |
| 139 | */ | 136 | */ |
| 140 | static int at91_nand_device_ready(struct mtd_info *mtd) | 137 | static int atmel_nand_device_ready(struct mtd_info *mtd) |
| 141 | { | 138 | { |
| 142 | struct nand_chip *nand_chip = mtd->priv; | 139 | struct nand_chip *nand_chip = mtd->priv; |
| 143 | struct at91_nand_host *host = nand_chip->priv; | 140 | struct atmel_nand_host *host = nand_chip->priv; |
| 144 | 141 | ||
| 145 | return at91_get_gpio_value(host->board->rdy_pin); | 142 | return gpio_get_value(host->board->rdy_pin); |
| 143 | } | ||
| 144 | |||
| 145 | /* | ||
| 146 | * Minimal-overhead PIO for data access. | ||
| 147 | */ | ||
| 148 | static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) | ||
| 149 | { | ||
| 150 | struct nand_chip *nand_chip = mtd->priv; | ||
| 151 | |||
| 152 | __raw_readsb(nand_chip->IO_ADDR_R, buf, len); | ||
| 153 | } | ||
| 154 | |||
| 155 | static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) | ||
| 156 | { | ||
| 157 | struct nand_chip *nand_chip = mtd->priv; | ||
| 158 | |||
| 159 | __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2); | ||
| 160 | } | ||
| 161 | |||
| 162 | static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) | ||
| 163 | { | ||
| 164 | struct nand_chip *nand_chip = mtd->priv; | ||
| 165 | |||
| 166 | __raw_writesb(nand_chip->IO_ADDR_W, buf, len); | ||
| 167 | } | ||
| 168 | |||
| 169 | static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) | ||
| 170 | { | ||
| 171 | struct nand_chip *nand_chip = mtd->priv; | ||
| 172 | |||
| 173 | __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2); | ||
| 146 | } | 174 | } |
| 147 | 175 | ||
| 148 | /* | 176 | /* |
| 149 | * write oob for small pages | 177 | * write oob for small pages |
| 150 | */ | 178 | */ |
| 151 | static int at91_nand_write_oob_512(struct mtd_info *mtd, | 179 | static int atmel_nand_write_oob_512(struct mtd_info *mtd, |
| 152 | struct nand_chip *chip, int page) | 180 | struct nand_chip *chip, int page) |
| 153 | { | 181 | { |
| 154 | int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; | 182 | int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; |
| @@ -176,7 +204,7 @@ static int at91_nand_write_oob_512(struct mtd_info *mtd, | |||
| 176 | /* | 204 | /* |
| 177 | * read oob for small pages | 205 | * read oob for small pages |
| 178 | */ | 206 | */ |
| 179 | static int at91_nand_read_oob_512(struct mtd_info *mtd, | 207 | static int atmel_nand_read_oob_512(struct mtd_info *mtd, |
| 180 | struct nand_chip *chip, int page, int sndcmd) | 208 | struct nand_chip *chip, int page, int sndcmd) |
| 181 | { | 209 | { |
| 182 | if (sndcmd) { | 210 | if (sndcmd) { |
| @@ -196,11 +224,11 @@ static int at91_nand_read_oob_512(struct mtd_info *mtd, | |||
| 196 | * dat: raw data (unused) | 224 | * dat: raw data (unused) |
| 197 | * ecc_code: buffer for ECC | 225 | * ecc_code: buffer for ECC |
| 198 | */ | 226 | */ |
| 199 | static int at91_nand_calculate(struct mtd_info *mtd, | 227 | static int atmel_nand_calculate(struct mtd_info *mtd, |
| 200 | const u_char *dat, unsigned char *ecc_code) | 228 | const u_char *dat, unsigned char *ecc_code) |
| 201 | { | 229 | { |
| 202 | struct nand_chip *nand_chip = mtd->priv; | 230 | struct nand_chip *nand_chip = mtd->priv; |
| 203 | struct at91_nand_host *host = nand_chip->priv; | 231 | struct atmel_nand_host *host = nand_chip->priv; |
| 204 | uint32_t *eccpos = nand_chip->ecc.layout->eccpos; | 232 | uint32_t *eccpos = nand_chip->ecc.layout->eccpos; |
| 205 | unsigned int ecc_value; | 233 | unsigned int ecc_value; |
| 206 | 234 | ||
| @@ -211,7 +239,7 @@ static int at91_nand_calculate(struct mtd_info *mtd, | |||
| 211 | ecc_code[eccpos[1]] = (ecc_value >> 8) & 0xFF; | 239 | ecc_code[eccpos[1]] = (ecc_value >> 8) & 0xFF; |
| 212 | 240 | ||
| 213 | /* get the last 2 ECC bytes */ | 241 | /* get the last 2 ECC bytes */ |
| 214 | ecc_value = ecc_readl(host->ecc, NPR) & AT91_ECC_NPARITY; | 242 | ecc_value = ecc_readl(host->ecc, NPR) & ATMEL_ECC_NPARITY; |
| 215 | 243 | ||
| 216 | ecc_code[eccpos[2]] = ecc_value & 0xFF; | 244 | ecc_code[eccpos[2]] = ecc_value & 0xFF; |
| 217 | ecc_code[eccpos[3]] = (ecc_value >> 8) & 0xFF; | 245 | ecc_code[eccpos[3]] = (ecc_value >> 8) & 0xFF; |
| @@ -226,7 +254,7 @@ static int at91_nand_calculate(struct mtd_info *mtd, | |||
| 226 | * chip: nand chip info structure | 254 | * chip: nand chip info structure |
| 227 | * buf: buffer to store read data | 255 | * buf: buffer to store read data |
| 228 | */ | 256 | */ |
| 229 | static int at91_nand_read_page(struct mtd_info *mtd, | 257 | static int atmel_nand_read_page(struct mtd_info *mtd, |
| 230 | struct nand_chip *chip, uint8_t *buf) | 258 | struct nand_chip *chip, uint8_t *buf) |
| 231 | { | 259 | { |
| 232 | int eccsize = chip->ecc.size; | 260 | int eccsize = chip->ecc.size; |
| @@ -237,6 +265,19 @@ static int at91_nand_read_page(struct mtd_info *mtd, | |||
| 237 | uint8_t *ecc_pos; | 265 | uint8_t *ecc_pos; |
| 238 | int stat; | 266 | int stat; |
| 239 | 267 | ||
| 268 | /* | ||
| 269 | * Errata: ALE is incorrectly wired up to the ECC controller | ||
| 270 | * on the AP7000, so it will include the address cycles in the | ||
| 271 | * ECC calculation. | ||
| 272 | * | ||
| 273 | * Workaround: Reset the parity registers before reading the | ||
| 274 | * actual data. | ||
| 275 | */ | ||
| 276 | if (cpu_is_at32ap7000()) { | ||
| 277 | struct atmel_nand_host *host = chip->priv; | ||
| 278 | ecc_writel(host->ecc, CR, ATMEL_ECC_RST); | ||
| 279 | } | ||
| 280 | |||
| 240 | /* read the page */ | 281 | /* read the page */ |
| 241 | chip->read_buf(mtd, p, eccsize); | 282 | chip->read_buf(mtd, p, eccsize); |
| 242 | 283 | ||
| @@ -285,11 +326,11 @@ static int at91_nand_read_page(struct mtd_info *mtd, | |||
| 285 | * | 326 | * |
| 286 | * Detect and correct a 1 bit error for a page | 327 | * Detect and correct a 1 bit error for a page |
| 287 | */ | 328 | */ |
| 288 | static int at91_nand_correct(struct mtd_info *mtd, u_char *dat, | 329 | static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, |
| 289 | u_char *read_ecc, u_char *isnull) | 330 | u_char *read_ecc, u_char *isnull) |
| 290 | { | 331 | { |
| 291 | struct nand_chip *nand_chip = mtd->priv; | 332 | struct nand_chip *nand_chip = mtd->priv; |
| 292 | struct at91_nand_host *host = nand_chip->priv; | 333 | struct atmel_nand_host *host = nand_chip->priv; |
| 293 | unsigned int ecc_status; | 334 | unsigned int ecc_status; |
| 294 | unsigned int ecc_word, ecc_bit; | 335 | unsigned int ecc_word, ecc_bit; |
| 295 | 336 | ||
| @@ -297,43 +338,43 @@ static int at91_nand_correct(struct mtd_info *mtd, u_char *dat, | |||
| 297 | ecc_status = ecc_readl(host->ecc, SR); | 338 | ecc_status = ecc_readl(host->ecc, SR); |
| 298 | 339 | ||
| 299 | /* if there's no error */ | 340 | /* if there's no error */ |
| 300 | if (likely(!(ecc_status & AT91_ECC_RECERR))) | 341 | if (likely(!(ecc_status & ATMEL_ECC_RECERR))) |
| 301 | return 0; | 342 | return 0; |
| 302 | 343 | ||
| 303 | /* get error bit offset (4 bits) */ | 344 | /* get error bit offset (4 bits) */ |
| 304 | ecc_bit = ecc_readl(host->ecc, PR) & AT91_ECC_BITADDR; | 345 | ecc_bit = ecc_readl(host->ecc, PR) & ATMEL_ECC_BITADDR; |
| 305 | /* get word address (12 bits) */ | 346 | /* get word address (12 bits) */ |
| 306 | ecc_word = ecc_readl(host->ecc, PR) & AT91_ECC_WORDADDR; | 347 | ecc_word = ecc_readl(host->ecc, PR) & ATMEL_ECC_WORDADDR; |
| 307 | ecc_word >>= 4; | 348 | ecc_word >>= 4; |
| 308 | 349 | ||
| 309 | /* if there are multiple errors */ | 350 | /* if there are multiple errors */ |
| 310 | if (ecc_status & AT91_ECC_MULERR) { | 351 | if (ecc_status & ATMEL_ECC_MULERR) { |
| 311 | /* check if it is a freshly erased block | 352 | /* check if it is a freshly erased block |
| 312 | * (filled with 0xff) */ | 353 | * (filled with 0xff) */ |
| 313 | if ((ecc_bit == AT91_ECC_BITADDR) | 354 | if ((ecc_bit == ATMEL_ECC_BITADDR) |
| 314 | && (ecc_word == (AT91_ECC_WORDADDR >> 4))) { | 355 | && (ecc_word == (ATMEL_ECC_WORDADDR >> 4))) { |
| 315 | /* the block has just been erased, return OK */ | 356 | /* the block has just been erased, return OK */ |
| 316 | return 0; | 357 | return 0; |
| 317 | } | 358 | } |
| 318 | /* it doesn't seems to be a freshly | 359 | /* it doesn't seems to be a freshly |
| 319 | * erased block. | 360 | * erased block. |
| 320 | * We can't correct so many errors */ | 361 | * We can't correct so many errors */ |
| 321 | dev_dbg(host->dev, "at91_nand : multiple errors detected." | 362 | dev_dbg(host->dev, "atmel_nand : multiple errors detected." |
| 322 | " Unable to correct.\n"); | 363 | " Unable to correct.\n"); |
| 323 | return -EIO; | 364 | return -EIO; |
| 324 | } | 365 | } |
| 325 | 366 | ||
| 326 | /* if there's a single bit error : we can correct it */ | 367 | /* if there's a single bit error : we can correct it */ |
| 327 | if (ecc_status & AT91_ECC_ECCERR) { | 368 | if (ecc_status & ATMEL_ECC_ECCERR) { |
| 328 | /* there's nothing much to do here. | 369 | /* there's nothing much to do here. |
| 329 | * the bit error is on the ECC itself. | 370 | * the bit error is on the ECC itself. |
| 330 | */ | 371 | */ |
| 331 | dev_dbg(host->dev, "at91_nand : one bit error on ECC code." | 372 | dev_dbg(host->dev, "atmel_nand : one bit error on ECC code." |
| 332 | " Nothing to correct\n"); | 373 | " Nothing to correct\n"); |
| 333 | return 0; | 374 | return 0; |
| 334 | } | 375 | } |
| 335 | 376 | ||
| 336 | dev_dbg(host->dev, "at91_nand : one bit error on data." | 377 | dev_dbg(host->dev, "atmel_nand : one bit error on data." |
| 337 | " (word offset in the page :" | 378 | " (word offset in the page :" |
| 338 | " 0x%x bit offset : 0x%x)\n", | 379 | " 0x%x bit offset : 0x%x)\n", |
| 339 | ecc_word, ecc_bit); | 380 | ecc_word, ecc_bit); |
| @@ -345,14 +386,21 @@ static int at91_nand_correct(struct mtd_info *mtd, u_char *dat, | |||
| 345 | /* 8 bits words */ | 386 | /* 8 bits words */ |
| 346 | dat[ecc_word] ^= (1 << ecc_bit); | 387 | dat[ecc_word] ^= (1 << ecc_bit); |
| 347 | } | 388 | } |
| 348 | dev_dbg(host->dev, "at91_nand : error corrected\n"); | 389 | dev_dbg(host->dev, "atmel_nand : error corrected\n"); |
| 349 | return 1; | 390 | return 1; |
| 350 | } | 391 | } |
| 351 | 392 | ||
| 352 | /* | 393 | /* |
| 353 | * Enable HW ECC : unsused | 394 | * Enable HW ECC : unused on most chips |
| 354 | */ | 395 | */ |
| 355 | static void at91_nand_hwctl(struct mtd_info *mtd, int mode) { ; } | 396 | static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) |
| 397 | { | ||
| 398 | if (cpu_is_at32ap7000()) { | ||
| 399 | struct nand_chip *nand_chip = mtd->priv; | ||
| 400 | struct atmel_nand_host *host = nand_chip->priv; | ||
| 401 | ecc_writel(host->ecc, CR, ATMEL_ECC_RST); | ||
| 402 | } | ||
| 403 | } | ||
| 356 | 404 | ||
| 357 | #ifdef CONFIG_MTD_PARTITIONS | 405 | #ifdef CONFIG_MTD_PARTITIONS |
| 358 | static const char *part_probes[] = { "cmdlinepart", NULL }; | 406 | static const char *part_probes[] = { "cmdlinepart", NULL }; |
| @@ -361,9 +409,9 @@ static const char *part_probes[] = { "cmdlinepart", NULL }; | |||
| 361 | /* | 409 | /* |
| 362 | * Probe for the NAND device. | 410 | * Probe for the NAND device. |
| 363 | */ | 411 | */ |
| 364 | static int __init at91_nand_probe(struct platform_device *pdev) | 412 | static int __init atmel_nand_probe(struct platform_device *pdev) |
| 365 | { | 413 | { |
| 366 | struct at91_nand_host *host; | 414 | struct atmel_nand_host *host; |
| 367 | struct mtd_info *mtd; | 415 | struct mtd_info *mtd; |
| 368 | struct nand_chip *nand_chip; | 416 | struct nand_chip *nand_chip; |
| 369 | struct resource *regs; | 417 | struct resource *regs; |
| @@ -375,24 +423,24 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
| 375 | int num_partitions = 0; | 423 | int num_partitions = 0; |
| 376 | #endif | 424 | #endif |
| 377 | 425 | ||
| 378 | /* Allocate memory for the device structure (and zero it) */ | ||
| 379 | host = kzalloc(sizeof(struct at91_nand_host), GFP_KERNEL); | ||
| 380 | if (!host) { | ||
| 381 | printk(KERN_ERR "at91_nand: failed to allocate device structure.\n"); | ||
| 382 | return -ENOMEM; | ||
| 383 | } | ||
| 384 | |||
| 385 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 426 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 386 | if (!mem) { | 427 | if (!mem) { |
| 387 | printk(KERN_ERR "at91_nand: can't get I/O resource mem\n"); | 428 | printk(KERN_ERR "atmel_nand: can't get I/O resource mem\n"); |
| 388 | return -ENXIO; | 429 | return -ENXIO; |
| 389 | } | 430 | } |
| 390 | 431 | ||
| 432 | /* Allocate memory for the device structure (and zero it) */ | ||
| 433 | host = kzalloc(sizeof(struct atmel_nand_host), GFP_KERNEL); | ||
| 434 | if (!host) { | ||
| 435 | printk(KERN_ERR "atmel_nand: failed to allocate device structure.\n"); | ||
| 436 | return -ENOMEM; | ||
| 437 | } | ||
| 438 | |||
| 391 | host->io_base = ioremap(mem->start, mem->end - mem->start + 1); | 439 | host->io_base = ioremap(mem->start, mem->end - mem->start + 1); |
| 392 | if (host->io_base == NULL) { | 440 | if (host->io_base == NULL) { |
| 393 | printk(KERN_ERR "at91_nand: ioremap failed\n"); | 441 | printk(KERN_ERR "atmel_nand: ioremap failed\n"); |
| 394 | kfree(host); | 442 | res = -EIO; |
| 395 | return -EIO; | 443 | goto err_nand_ioremap; |
| 396 | } | 444 | } |
| 397 | 445 | ||
| 398 | mtd = &host->mtd; | 446 | mtd = &host->mtd; |
| @@ -407,14 +455,14 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
| 407 | /* Set address of NAND IO lines */ | 455 | /* Set address of NAND IO lines */ |
| 408 | nand_chip->IO_ADDR_R = host->io_base; | 456 | nand_chip->IO_ADDR_R = host->io_base; |
| 409 | nand_chip->IO_ADDR_W = host->io_base; | 457 | nand_chip->IO_ADDR_W = host->io_base; |
| 410 | nand_chip->cmd_ctrl = at91_nand_cmd_ctrl; | 458 | nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl; |
| 411 | 459 | ||
| 412 | if (host->board->rdy_pin) | 460 | if (host->board->rdy_pin) |
| 413 | nand_chip->dev_ready = at91_nand_device_ready; | 461 | nand_chip->dev_ready = atmel_nand_device_ready; |
| 414 | 462 | ||
| 415 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 463 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
| 416 | if (!regs && hard_ecc) { | 464 | if (!regs && hard_ecc) { |
| 417 | printk(KERN_ERR "at91_nand: can't get I/O resource " | 465 | printk(KERN_ERR "atmel_nand: can't get I/O resource " |
| 418 | "regs\nFalling back on software ECC\n"); | 466 | "regs\nFalling back on software ECC\n"); |
| 419 | } | 467 | } |
| 420 | 468 | ||
| @@ -424,15 +472,15 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
| 424 | if (hard_ecc && regs) { | 472 | if (hard_ecc && regs) { |
| 425 | host->ecc = ioremap(regs->start, regs->end - regs->start + 1); | 473 | host->ecc = ioremap(regs->start, regs->end - regs->start + 1); |
| 426 | if (host->ecc == NULL) { | 474 | if (host->ecc == NULL) { |
| 427 | printk(KERN_ERR "at91_nand: ioremap failed\n"); | 475 | printk(KERN_ERR "atmel_nand: ioremap failed\n"); |
| 428 | res = -EIO; | 476 | res = -EIO; |
| 429 | goto err_ecc_ioremap; | 477 | goto err_ecc_ioremap; |
| 430 | } | 478 | } |
| 431 | nand_chip->ecc.mode = NAND_ECC_HW_SYNDROME; | 479 | nand_chip->ecc.mode = NAND_ECC_HW_SYNDROME; |
| 432 | nand_chip->ecc.calculate = at91_nand_calculate; | 480 | nand_chip->ecc.calculate = atmel_nand_calculate; |
| 433 | nand_chip->ecc.correct = at91_nand_correct; | 481 | nand_chip->ecc.correct = atmel_nand_correct; |
| 434 | nand_chip->ecc.hwctl = at91_nand_hwctl; | 482 | nand_chip->ecc.hwctl = atmel_nand_hwctl; |
| 435 | nand_chip->ecc.read_page = at91_nand_read_page; | 483 | nand_chip->ecc.read_page = atmel_nand_read_page; |
| 436 | nand_chip->ecc.bytes = 4; | 484 | nand_chip->ecc.bytes = 4; |
| 437 | nand_chip->ecc.prepad = 0; | 485 | nand_chip->ecc.prepad = 0; |
| 438 | nand_chip->ecc.postpad = 0; | 486 | nand_chip->ecc.postpad = 0; |
| @@ -440,24 +488,30 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
| 440 | 488 | ||
| 441 | nand_chip->chip_delay = 20; /* 20us command delay time */ | 489 | nand_chip->chip_delay = 20; /* 20us command delay time */ |
| 442 | 490 | ||
| 443 | if (host->board->bus_width_16) /* 16-bit bus width */ | 491 | if (host->board->bus_width_16) { /* 16-bit bus width */ |
| 444 | nand_chip->options |= NAND_BUSWIDTH_16; | 492 | nand_chip->options |= NAND_BUSWIDTH_16; |
| 493 | nand_chip->read_buf = atmel_read_buf16; | ||
| 494 | nand_chip->write_buf = atmel_write_buf16; | ||
| 495 | } else { | ||
| 496 | nand_chip->read_buf = atmel_read_buf; | ||
| 497 | nand_chip->write_buf = atmel_write_buf; | ||
| 498 | } | ||
| 445 | 499 | ||
| 446 | platform_set_drvdata(pdev, host); | 500 | platform_set_drvdata(pdev, host); |
| 447 | at91_nand_enable(host); | 501 | atmel_nand_enable(host); |
| 448 | 502 | ||
| 449 | if (host->board->det_pin) { | 503 | if (host->board->det_pin) { |
| 450 | if (at91_get_gpio_value(host->board->det_pin)) { | 504 | if (gpio_get_value(host->board->det_pin)) { |
| 451 | printk ("No SmartMedia card inserted.\n"); | 505 | printk("No SmartMedia card inserted.\n"); |
| 452 | res = ENXIO; | 506 | res = ENXIO; |
| 453 | goto out; | 507 | goto err_no_card; |
| 454 | } | 508 | } |
| 455 | } | 509 | } |
| 456 | 510 | ||
| 457 | /* first scan to find the device and get the page size */ | 511 | /* first scan to find the device and get the page size */ |
| 458 | if (nand_scan_ident(mtd, 1)) { | 512 | if (nand_scan_ident(mtd, 1)) { |
| 459 | res = -ENXIO; | 513 | res = -ENXIO; |
| 460 | goto out; | 514 | goto err_scan_ident; |
| 461 | } | 515 | } |
| 462 | 516 | ||
| 463 | if (nand_chip->ecc.mode == NAND_ECC_HW_SYNDROME) { | 517 | if (nand_chip->ecc.mode == NAND_ECC_HW_SYNDROME) { |
| @@ -467,22 +521,22 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
| 467 | /* set ECC page size and oob layout */ | 521 | /* set ECC page size and oob layout */ |
| 468 | switch (mtd->writesize) { | 522 | switch (mtd->writesize) { |
| 469 | case 512: | 523 | case 512: |
| 470 | nand_chip->ecc.layout = &at91_oobinfo_small; | 524 | nand_chip->ecc.layout = &atmel_oobinfo_small; |
| 471 | nand_chip->ecc.read_oob = at91_nand_read_oob_512; | 525 | nand_chip->ecc.read_oob = atmel_nand_read_oob_512; |
| 472 | nand_chip->ecc.write_oob = at91_nand_write_oob_512; | 526 | nand_chip->ecc.write_oob = atmel_nand_write_oob_512; |
| 473 | ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_528); | 527 | ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); |
| 474 | break; | 528 | break; |
| 475 | case 1024: | 529 | case 1024: |
| 476 | nand_chip->ecc.layout = &at91_oobinfo_large; | 530 | nand_chip->ecc.layout = &atmel_oobinfo_large; |
| 477 | ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_1056); | 531 | ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056); |
| 478 | break; | 532 | break; |
| 479 | case 2048: | 533 | case 2048: |
| 480 | nand_chip->ecc.layout = &at91_oobinfo_large; | 534 | nand_chip->ecc.layout = &atmel_oobinfo_large; |
| 481 | ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_2112); | 535 | ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112); |
| 482 | break; | 536 | break; |
| 483 | case 4096: | 537 | case 4096: |
| 484 | nand_chip->ecc.layout = &at91_oobinfo_large; | 538 | nand_chip->ecc.layout = &atmel_oobinfo_large; |
| 485 | ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_4224); | 539 | ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224); |
| 486 | break; | 540 | break; |
| 487 | default: | 541 | default: |
| 488 | /* page size not handled by HW ECC */ | 542 | /* page size not handled by HW ECC */ |
| @@ -502,12 +556,12 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
| 502 | /* second phase scan */ | 556 | /* second phase scan */ |
| 503 | if (nand_scan_tail(mtd)) { | 557 | if (nand_scan_tail(mtd)) { |
| 504 | res = -ENXIO; | 558 | res = -ENXIO; |
| 505 | goto out; | 559 | goto err_scan_tail; |
| 506 | } | 560 | } |
| 507 | 561 | ||
| 508 | #ifdef CONFIG_MTD_PARTITIONS | 562 | #ifdef CONFIG_MTD_PARTITIONS |
| 509 | #ifdef CONFIG_MTD_CMDLINE_PARTS | 563 | #ifdef CONFIG_MTD_CMDLINE_PARTS |
| 510 | mtd->name = "at91_nand"; | 564 | mtd->name = "atmel_nand"; |
| 511 | num_partitions = parse_mtd_partitions(mtd, part_probes, | 565 | num_partitions = parse_mtd_partitions(mtd, part_probes, |
| 512 | &partitions, 0); | 566 | &partitions, 0); |
| 513 | #endif | 567 | #endif |
| @@ -516,9 +570,9 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
| 516 | &num_partitions); | 570 | &num_partitions); |
| 517 | 571 | ||
| 518 | if ((!partitions) || (num_partitions == 0)) { | 572 | if ((!partitions) || (num_partitions == 0)) { |
| 519 | printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n"); | 573 | printk(KERN_ERR "atmel_nand: No parititions defined, or unsupported device.\n"); |
| 520 | res = ENXIO; | 574 | res = ENXIO; |
| 521 | goto release; | 575 | goto err_no_partitions; |
| 522 | } | 576 | } |
| 523 | 577 | ||
| 524 | res = add_mtd_partitions(mtd, partitions, num_partitions); | 578 | res = add_mtd_partitions(mtd, partitions, num_partitions); |
| @@ -530,17 +584,19 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
| 530 | return res; | 584 | return res; |
| 531 | 585 | ||
| 532 | #ifdef CONFIG_MTD_PARTITIONS | 586 | #ifdef CONFIG_MTD_PARTITIONS |
| 533 | release: | 587 | err_no_partitions: |
| 534 | #endif | 588 | #endif |
| 535 | nand_release(mtd); | 589 | nand_release(mtd); |
| 536 | 590 | err_scan_tail: | |
| 537 | out: | 591 | err_scan_ident: |
| 538 | iounmap(host->ecc); | 592 | err_no_card: |
| 539 | 593 | atmel_nand_disable(host); | |
| 540 | err_ecc_ioremap: | ||
| 541 | at91_nand_disable(host); | ||
| 542 | platform_set_drvdata(pdev, NULL); | 594 | platform_set_drvdata(pdev, NULL); |
| 595 | if (host->ecc) | ||
| 596 | iounmap(host->ecc); | ||
| 597 | err_ecc_ioremap: | ||
| 543 | iounmap(host->io_base); | 598 | iounmap(host->io_base); |
| 599 | err_nand_ioremap: | ||
| 544 | kfree(host); | 600 | kfree(host); |
| 545 | return res; | 601 | return res; |
| 546 | } | 602 | } |
| @@ -548,47 +604,47 @@ err_ecc_ioremap: | |||
| 548 | /* | 604 | /* |
| 549 | * Remove a NAND device. | 605 | * Remove a NAND device. |
| 550 | */ | 606 | */ |
| 551 | static int __devexit at91_nand_remove(struct platform_device *pdev) | 607 | static int __exit atmel_nand_remove(struct platform_device *pdev) |
| 552 | { | 608 | { |
| 553 | struct at91_nand_host *host = platform_get_drvdata(pdev); | 609 | struct atmel_nand_host *host = platform_get_drvdata(pdev); |
| 554 | struct mtd_info *mtd = &host->mtd; | 610 | struct mtd_info *mtd = &host->mtd; |
| 555 | 611 | ||
| 556 | nand_release(mtd); | 612 | nand_release(mtd); |
| 557 | 613 | ||
| 558 | at91_nand_disable(host); | 614 | atmel_nand_disable(host); |
| 559 | 615 | ||
| 616 | if (host->ecc) | ||
| 617 | iounmap(host->ecc); | ||
| 560 | iounmap(host->io_base); | 618 | iounmap(host->io_base); |
| 561 | iounmap(host->ecc); | ||
| 562 | kfree(host); | 619 | kfree(host); |
| 563 | 620 | ||
| 564 | return 0; | 621 | return 0; |
| 565 | } | 622 | } |
| 566 | 623 | ||
| 567 | static struct platform_driver at91_nand_driver = { | 624 | static struct platform_driver atmel_nand_driver = { |
| 568 | .probe = at91_nand_probe, | 625 | .remove = __exit_p(atmel_nand_remove), |
| 569 | .remove = at91_nand_remove, | ||
| 570 | .driver = { | 626 | .driver = { |
| 571 | .name = "at91_nand", | 627 | .name = "atmel_nand", |
| 572 | .owner = THIS_MODULE, | 628 | .owner = THIS_MODULE, |
| 573 | }, | 629 | }, |
| 574 | }; | 630 | }; |
| 575 | 631 | ||
| 576 | static int __init at91_nand_init(void) | 632 | static int __init atmel_nand_init(void) |
| 577 | { | 633 | { |
| 578 | return platform_driver_register(&at91_nand_driver); | 634 | return platform_driver_probe(&atmel_nand_driver, atmel_nand_probe); |
| 579 | } | 635 | } |
| 580 | 636 | ||
| 581 | 637 | ||
| 582 | static void __exit at91_nand_exit(void) | 638 | static void __exit atmel_nand_exit(void) |
| 583 | { | 639 | { |
| 584 | platform_driver_unregister(&at91_nand_driver); | 640 | platform_driver_unregister(&atmel_nand_driver); |
| 585 | } | 641 | } |
| 586 | 642 | ||
| 587 | 643 | ||
| 588 | module_init(at91_nand_init); | 644 | module_init(atmel_nand_init); |
| 589 | module_exit(at91_nand_exit); | 645 | module_exit(atmel_nand_exit); |
| 590 | 646 | ||
| 591 | MODULE_LICENSE("GPL"); | 647 | MODULE_LICENSE("GPL"); |
| 592 | MODULE_AUTHOR("Rick Bronson"); | 648 | MODULE_AUTHOR("Rick Bronson"); |
| 593 | MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200 / AT91SAM9"); | 649 | MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91 / AVR32"); |
| 594 | MODULE_ALIAS("platform:at91_nand"); | 650 | MODULE_ALIAS("platform:atmel_nand"); |
diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h new file mode 100644 index 000000000000..1ee7f993db1c --- /dev/null +++ b/drivers/mtd/nand/atmel_nand_ecc.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | /* | ||
| 2 | * Error Corrected Code Controller (ECC) - System peripherals regsters. | ||
| 3 | * Based on AT91SAM9260 datasheet revision B. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License as published by the | ||
| 7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 8 | * option) any later version. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef ATMEL_NAND_ECC_H | ||
| 12 | #define ATMEL_NAND_ECC_H | ||
| 13 | |||
| 14 | #define ATMEL_ECC_CR 0x00 /* Control register */ | ||
| 15 | #define ATMEL_ECC_RST (1 << 0) /* Reset parity */ | ||
| 16 | |||
| 17 | #define ATMEL_ECC_MR 0x04 /* Mode register */ | ||
| 18 | #define ATMEL_ECC_PAGESIZE (3 << 0) /* Page Size */ | ||
| 19 | #define ATMEL_ECC_PAGESIZE_528 (0) | ||
| 20 | #define ATMEL_ECC_PAGESIZE_1056 (1) | ||
| 21 | #define ATMEL_ECC_PAGESIZE_2112 (2) | ||
| 22 | #define ATMEL_ECC_PAGESIZE_4224 (3) | ||
| 23 | |||
| 24 | #define ATMEL_ECC_SR 0x08 /* Status register */ | ||
| 25 | #define ATMEL_ECC_RECERR (1 << 0) /* Recoverable Error */ | ||
| 26 | #define ATMEL_ECC_ECCERR (1 << 1) /* ECC Single Bit Error */ | ||
| 27 | #define ATMEL_ECC_MULERR (1 << 2) /* Multiple Errors */ | ||
| 28 | |||
| 29 | #define ATMEL_ECC_PR 0x0c /* Parity register */ | ||
| 30 | #define ATMEL_ECC_BITADDR (0xf << 0) /* Bit Error Address */ | ||
| 31 | #define ATMEL_ECC_WORDADDR (0xfff << 4) /* Word Error Address */ | ||
| 32 | |||
| 33 | #define ATMEL_ECC_NPR 0x10 /* NParity register */ | ||
| 34 | #define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */ | ||
| 35 | |||
| 36 | #endif | ||
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 09e421a96893..761946ea45b1 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c | |||
| @@ -3,8 +3,6 @@ | |||
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2004 Embedded Edge, LLC | 4 | * Copyright (C) 2004 Embedded Edge, LLC |
| 5 | * | 5 | * |
| 6 | * $Id: au1550nd.c,v 1.13 2005/11/07 11:14:30 gleixner Exp $ | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
| 9 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
| 10 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
| @@ -604,8 +602,6 @@ module_init(au1xxx_nand_init); | |||
| 604 | */ | 602 | */ |
| 605 | static void __exit au1550_cleanup(void) | 603 | static void __exit au1550_cleanup(void) |
| 606 | { | 604 | { |
| 607 | struct nand_chip *this = (struct nand_chip *)&au1550_mtd[1]; | ||
| 608 | |||
| 609 | /* Release resources, unregister device */ | 605 | /* Release resources, unregister device */ |
| 610 | nand_release(au1550_mtd); | 606 | nand_release(au1550_mtd); |
| 611 | 607 | ||
diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index dd38011ee0b7..553dd7e9b41c 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c | |||
| @@ -6,8 +6,6 @@ | |||
| 6 | * Derived from drivers/mtd/spia.c | 6 | * Derived from drivers/mtd/spia.c |
| 7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) | 7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) |
| 8 | * | 8 | * |
| 9 | * $Id: autcpu12.c,v 1.23 2005/11/07 11:14:30 gleixner Exp $ | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
| 12 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
| 13 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index da6ceaa80ba1..95345d051579 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c | |||
| @@ -626,10 +626,12 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, | |||
| 626 | { | 626 | { |
| 627 | struct mtd_info *mtd; | 627 | struct mtd_info *mtd; |
| 628 | struct cafe_priv *cafe; | 628 | struct cafe_priv *cafe; |
| 629 | struct mtd_partition *parts; | ||
| 630 | uint32_t ctrl; | 629 | uint32_t ctrl; |
| 631 | int nr_parts; | ||
| 632 | int err = 0; | 630 | int err = 0; |
| 631 | #ifdef CONFIG_MTD_PARTITIONS | ||
| 632 | struct mtd_partition *parts; | ||
| 633 | int nr_parts; | ||
| 634 | #endif | ||
| 633 | 635 | ||
| 634 | /* Very old versions shared the same PCI ident for all three | 636 | /* Very old versions shared the same PCI ident for all three |
| 635 | functions on the chip. Verify the class too... */ | 637 | functions on the chip. Verify the class too... */ |
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 0e72153b3297..765d4f0f7c86 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c | |||
| @@ -15,8 +15,6 @@ | |||
| 15 | * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de> | 15 | * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de> |
| 16 | * | 16 | * |
| 17 | * Interface to generic NAND code for M-Systems DiskOnChip devices | 17 | * Interface to generic NAND code for M-Systems DiskOnChip devices |
| 18 | * | ||
| 19 | * $Id: diskonchip.c,v 1.55 2005/11/07 11:14:30 gleixner Exp $ | ||
| 20 | */ | 18 | */ |
| 21 | 19 | ||
| 22 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
| @@ -54,8 +52,6 @@ static unsigned long __initdata doc_locations[] = { | |||
| 54 | 0xe0000, 0xe2000, 0xe4000, 0xe6000, | 52 | 0xe0000, 0xe2000, 0xe4000, 0xe6000, |
| 55 | 0xe8000, 0xea000, 0xec000, 0xee000, | 53 | 0xe8000, 0xea000, 0xec000, 0xee000, |
| 56 | #endif /* CONFIG_MTD_DOCPROBE_HIGH */ | 54 | #endif /* CONFIG_MTD_DOCPROBE_HIGH */ |
| 57 | #elif defined(__PPC__) | ||
| 58 | 0xe4000000, | ||
| 59 | #else | 55 | #else |
| 60 | #warning Unknown architecture for DiskOnChip. No default probe locations defined | 56 | #warning Unknown architecture for DiskOnChip. No default probe locations defined |
| 61 | #endif | 57 | #endif |
diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c index ba67bbec20d3..387e4352903e 100644 --- a/drivers/mtd/nand/edb7312.c +++ b/drivers/mtd/nand/edb7312.c | |||
| @@ -6,8 +6,6 @@ | |||
| 6 | * Derived from drivers/mtd/nand/autcpu12.c | 6 | * Derived from drivers/mtd/nand/autcpu12.c |
| 7 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) | 7 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) |
| 8 | * | 8 | * |
| 9 | * $Id: edb7312.c,v 1.12 2005/11/07 11:14:30 gleixner Exp $ | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
| 12 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
| 13 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
diff --git a/drivers/mtd/nand/excite_nandflash.c b/drivers/mtd/nand/excite_nandflash.c index bed87290decc..ced14b5294d5 100644 --- a/drivers/mtd/nand/excite_nandflash.c +++ b/drivers/mtd/nand/excite_nandflash.c | |||
| @@ -209,7 +209,7 @@ static int __init excite_nand_probe(struct device *dev) | |||
| 209 | if (likely(!scan_res)) { | 209 | if (likely(!scan_res)) { |
| 210 | DEBUG(MTD_DEBUG_LEVEL2, "%s: register partitions\n", module_id); | 210 | DEBUG(MTD_DEBUG_LEVEL2, "%s: register partitions\n", module_id); |
| 211 | add_mtd_partitions(&drvdata->board_mtd, partition_info, | 211 | add_mtd_partitions(&drvdata->board_mtd, partition_info, |
| 212 | sizeof partition_info / sizeof partition_info[0]); | 212 | ARRAY_SIZE(partition_info)); |
| 213 | } else { | 213 | } else { |
| 214 | iounmap(drvdata->regs); | 214 | iounmap(drvdata->regs); |
| 215 | kfree(drvdata); | 215 | kfree(drvdata); |
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 4b69aacdf5ca..9dff51351f4f 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c | |||
| @@ -89,7 +89,6 @@ static struct nand_ecclayout fsl_elbc_oob_sp_eccm0 = { | |||
| 89 | .eccbytes = 3, | 89 | .eccbytes = 3, |
| 90 | .eccpos = {6, 7, 8}, | 90 | .eccpos = {6, 7, 8}, |
| 91 | .oobfree = { {0, 5}, {9, 7} }, | 91 | .oobfree = { {0, 5}, {9, 7} }, |
| 92 | .oobavail = 12, | ||
| 93 | }; | 92 | }; |
| 94 | 93 | ||
| 95 | /* Small Page FLASH with FMR[ECCM] = 1 */ | 94 | /* Small Page FLASH with FMR[ECCM] = 1 */ |
| @@ -97,7 +96,6 @@ static struct nand_ecclayout fsl_elbc_oob_sp_eccm1 = { | |||
| 97 | .eccbytes = 3, | 96 | .eccbytes = 3, |
| 98 | .eccpos = {8, 9, 10}, | 97 | .eccpos = {8, 9, 10}, |
| 99 | .oobfree = { {0, 5}, {6, 2}, {11, 5} }, | 98 | .oobfree = { {0, 5}, {6, 2}, {11, 5} }, |
| 100 | .oobavail = 12, | ||
| 101 | }; | 99 | }; |
| 102 | 100 | ||
| 103 | /* Large Page FLASH with FMR[ECCM] = 0 */ | 101 | /* Large Page FLASH with FMR[ECCM] = 0 */ |
| @@ -105,7 +103,6 @@ static struct nand_ecclayout fsl_elbc_oob_lp_eccm0 = { | |||
| 105 | .eccbytes = 12, | 103 | .eccbytes = 12, |
| 106 | .eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56}, | 104 | .eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56}, |
| 107 | .oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} }, | 105 | .oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} }, |
| 108 | .oobavail = 48, | ||
| 109 | }; | 106 | }; |
| 110 | 107 | ||
| 111 | /* Large Page FLASH with FMR[ECCM] = 1 */ | 108 | /* Large Page FLASH with FMR[ECCM] = 1 */ |
| @@ -113,7 +110,48 @@ static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = { | |||
| 113 | .eccbytes = 12, | 110 | .eccbytes = 12, |
| 114 | .eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58}, | 111 | .eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58}, |
| 115 | .oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} }, | 112 | .oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} }, |
| 116 | .oobavail = 48, | 113 | }; |
| 114 | |||
| 115 | /* | ||
| 116 | * fsl_elbc_oob_lp_eccm* specify that LP NAND's OOB free area starts at offset | ||
| 117 | * 1, so we have to adjust bad block pattern. This pattern should be used for | ||
| 118 | * x8 chips only. So far hardware does not support x16 chips anyway. | ||
| 119 | */ | ||
| 120 | static u8 scan_ff_pattern[] = { 0xff, }; | ||
| 121 | |||
| 122 | static struct nand_bbt_descr largepage_memorybased = { | ||
| 123 | .options = 0, | ||
| 124 | .offs = 0, | ||
| 125 | .len = 1, | ||
| 126 | .pattern = scan_ff_pattern, | ||
| 127 | }; | ||
| 128 | |||
| 129 | /* | ||
| 130 | * ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt, | ||
| 131 | * interfere with ECC positions, that's why we implement our own descriptors. | ||
| 132 | * OOB {11, 5}, works for both SP and LP chips, with ECCM = 1 and ECCM = 0. | ||
| 133 | */ | ||
| 134 | static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; | ||
| 135 | static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; | ||
| 136 | |||
| 137 | static struct nand_bbt_descr bbt_main_descr = { | ||
| 138 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | | ||
| 139 | NAND_BBT_2BIT | NAND_BBT_VERSION, | ||
| 140 | .offs = 11, | ||
| 141 | .len = 4, | ||
| 142 | .veroffs = 15, | ||
| 143 | .maxblocks = 4, | ||
| 144 | .pattern = bbt_pattern, | ||
| 145 | }; | ||
| 146 | |||
| 147 | static struct nand_bbt_descr bbt_mirror_descr = { | ||
| 148 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | | ||
| 149 | NAND_BBT_2BIT | NAND_BBT_VERSION, | ||
| 150 | .offs = 11, | ||
| 151 | .len = 4, | ||
| 152 | .veroffs = 15, | ||
| 153 | .maxblocks = 4, | ||
| 154 | .pattern = mirror_pattern, | ||
| 117 | }; | 155 | }; |
| 118 | 156 | ||
| 119 | /*=================================*/ | 157 | /*=================================*/ |
| @@ -687,8 +725,7 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) | |||
| 687 | chip->ecc.layout = (priv->fmr & FMR_ECCM) ? | 725 | chip->ecc.layout = (priv->fmr & FMR_ECCM) ? |
| 688 | &fsl_elbc_oob_lp_eccm1 : | 726 | &fsl_elbc_oob_lp_eccm1 : |
| 689 | &fsl_elbc_oob_lp_eccm0; | 727 | &fsl_elbc_oob_lp_eccm0; |
| 690 | mtd->ecclayout = chip->ecc.layout; | 728 | chip->badblock_pattern = &largepage_memorybased; |
| 691 | mtd->oobavail = chip->ecc.layout->oobavail; | ||
| 692 | } | 729 | } |
| 693 | } else { | 730 | } else { |
| 694 | dev_err(ctrl->dev, | 731 | dev_err(ctrl->dev, |
| @@ -752,8 +789,12 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) | |||
| 752 | chip->cmdfunc = fsl_elbc_cmdfunc; | 789 | chip->cmdfunc = fsl_elbc_cmdfunc; |
| 753 | chip->waitfunc = fsl_elbc_wait; | 790 | chip->waitfunc = fsl_elbc_wait; |
| 754 | 791 | ||
| 792 | chip->bbt_td = &bbt_main_descr; | ||
| 793 | chip->bbt_md = &bbt_mirror_descr; | ||
| 794 | |||
| 755 | /* set up nand options */ | 795 | /* set up nand options */ |
| 756 | chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR; | 796 | chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR | |
| 797 | NAND_USE_FLASH_BBT; | ||
| 757 | 798 | ||
| 758 | chip->controller = &ctrl->controller; | 799 | chip->controller = &ctrl->controller; |
| 759 | chip->priv = priv; | 800 | chip->priv = priv; |
| @@ -795,8 +836,8 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv) | |||
| 795 | return 0; | 836 | return 0; |
| 796 | } | 837 | } |
| 797 | 838 | ||
| 798 | static int fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, | 839 | static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, |
| 799 | struct device_node *node) | 840 | struct device_node *node) |
| 800 | { | 841 | { |
| 801 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; | 842 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; |
| 802 | struct fsl_elbc_mtd *priv; | 843 | struct fsl_elbc_mtd *priv; |
| @@ -917,7 +958,7 @@ static int __devinit fsl_elbc_ctrl_init(struct fsl_elbc_ctrl *ctrl) | |||
| 917 | return 0; | 958 | return 0; |
| 918 | } | 959 | } |
| 919 | 960 | ||
| 920 | static int __devexit fsl_elbc_ctrl_remove(struct of_device *ofdev) | 961 | static int fsl_elbc_ctrl_remove(struct of_device *ofdev) |
| 921 | { | 962 | { |
| 922 | struct fsl_elbc_ctrl *ctrl = dev_get_drvdata(&ofdev->dev); | 963 | struct fsl_elbc_ctrl *ctrl = dev_get_drvdata(&ofdev->dev); |
| 923 | int i; | 964 | int i; |
| @@ -1041,7 +1082,7 @@ static struct of_platform_driver fsl_elbc_ctrl_driver = { | |||
| 1041 | }, | 1082 | }, |
| 1042 | .match_table = fsl_elbc_match, | 1083 | .match_table = fsl_elbc_match, |
| 1043 | .probe = fsl_elbc_ctrl_probe, | 1084 | .probe = fsl_elbc_ctrl_probe, |
| 1044 | .remove = __devexit_p(fsl_elbc_ctrl_remove), | 1085 | .remove = fsl_elbc_ctrl_remove, |
| 1045 | }; | 1086 | }; |
| 1046 | 1087 | ||
| 1047 | static int __init fsl_elbc_init(void) | 1088 | static int __init fsl_elbc_init(void) |
diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c index 2d585d2d090c..9e59de501c2e 100644 --- a/drivers/mtd/nand/h1910.c +++ b/drivers/mtd/nand/h1910.c | |||
| @@ -7,8 +7,6 @@ | |||
| 7 | * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) | 7 | * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) |
| 8 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) | 8 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) |
| 9 | * | 9 | * |
| 10 | * $Id: h1910.c,v 1.6 2005/11/07 11:14:30 gleixner Exp $ | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
| 13 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
| 14 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ba1bdf787323..d1129bae6c27 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
| @@ -798,6 +798,87 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 798 | } | 798 | } |
| 799 | 799 | ||
| 800 | /** | 800 | /** |
| 801 | * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function | ||
| 802 | * @mtd: mtd info structure | ||
| 803 | * @chip: nand chip info structure | ||
| 804 | * @dataofs offset of requested data within the page | ||
| 805 | * @readlen data length | ||
| 806 | * @buf: buffer to store read data | ||
| 807 | */ | ||
| 808 | static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) | ||
| 809 | { | ||
| 810 | int start_step, end_step, num_steps; | ||
| 811 | uint32_t *eccpos = chip->ecc.layout->eccpos; | ||
| 812 | uint8_t *p; | ||
| 813 | int data_col_addr, i, gaps = 0; | ||
| 814 | int datafrag_len, eccfrag_len, aligned_len, aligned_pos; | ||
| 815 | int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; | ||
| 816 | |||
| 817 | /* Column address wihin the page aligned to ECC size (256bytes). */ | ||
| 818 | start_step = data_offs / chip->ecc.size; | ||
| 819 | end_step = (data_offs + readlen - 1) / chip->ecc.size; | ||
| 820 | num_steps = end_step - start_step + 1; | ||
| 821 | |||
| 822 | /* Data size aligned to ECC ecc.size*/ | ||
| 823 | datafrag_len = num_steps * chip->ecc.size; | ||
| 824 | eccfrag_len = num_steps * chip->ecc.bytes; | ||
| 825 | |||
| 826 | data_col_addr = start_step * chip->ecc.size; | ||
| 827 | /* If we read not a page aligned data */ | ||
| 828 | if (data_col_addr != 0) | ||
| 829 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1); | ||
| 830 | |||
| 831 | p = bufpoi + data_col_addr; | ||
| 832 | chip->read_buf(mtd, p, datafrag_len); | ||
| 833 | |||
| 834 | /* Calculate ECC */ | ||
| 835 | for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) | ||
| 836 | chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]); | ||
| 837 | |||
| 838 | /* The performance is faster if to position offsets | ||
| 839 | according to ecc.pos. Let make sure here that | ||
| 840 | there are no gaps in ecc positions */ | ||
| 841 | for (i = 0; i < eccfrag_len - 1; i++) { | ||
| 842 | if (eccpos[i + start_step * chip->ecc.bytes] + 1 != | ||
| 843 | eccpos[i + start_step * chip->ecc.bytes + 1]) { | ||
| 844 | gaps = 1; | ||
| 845 | break; | ||
| 846 | } | ||
| 847 | } | ||
| 848 | if (gaps) { | ||
| 849 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); | ||
| 850 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
| 851 | } else { | ||
| 852 | /* send the command to read the particular ecc bytes */ | ||
| 853 | /* take care about buswidth alignment in read_buf */ | ||
| 854 | aligned_pos = eccpos[start_step * chip->ecc.bytes] & ~(busw - 1); | ||
| 855 | aligned_len = eccfrag_len; | ||
| 856 | if (eccpos[start_step * chip->ecc.bytes] & (busw - 1)) | ||
| 857 | aligned_len++; | ||
| 858 | if (eccpos[(start_step + num_steps) * chip->ecc.bytes] & (busw - 1)) | ||
| 859 | aligned_len++; | ||
| 860 | |||
| 861 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize + aligned_pos, -1); | ||
| 862 | chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len); | ||
| 863 | } | ||
| 864 | |||
| 865 | for (i = 0; i < eccfrag_len; i++) | ||
| 866 | chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + start_step * chip->ecc.bytes]]; | ||
| 867 | |||
| 868 | p = bufpoi + data_col_addr; | ||
| 869 | for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) { | ||
| 870 | int stat; | ||
| 871 | |||
| 872 | stat = chip->ecc.correct(mtd, p, &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); | ||
| 873 | if (stat == -1) | ||
| 874 | mtd->ecc_stats.failed++; | ||
| 875 | else | ||
| 876 | mtd->ecc_stats.corrected += stat; | ||
| 877 | } | ||
| 878 | return 0; | ||
| 879 | } | ||
| 880 | |||
| 881 | /** | ||
| 801 | * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function | 882 | * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function |
| 802 | * @mtd: mtd info structure | 883 | * @mtd: mtd info structure |
| 803 | * @chip: nand chip info structure | 884 | * @chip: nand chip info structure |
| @@ -994,6 +1075,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
| 994 | /* Now read the page into the buffer */ | 1075 | /* Now read the page into the buffer */ |
| 995 | if (unlikely(ops->mode == MTD_OOB_RAW)) | 1076 | if (unlikely(ops->mode == MTD_OOB_RAW)) |
| 996 | ret = chip->ecc.read_page_raw(mtd, chip, bufpoi); | 1077 | ret = chip->ecc.read_page_raw(mtd, chip, bufpoi); |
| 1078 | else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) | ||
| 1079 | ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi); | ||
| 997 | else | 1080 | else |
| 998 | ret = chip->ecc.read_page(mtd, chip, bufpoi); | 1081 | ret = chip->ecc.read_page(mtd, chip, bufpoi); |
| 999 | if (ret < 0) | 1082 | if (ret < 0) |
| @@ -1001,7 +1084,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
| 1001 | 1084 | ||
| 1002 | /* Transfer not aligned data */ | 1085 | /* Transfer not aligned data */ |
| 1003 | if (!aligned) { | 1086 | if (!aligned) { |
| 1004 | chip->pagebuf = realpage; | 1087 | if (!NAND_SUBPAGE_READ(chip) && !oob) |
| 1088 | chip->pagebuf = realpage; | ||
| 1005 | memcpy(buf, chip->buffers->databuf + col, bytes); | 1089 | memcpy(buf, chip->buffers->databuf + col, bytes); |
| 1006 | } | 1090 | } |
| 1007 | 1091 | ||
| @@ -2521,6 +2605,7 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
| 2521 | chip->ecc.calculate = nand_calculate_ecc; | 2605 | chip->ecc.calculate = nand_calculate_ecc; |
| 2522 | chip->ecc.correct = nand_correct_data; | 2606 | chip->ecc.correct = nand_correct_data; |
| 2523 | chip->ecc.read_page = nand_read_page_swecc; | 2607 | chip->ecc.read_page = nand_read_page_swecc; |
| 2608 | chip->ecc.read_subpage = nand_read_subpage; | ||
| 2524 | chip->ecc.write_page = nand_write_page_swecc; | 2609 | chip->ecc.write_page = nand_write_page_swecc; |
| 2525 | chip->ecc.read_oob = nand_read_oob_std; | 2610 | chip->ecc.read_oob = nand_read_oob_std; |
| 2526 | chip->ecc.write_oob = nand_write_oob_std; | 2611 | chip->ecc.write_oob = nand_write_oob_std; |
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 5e121ceaa598..0b1c48595f12 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c | |||
| @@ -6,8 +6,6 @@ | |||
| 6 | * | 6 | * |
| 7 | * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) | 7 | * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) |
| 8 | * | 8 | * |
| 9 | * $Id: nand_bbt.c,v 1.36 2005/11/07 11:14:30 gleixner Exp $ | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
| 12 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
| 13 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index 9003a135e050..918a806a8471 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c | |||
| @@ -9,8 +9,6 @@ | |||
| 9 | * | 9 | * |
| 10 | * Copyright (C) 2006 Thomas Gleixner <tglx@linutronix.de> | 10 | * Copyright (C) 2006 Thomas Gleixner <tglx@linutronix.de> |
| 11 | * | 11 | * |
| 12 | * $Id: nand_ecc.c,v 1.15 2005/11/07 11:14:30 gleixner Exp $ | ||
| 13 | * | ||
| 14 | * This file is free software; you can redistribute it and/or modify it | 12 | * This file is free software; you can redistribute it and/or modify it |
| 15 | * under the terms of the GNU General Public License as published by the | 13 | * under the terms of the GNU General Public License as published by the |
| 16 | * Free Software Foundation; either version 2 or (at your option) any | 14 | * Free Software Foundation; either version 2 or (at your option) any |
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index a3e3ab0185d5..69ee2c90eb0b 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c | |||
| @@ -3,8 +3,6 @@ | |||
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) | 4 | * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) |
| 5 | * | 5 | * |
| 6 | * $Id: nand_ids.c,v 1.16 2005/11/07 11:14:31 gleixner Exp $ | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
| 9 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
| 10 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index bb885d1fcab5..ecd70e2504f6 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c | |||
| @@ -21,8 +21,6 @@ | |||
| 21 | * You should have received a copy of the GNU General Public License | 21 | * You should have received a copy of the GNU General Public License |
| 22 | * along with this program; if not, write to the Free Software | 22 | * along with this program; if not, write to the Free Software |
| 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA | 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA |
| 24 | * | ||
| 25 | * $Id: nandsim.c,v 1.8 2005/03/19 15:33:56 dedekind Exp $ | ||
| 26 | */ | 24 | */ |
| 27 | 25 | ||
| 28 | #include <linux/init.h> | 26 | #include <linux/init.h> |
| @@ -39,6 +37,7 @@ | |||
| 39 | #include <linux/delay.h> | 37 | #include <linux/delay.h> |
| 40 | #include <linux/list.h> | 38 | #include <linux/list.h> |
| 41 | #include <linux/random.h> | 39 | #include <linux/random.h> |
| 40 | #include <asm/div64.h> | ||
| 42 | 41 | ||
| 43 | /* Default simulator parameters values */ | 42 | /* Default simulator parameters values */ |
| 44 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ | 43 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ |
| @@ -298,11 +297,11 @@ struct nandsim { | |||
| 298 | 297 | ||
| 299 | /* NAND flash "geometry" */ | 298 | /* NAND flash "geometry" */ |
| 300 | struct nandsin_geometry { | 299 | struct nandsin_geometry { |
| 301 | uint32_t totsz; /* total flash size, bytes */ | 300 | uint64_t totsz; /* total flash size, bytes */ |
| 302 | uint32_t secsz; /* flash sector (erase block) size, bytes */ | 301 | uint32_t secsz; /* flash sector (erase block) size, bytes */ |
| 303 | uint pgsz; /* NAND flash page size, bytes */ | 302 | uint pgsz; /* NAND flash page size, bytes */ |
| 304 | uint oobsz; /* page OOB area size, bytes */ | 303 | uint oobsz; /* page OOB area size, bytes */ |
| 305 | uint32_t totszoob; /* total flash size including OOB, bytes */ | 304 | uint64_t totszoob; /* total flash size including OOB, bytes */ |
| 306 | uint pgszoob; /* page size including OOB , bytes*/ | 305 | uint pgszoob; /* page size including OOB , bytes*/ |
| 307 | uint secszoob; /* sector size including OOB, bytes */ | 306 | uint secszoob; /* sector size including OOB, bytes */ |
| 308 | uint pgnum; /* total number of pages */ | 307 | uint pgnum; /* total number of pages */ |
| @@ -459,6 +458,12 @@ static char *get_partition_name(int i) | |||
| 459 | return kstrdup(buf, GFP_KERNEL); | 458 | return kstrdup(buf, GFP_KERNEL); |
| 460 | } | 459 | } |
| 461 | 460 | ||
| 461 | static u_int64_t divide(u_int64_t n, u_int32_t d) | ||
| 462 | { | ||
| 463 | do_div(n, d); | ||
| 464 | return n; | ||
| 465 | } | ||
| 466 | |||
| 462 | /* | 467 | /* |
| 463 | * Initialize the nandsim structure. | 468 | * Initialize the nandsim structure. |
| 464 | * | 469 | * |
| @@ -469,8 +474,8 @@ static int init_nandsim(struct mtd_info *mtd) | |||
| 469 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; | 474 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; |
| 470 | struct nandsim *ns = (struct nandsim *)(chip->priv); | 475 | struct nandsim *ns = (struct nandsim *)(chip->priv); |
| 471 | int i, ret = 0; | 476 | int i, ret = 0; |
| 472 | u_int32_t remains; | 477 | u_int64_t remains; |
| 473 | u_int32_t next_offset; | 478 | u_int64_t next_offset; |
| 474 | 479 | ||
| 475 | if (NS_IS_INITIALIZED(ns)) { | 480 | if (NS_IS_INITIALIZED(ns)) { |
| 476 | NS_ERR("init_nandsim: nandsim is already initialized\n"); | 481 | NS_ERR("init_nandsim: nandsim is already initialized\n"); |
| @@ -487,8 +492,8 @@ static int init_nandsim(struct mtd_info *mtd) | |||
| 487 | ns->geom.oobsz = mtd->oobsize; | 492 | ns->geom.oobsz = mtd->oobsize; |
| 488 | ns->geom.secsz = mtd->erasesize; | 493 | ns->geom.secsz = mtd->erasesize; |
| 489 | ns->geom.pgszoob = ns->geom.pgsz + ns->geom.oobsz; | 494 | ns->geom.pgszoob = ns->geom.pgsz + ns->geom.oobsz; |
| 490 | ns->geom.pgnum = ns->geom.totsz / ns->geom.pgsz; | 495 | ns->geom.pgnum = divide(ns->geom.totsz, ns->geom.pgsz); |
| 491 | ns->geom.totszoob = ns->geom.totsz + ns->geom.pgnum * ns->geom.oobsz; | 496 | ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz; |
| 492 | ns->geom.secshift = ffs(ns->geom.secsz) - 1; | 497 | ns->geom.secshift = ffs(ns->geom.secsz) - 1; |
| 493 | ns->geom.pgshift = chip->page_shift; | 498 | ns->geom.pgshift = chip->page_shift; |
| 494 | ns->geom.oobshift = ffs(ns->geom.oobsz) - 1; | 499 | ns->geom.oobshift = ffs(ns->geom.oobsz) - 1; |
| @@ -511,7 +516,7 @@ static int init_nandsim(struct mtd_info *mtd) | |||
| 511 | } | 516 | } |
| 512 | 517 | ||
| 513 | if (ns->options & OPT_SMALLPAGE) { | 518 | if (ns->options & OPT_SMALLPAGE) { |
| 514 | if (ns->geom.totsz < (32 << 20)) { | 519 | if (ns->geom.totsz <= (32 << 20)) { |
| 515 | ns->geom.pgaddrbytes = 3; | 520 | ns->geom.pgaddrbytes = 3; |
| 516 | ns->geom.secaddrbytes = 2; | 521 | ns->geom.secaddrbytes = 2; |
| 517 | } else { | 522 | } else { |
| @@ -537,15 +542,16 @@ static int init_nandsim(struct mtd_info *mtd) | |||
| 537 | remains = ns->geom.totsz; | 542 | remains = ns->geom.totsz; |
| 538 | next_offset = 0; | 543 | next_offset = 0; |
| 539 | for (i = 0; i < parts_num; ++i) { | 544 | for (i = 0; i < parts_num; ++i) { |
| 540 | unsigned long part = parts[i]; | 545 | u_int64_t part_sz = (u_int64_t)parts[i] * ns->geom.secsz; |
| 541 | if (!part || part > remains / ns->geom.secsz) { | 546 | |
| 547 | if (!part_sz || part_sz > remains) { | ||
| 542 | NS_ERR("bad partition size.\n"); | 548 | NS_ERR("bad partition size.\n"); |
| 543 | ret = -EINVAL; | 549 | ret = -EINVAL; |
| 544 | goto error; | 550 | goto error; |
| 545 | } | 551 | } |
| 546 | ns->partitions[i].name = get_partition_name(i); | 552 | ns->partitions[i].name = get_partition_name(i); |
| 547 | ns->partitions[i].offset = next_offset; | 553 | ns->partitions[i].offset = next_offset; |
| 548 | ns->partitions[i].size = part * ns->geom.secsz; | 554 | ns->partitions[i].size = part_sz; |
| 549 | next_offset += ns->partitions[i].size; | 555 | next_offset += ns->partitions[i].size; |
| 550 | remains -= ns->partitions[i].size; | 556 | remains -= ns->partitions[i].size; |
| 551 | } | 557 | } |
| @@ -573,7 +579,7 @@ static int init_nandsim(struct mtd_info *mtd) | |||
| 573 | if (ns->busw == 16) | 579 | if (ns->busw == 16) |
| 574 | NS_WARN("16-bit flashes support wasn't tested\n"); | 580 | NS_WARN("16-bit flashes support wasn't tested\n"); |
| 575 | 581 | ||
| 576 | printk("flash size: %u MiB\n", ns->geom.totsz >> 20); | 582 | printk("flash size: %llu MiB\n", ns->geom.totsz >> 20); |
| 577 | printk("page size: %u bytes\n", ns->geom.pgsz); | 583 | printk("page size: %u bytes\n", ns->geom.pgsz); |
| 578 | printk("OOB area size: %u bytes\n", ns->geom.oobsz); | 584 | printk("OOB area size: %u bytes\n", ns->geom.oobsz); |
| 579 | printk("sector size: %u KiB\n", ns->geom.secsz >> 10); | 585 | printk("sector size: %u KiB\n", ns->geom.secsz >> 10); |
| @@ -583,7 +589,7 @@ static int init_nandsim(struct mtd_info *mtd) | |||
| 583 | printk("bits in sector size: %u\n", ns->geom.secshift); | 589 | printk("bits in sector size: %u\n", ns->geom.secshift); |
| 584 | printk("bits in page size: %u\n", ns->geom.pgshift); | 590 | printk("bits in page size: %u\n", ns->geom.pgshift); |
| 585 | printk("bits in OOB size: %u\n", ns->geom.oobshift); | 591 | printk("bits in OOB size: %u\n", ns->geom.oobshift); |
| 586 | printk("flash size with OOB: %u KiB\n", ns->geom.totszoob >> 10); | 592 | printk("flash size with OOB: %llu KiB\n", ns->geom.totszoob >> 10); |
| 587 | printk("page address bytes: %u\n", ns->geom.pgaddrbytes); | 593 | printk("page address bytes: %u\n", ns->geom.pgaddrbytes); |
| 588 | printk("sector address bytes: %u\n", ns->geom.secaddrbytes); | 594 | printk("sector address bytes: %u\n", ns->geom.secaddrbytes); |
| 589 | printk("options: %#x\n", ns->options); | 595 | printk("options: %#x\n", ns->options); |
| @@ -825,7 +831,7 @@ static int setup_wear_reporting(struct mtd_info *mtd) | |||
| 825 | 831 | ||
| 826 | if (!rptwear) | 832 | if (!rptwear) |
| 827 | return 0; | 833 | return 0; |
| 828 | wear_eb_count = mtd->size / mtd->erasesize; | 834 | wear_eb_count = divide(mtd->size, mtd->erasesize); |
| 829 | mem = wear_eb_count * sizeof(unsigned long); | 835 | mem = wear_eb_count * sizeof(unsigned long); |
| 830 | if (mem / sizeof(unsigned long) != wear_eb_count) { | 836 | if (mem / sizeof(unsigned long) != wear_eb_count) { |
| 831 | NS_ERR("Too many erase blocks for wear reporting\n"); | 837 | NS_ERR("Too many erase blocks for wear reporting\n"); |
| @@ -2013,7 +2019,7 @@ static int __init ns_init_module(void) | |||
| 2013 | } | 2019 | } |
| 2014 | 2020 | ||
| 2015 | if (overridesize) { | 2021 | if (overridesize) { |
| 2016 | u_int32_t new_size = nsmtd->erasesize << overridesize; | 2022 | u_int64_t new_size = (u_int64_t)nsmtd->erasesize << overridesize; |
| 2017 | if (new_size >> overridesize != nsmtd->erasesize) { | 2023 | if (new_size >> overridesize != nsmtd->erasesize) { |
| 2018 | NS_ERR("overridesize is too big\n"); | 2024 | NS_ERR("overridesize is too big\n"); |
| 2019 | goto err_exit; | 2025 | goto err_exit; |
| @@ -2021,7 +2027,8 @@ static int __init ns_init_module(void) | |||
| 2021 | /* N.B. This relies on nand_scan not doing anything with the size before we change it */ | 2027 | /* N.B. This relies on nand_scan not doing anything with the size before we change it */ |
| 2022 | nsmtd->size = new_size; | 2028 | nsmtd->size = new_size; |
| 2023 | chip->chipsize = new_size; | 2029 | chip->chipsize = new_size; |
| 2024 | chip->chip_shift = ffs(new_size) - 1; | 2030 | chip->chip_shift = ffs(nsmtd->erasesize) + overridesize - 1; |
| 2031 | chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; | ||
| 2025 | } | 2032 | } |
| 2026 | 2033 | ||
| 2027 | if ((retval = setup_wear_reporting(nsmtd)) != 0) | 2034 | if ((retval = setup_wear_reporting(nsmtd)) != 0) |
diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c index 082073acf20f..cc8658431851 100644 --- a/drivers/mtd/nand/ppchameleonevb.c +++ b/drivers/mtd/nand/ppchameleonevb.c | |||
| @@ -6,8 +6,6 @@ | |||
| 6 | * Derived from drivers/mtd/nand/edb7312.c | 6 | * Derived from drivers/mtd/nand/edb7312.c |
| 7 | * | 7 | * |
| 8 | * | 8 | * |
| 9 | * $Id: ppchameleonevb.c,v 1.7 2005/11/07 11:14:31 gleixner Exp $ | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
| 12 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
| 13 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index 26f88215bc47..a033c4cd8e16 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c | |||
| @@ -6,8 +6,6 @@ | |||
| 6 | * Derived from drivers/mtd/nand/spia.c | 6 | * Derived from drivers/mtd/nand/spia.c |
| 7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) | 7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) |
| 8 | * | 8 | * |
| 9 | * $Id: rtc_from4.c,v 1.10 2005/11/07 11:14:31 gleixner Exp $ | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
| 12 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
| 13 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index b34a460ab679..556139ed1fdf 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c | |||
| @@ -1,26 +1,10 @@ | |||
| 1 | /* linux/drivers/mtd/nand/s3c2410.c | 1 | /* linux/drivers/mtd/nand/s3c2410.c |
| 2 | * | 2 | * |
| 3 | * Copyright (c) 2004,2005 Simtec Electronics | 3 | * Copyright © 2004-2008 Simtec Electronics |
| 4 | * http://www.simtec.co.uk/products/SWLINUX/ | 4 | * http://armlinux.simtec.co.uk/ |
| 5 | * Ben Dooks <ben@simtec.co.uk> | 5 | * Ben Dooks <ben@simtec.co.uk> |
| 6 | * | 6 | * |
| 7 | * Samsung S3C2410/S3C240 NAND driver | 7 | * Samsung S3C2410/S3C2440/S3C2412 NAND driver |
| 8 | * | ||
| 9 | * Changelog: | ||
| 10 | * 21-Sep-2004 BJD Initial version | ||
| 11 | * 23-Sep-2004 BJD Multiple device support | ||
| 12 | * 28-Sep-2004 BJD Fixed ECC placement for Hardware mode | ||
| 13 | * 12-Oct-2004 BJD Fixed errors in use of platform data | ||
| 14 | * 18-Feb-2005 BJD Fix sparse errors | ||
| 15 | * 14-Mar-2005 BJD Applied tglx's code reduction patch | ||
| 16 | * 02-May-2005 BJD Fixed s3c2440 support | ||
| 17 | * 02-May-2005 BJD Reduced hwcontrol decode | ||
| 18 | * 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug | ||
| 19 | * 08-Jul-2005 BJD Fix OOPS when no platform data supplied | ||
| 20 | * 20-Oct-2005 BJD Fix timing calculation bug | ||
| 21 | * 14-Jan-2006 BJD Allow clock to be stopped when idle | ||
| 22 | * | ||
| 23 | * $Id: s3c2410.c,v 1.23 2006/04/01 18:06:29 bjd Exp $ | ||
| 24 | * | 8 | * |
| 25 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
| 26 | * it under the terms of the GNU General Public License as published by | 10 | * it under the terms of the GNU General Public License as published by |
| @@ -52,6 +36,7 @@ | |||
| 52 | #include <linux/err.h> | 36 | #include <linux/err.h> |
| 53 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
| 54 | #include <linux/clk.h> | 38 | #include <linux/clk.h> |
| 39 | #include <linux/cpufreq.h> | ||
| 55 | 40 | ||
| 56 | #include <linux/mtd/mtd.h> | 41 | #include <linux/mtd/mtd.h> |
| 57 | #include <linux/mtd/nand.h> | 42 | #include <linux/mtd/nand.h> |
| @@ -120,8 +105,13 @@ struct s3c2410_nand_info { | |||
| 120 | int sel_bit; | 105 | int sel_bit; |
| 121 | int mtd_count; | 106 | int mtd_count; |
| 122 | unsigned long save_sel; | 107 | unsigned long save_sel; |
| 108 | unsigned long clk_rate; | ||
| 123 | 109 | ||
| 124 | enum s3c_cpu_type cpu_type; | 110 | enum s3c_cpu_type cpu_type; |
| 111 | |||
| 112 | #ifdef CONFIG_CPU_FREQ | ||
| 113 | struct notifier_block freq_transition; | ||
| 114 | #endif | ||
| 125 | }; | 115 | }; |
| 126 | 116 | ||
| 127 | /* conversion functions */ | 117 | /* conversion functions */ |
| @@ -179,17 +169,18 @@ static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max) | |||
| 179 | 169 | ||
| 180 | /* controller setup */ | 170 | /* controller setup */ |
| 181 | 171 | ||
| 182 | static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, | 172 | static int s3c2410_nand_setrate(struct s3c2410_nand_info *info) |
| 183 | struct platform_device *pdev) | ||
| 184 | { | 173 | { |
| 185 | struct s3c2410_platform_nand *plat = to_nand_plat(pdev); | 174 | struct s3c2410_platform_nand *plat = info->platform; |
| 186 | unsigned long clkrate = clk_get_rate(info->clk); | ||
| 187 | int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4; | 175 | int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4; |
| 188 | int tacls, twrph0, twrph1; | 176 | int tacls, twrph0, twrph1; |
| 189 | unsigned long cfg = 0; | 177 | unsigned long clkrate = clk_get_rate(info->clk); |
| 178 | unsigned long set, cfg, mask; | ||
| 179 | unsigned long flags; | ||
| 190 | 180 | ||
| 191 | /* calculate the timing information for the controller */ | 181 | /* calculate the timing information for the controller */ |
| 192 | 182 | ||
| 183 | info->clk_rate = clkrate; | ||
| 193 | clkrate /= 1000; /* turn clock into kHz for ease of use */ | 184 | clkrate /= 1000; /* turn clock into kHz for ease of use */ |
| 194 | 185 | ||
| 195 | if (plat != NULL) { | 186 | if (plat != NULL) { |
| @@ -211,28 +202,69 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, | |||
| 211 | dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", | 202 | dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", |
| 212 | tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate)); | 203 | tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate)); |
| 213 | 204 | ||
| 205 | switch (info->cpu_type) { | ||
| 206 | case TYPE_S3C2410: | ||
| 207 | mask = (S3C2410_NFCONF_TACLS(3) | | ||
| 208 | S3C2410_NFCONF_TWRPH0(7) | | ||
| 209 | S3C2410_NFCONF_TWRPH1(7)); | ||
| 210 | set = S3C2410_NFCONF_EN; | ||
| 211 | set |= S3C2410_NFCONF_TACLS(tacls - 1); | ||
| 212 | set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); | ||
| 213 | set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); | ||
| 214 | break; | ||
| 215 | |||
| 216 | case TYPE_S3C2440: | ||
| 217 | case TYPE_S3C2412: | ||
| 218 | mask = (S3C2410_NFCONF_TACLS(tacls_max - 1) | | ||
| 219 | S3C2410_NFCONF_TWRPH0(7) | | ||
| 220 | S3C2410_NFCONF_TWRPH1(7)); | ||
| 221 | |||
| 222 | set = S3C2440_NFCONF_TACLS(tacls - 1); | ||
| 223 | set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); | ||
| 224 | set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); | ||
| 225 | break; | ||
| 226 | |||
| 227 | default: | ||
| 228 | /* keep compiler happy */ | ||
| 229 | mask = 0; | ||
| 230 | set = 0; | ||
| 231 | BUG(); | ||
| 232 | } | ||
| 233 | |||
| 234 | dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); | ||
| 235 | |||
| 236 | local_irq_save(flags); | ||
| 237 | |||
| 238 | cfg = readl(info->regs + S3C2410_NFCONF); | ||
| 239 | cfg &= ~mask; | ||
| 240 | cfg |= set; | ||
| 241 | writel(cfg, info->regs + S3C2410_NFCONF); | ||
| 242 | |||
| 243 | local_irq_restore(flags); | ||
| 244 | |||
| 245 | return 0; | ||
| 246 | } | ||
| 247 | |||
| 248 | static int s3c2410_nand_inithw(struct s3c2410_nand_info *info) | ||
| 249 | { | ||
| 250 | int ret; | ||
| 251 | |||
| 252 | ret = s3c2410_nand_setrate(info); | ||
| 253 | if (ret < 0) | ||
| 254 | return ret; | ||
| 255 | |||
| 214 | switch (info->cpu_type) { | 256 | switch (info->cpu_type) { |
| 215 | case TYPE_S3C2410: | 257 | case TYPE_S3C2410: |
| 216 | cfg = S3C2410_NFCONF_EN; | 258 | default: |
| 217 | cfg |= S3C2410_NFCONF_TACLS(tacls - 1); | ||
| 218 | cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); | ||
| 219 | cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); | ||
| 220 | break; | 259 | break; |
| 221 | 260 | ||
| 222 | case TYPE_S3C2440: | 261 | case TYPE_S3C2440: |
| 223 | case TYPE_S3C2412: | 262 | case TYPE_S3C2412: |
| 224 | cfg = S3C2440_NFCONF_TACLS(tacls - 1); | ||
| 225 | cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); | ||
| 226 | cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); | ||
| 227 | |||
| 228 | /* enable the controller and de-assert nFCE */ | 263 | /* enable the controller and de-assert nFCE */ |
| 229 | 264 | ||
| 230 | writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT); | 265 | writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT); |
| 231 | } | 266 | } |
| 232 | 267 | ||
| 233 | dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); | ||
| 234 | |||
| 235 | writel(cfg, info->regs + S3C2410_NFCONF); | ||
| 236 | return 0; | 268 | return 0; |
| 237 | } | 269 | } |
| 238 | 270 | ||
| @@ -513,6 +545,52 @@ static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int | |||
| 513 | writesl(info->regs + S3C2440_NFDATA, buf, len / 4); | 545 | writesl(info->regs + S3C2440_NFDATA, buf, len / 4); |
| 514 | } | 546 | } |
| 515 | 547 | ||
| 548 | /* cpufreq driver support */ | ||
| 549 | |||
| 550 | #ifdef CONFIG_CPU_FREQ | ||
| 551 | |||
| 552 | static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb, | ||
| 553 | unsigned long val, void *data) | ||
| 554 | { | ||
| 555 | struct s3c2410_nand_info *info; | ||
| 556 | unsigned long newclk; | ||
| 557 | |||
| 558 | info = container_of(nb, struct s3c2410_nand_info, freq_transition); | ||
| 559 | newclk = clk_get_rate(info->clk); | ||
| 560 | |||
| 561 | if ((val == CPUFREQ_POSTCHANGE && newclk < info->clk_rate) || | ||
| 562 | (val == CPUFREQ_PRECHANGE && newclk > info->clk_rate)) { | ||
| 563 | s3c2410_nand_setrate(info); | ||
| 564 | } | ||
| 565 | |||
| 566 | return 0; | ||
| 567 | } | ||
| 568 | |||
| 569 | static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info) | ||
| 570 | { | ||
| 571 | info->freq_transition.notifier_call = s3c2410_nand_cpufreq_transition; | ||
| 572 | |||
| 573 | return cpufreq_register_notifier(&info->freq_transition, | ||
| 574 | CPUFREQ_TRANSITION_NOTIFIER); | ||
| 575 | } | ||
| 576 | |||
| 577 | static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info) | ||
| 578 | { | ||
| 579 | cpufreq_unregister_notifier(&info->freq_transition, | ||
| 580 | CPUFREQ_TRANSITION_NOTIFIER); | ||
| 581 | } | ||
| 582 | |||
| 583 | #else | ||
| 584 | static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info) | ||
| 585 | { | ||
| 586 | return 0; | ||
| 587 | } | ||
| 588 | |||
| 589 | static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info) | ||
| 590 | { | ||
| 591 | } | ||
| 592 | #endif | ||
| 593 | |||
| 516 | /* device management functions */ | 594 | /* device management functions */ |
| 517 | 595 | ||
| 518 | static int s3c2410_nand_remove(struct platform_device *pdev) | 596 | static int s3c2410_nand_remove(struct platform_device *pdev) |
| @@ -524,9 +602,10 @@ static int s3c2410_nand_remove(struct platform_device *pdev) | |||
| 524 | if (info == NULL) | 602 | if (info == NULL) |
| 525 | return 0; | 603 | return 0; |
| 526 | 604 | ||
| 527 | /* first thing we need to do is release all our mtds | 605 | s3c2410_nand_cpufreq_deregister(info); |
| 528 | * and their partitions, then go through freeing the | 606 | |
| 529 | * resources used | 607 | /* Release all our mtds and their partitions, then go through |
| 608 | * freeing the resources used | ||
| 530 | */ | 609 | */ |
| 531 | 610 | ||
| 532 | if (info->mtds != NULL) { | 611 | if (info->mtds != NULL) { |
| @@ -691,7 +770,8 @@ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info, | |||
| 691 | { | 770 | { |
| 692 | struct nand_chip *chip = &nmtd->chip; | 771 | struct nand_chip *chip = &nmtd->chip; |
| 693 | 772 | ||
| 694 | printk("%s: chip %p: %d\n", __func__, chip, chip->page_shift); | 773 | dev_dbg(info->device, "chip %p => page shift %d\n", |
| 774 | chip, chip->page_shift); | ||
| 695 | 775 | ||
| 696 | if (hardware_ecc) { | 776 | if (hardware_ecc) { |
| 697 | /* change the behaviour depending on wether we are using | 777 | /* change the behaviour depending on wether we are using |
| @@ -784,7 +864,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, | |||
| 784 | 864 | ||
| 785 | /* initialise the hardware */ | 865 | /* initialise the hardware */ |
| 786 | 866 | ||
| 787 | err = s3c2410_nand_inithw(info, pdev); | 867 | err = s3c2410_nand_inithw(info); |
| 788 | if (err != 0) | 868 | if (err != 0) |
| 789 | goto exit_error; | 869 | goto exit_error; |
| 790 | 870 | ||
| @@ -827,6 +907,12 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, | |||
| 827 | sets++; | 907 | sets++; |
| 828 | } | 908 | } |
| 829 | 909 | ||
| 910 | err = s3c2410_nand_cpufreq_register(info); | ||
| 911 | if (err < 0) { | ||
| 912 | dev_err(&pdev->dev, "failed to init cpufreq support\n"); | ||
| 913 | goto exit_error; | ||
| 914 | } | ||
| 915 | |||
| 830 | if (allow_clk_stop(info)) { | 916 | if (allow_clk_stop(info)) { |
| 831 | dev_info(&pdev->dev, "clock idle support enabled\n"); | 917 | dev_info(&pdev->dev, "clock idle support enabled\n"); |
| 832 | clk_disable(info->clk); | 918 | clk_disable(info->clk); |
| @@ -874,7 +960,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev) | |||
| 874 | 960 | ||
| 875 | if (info) { | 961 | if (info) { |
| 876 | clk_enable(info->clk); | 962 | clk_enable(info->clk); |
| 877 | s3c2410_nand_inithw(info, dev); | 963 | s3c2410_nand_inithw(info); |
| 878 | 964 | ||
| 879 | /* Restore the state of the nFCE line. */ | 965 | /* Restore the state of the nFCE line. */ |
| 880 | 966 | ||
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 033f8800b1e6..6dba2fb66ae5 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c | |||
| @@ -3,8 +3,6 @@ | |||
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2004 Richard Purdie | 4 | * Copyright (C) 2004 Richard Purdie |
| 5 | * | 5 | * |
| 6 | * $Id: sharpsl.c,v 1.7 2005/11/07 11:14:31 gleixner Exp $ | ||
| 7 | * | ||
| 8 | * Based on Sharp's NAND driver sharp_sl.c | 6 | * Based on Sharp's NAND driver sharp_sl.c |
| 9 | * | 7 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/mtd/nand/spia.c b/drivers/mtd/nand/spia.c index 1f6d429b1583..0cc6d0acb8fe 100644 --- a/drivers/mtd/nand/spia.c +++ b/drivers/mtd/nand/spia.c | |||
| @@ -8,8 +8,6 @@ | |||
| 8 | * to controllines (due to change in nand.c) | 8 | * to controllines (due to change in nand.c) |
| 9 | * page_cache added | 9 | * page_cache added |
| 10 | * | 10 | * |
| 11 | * $Id: spia.c,v 1.25 2005/11/07 11:14:31 gleixner Exp $ | ||
| 12 | * | ||
| 13 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 14 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
| 15 | * published by the Free Software Foundation. | 13 | * published by the Free Software Foundation. |
diff --git a/drivers/mtd/nand/toto.c b/drivers/mtd/nand/toto.c index f9e2d4a0ab8c..bbf492e6830d 100644 --- a/drivers/mtd/nand/toto.c +++ b/drivers/mtd/nand/toto.c | |||
| @@ -14,8 +14,6 @@ | |||
| 14 | * Overview: | 14 | * Overview: |
| 15 | * This is a device driver for the NAND flash device found on the | 15 | * This is a device driver for the NAND flash device found on the |
| 16 | * TI fido board. It supports 32MiB and 64MiB cards | 16 | * TI fido board. It supports 32MiB and 64MiB cards |
| 17 | * | ||
| 18 | * $Id: toto.c,v 1.5 2005/11/07 11:14:31 gleixner Exp $ | ||
| 19 | */ | 17 | */ |
| 20 | 18 | ||
| 21 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
diff --git a/drivers/mtd/nand/ts7250.c b/drivers/mtd/nand/ts7250.c index f40081069ab2..807a72752eeb 100644 --- a/drivers/mtd/nand/ts7250.c +++ b/drivers/mtd/nand/ts7250.c | |||
| @@ -9,8 +9,6 @@ | |||
| 9 | * Derived from drivers/mtd/nand/autcpu12.c | 9 | * Derived from drivers/mtd/nand/autcpu12.c |
| 10 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) | 10 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) |
| 11 | * | 11 | * |
| 12 | * $Id: ts7250.c,v 1.4 2004/12/30 22:02:07 joff Exp $ | ||
| 13 | * | ||
| 14 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
| 15 | * it under the terms of the GNU General Public License version 2 as | 13 | * it under the terms of the GNU General Public License version 2 as |
| 16 | * published by the Free Software Foundation. | 14 | * published by the Free Software Foundation. |
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index 0c9ce19ea27a..320b929abe79 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | /* Linux driver for NAND Flash Translation Layer */ | 1 | /* Linux driver for NAND Flash Translation Layer */ |
| 2 | /* (c) 1999 Machine Vision Holdings, Inc. */ | 2 | /* (c) 1999 Machine Vision Holdings, Inc. */ |
| 3 | /* Author: David Woodhouse <dwmw2@infradead.org> */ | 3 | /* Author: David Woodhouse <dwmw2@infradead.org> */ |
| 4 | /* $Id: nftlcore.c,v 1.98 2005/11/07 11:14:21 gleixner Exp $ */ | ||
| 5 | 4 | ||
| 6 | /* | 5 | /* |
| 7 | The contents of this file are distributed under the GNU General | 6 | The contents of this file are distributed under the GNU General |
| @@ -803,12 +802,8 @@ static struct mtd_blktrans_ops nftl_tr = { | |||
| 803 | .owner = THIS_MODULE, | 802 | .owner = THIS_MODULE, |
| 804 | }; | 803 | }; |
| 805 | 804 | ||
| 806 | extern char nftlmountrev[]; | ||
| 807 | |||
| 808 | static int __init init_nftl(void) | 805 | static int __init init_nftl(void) |
| 809 | { | 806 | { |
| 810 | printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.98 $, nftlmount.c %s\n", nftlmountrev); | ||
| 811 | |||
| 812 | return register_mtd_blktrans(&nftl_tr); | 807 | return register_mtd_blktrans(&nftl_tr); |
| 813 | } | 808 | } |
| 814 | 809 | ||
diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index 345e6eff89ce..ccc4f209fbb5 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c | |||
| @@ -4,8 +4,6 @@ | |||
| 4 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) | 4 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) |
| 5 | * Copyright (C) 2000 Netgem S.A. | 5 | * Copyright (C) 2000 Netgem S.A. |
| 6 | * | 6 | * |
| 7 | * $Id: nftlmount.c,v 1.41 2005/11/07 11:14:21 gleixner Exp $ | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
| 10 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
| 11 | * the Free Software Foundation; either version 2 of the License, or | 9 | * the Free Software Foundation; either version 2 of the License, or |
| @@ -31,8 +29,6 @@ | |||
| 31 | 29 | ||
| 32 | #define SECTORSIZE 512 | 30 | #define SECTORSIZE 512 |
| 33 | 31 | ||
| 34 | char nftlmountrev[]="$Revision: 1.41 $"; | ||
| 35 | |||
| 36 | /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the | 32 | /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the |
| 37 | * various device information of the NFTL partition and Bad Unit Table. Update | 33 | * various device information of the NFTL partition and Bad Unit Table. Update |
| 38 | * the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[] | 34 | * the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[] |
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 5d7965f7e9ce..926cf3a4135d 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
| @@ -325,28 +325,11 @@ static int onenand_wait(struct mtd_info *mtd, int state) | |||
| 325 | 325 | ||
| 326 | ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); | 326 | ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); |
| 327 | 327 | ||
| 328 | if (ctrl & ONENAND_CTRL_ERROR) { | 328 | /* |
| 329 | printk(KERN_ERR "onenand_wait: controller error = 0x%04x\n", ctrl); | 329 | * In the Spec. it checks the controller status first |
| 330 | if (ctrl & ONENAND_CTRL_LOCK) | 330 | * However if you get the correct information in case of |
| 331 | printk(KERN_ERR "onenand_wait: it's locked error.\n"); | 331 | * power off recovery (POR) test, it should read ECC status first |
| 332 | if (state == FL_READING) { | 332 | */ |
| 333 | /* | ||
| 334 | * A power loss while writing can result in a page | ||
| 335 | * becoming unreadable. When the device is mounted | ||
| 336 | * again, reading that page gives controller errors. | ||
| 337 | * Upper level software like JFFS2 treat -EIO as fatal, | ||
| 338 | * refusing to mount at all. That means it is necessary | ||
| 339 | * to treat the error as an ECC error to allow recovery. | ||
| 340 | * Note that typically in this case, the eraseblock can | ||
| 341 | * still be erased and rewritten i.e. it has not become | ||
| 342 | * a bad block. | ||
| 343 | */ | ||
| 344 | mtd->ecc_stats.failed++; | ||
| 345 | return -EBADMSG; | ||
| 346 | } | ||
| 347 | return -EIO; | ||
| 348 | } | ||
| 349 | |||
| 350 | if (interrupt & ONENAND_INT_READ) { | 333 | if (interrupt & ONENAND_INT_READ) { |
| 351 | int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); | 334 | int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); |
| 352 | if (ecc) { | 335 | if (ecc) { |
| @@ -364,6 +347,15 @@ static int onenand_wait(struct mtd_info *mtd, int state) | |||
| 364 | return -EIO; | 347 | return -EIO; |
| 365 | } | 348 | } |
| 366 | 349 | ||
| 350 | /* If there's controller error, it's a real error */ | ||
| 351 | if (ctrl & ONENAND_CTRL_ERROR) { | ||
| 352 | printk(KERN_ERR "onenand_wait: controller error = 0x%04x\n", | ||
| 353 | ctrl); | ||
| 354 | if (ctrl & ONENAND_CTRL_LOCK) | ||
| 355 | printk(KERN_ERR "onenand_wait: it's locked error.\n"); | ||
| 356 | return -EIO; | ||
| 357 | } | ||
| 358 | |||
| 367 | return 0; | 359 | return 0; |
| 368 | } | 360 | } |
| 369 | 361 | ||
| @@ -1135,22 +1127,26 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state) | |||
| 1135 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); | 1127 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); |
| 1136 | ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); | 1128 | ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); |
| 1137 | 1129 | ||
| 1138 | /* Initial bad block case: 0x2400 or 0x0400 */ | ||
| 1139 | if (ctrl & ONENAND_CTRL_ERROR) { | ||
| 1140 | printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl); | ||
| 1141 | return ONENAND_BBT_READ_ERROR; | ||
| 1142 | } | ||
| 1143 | |||
| 1144 | if (interrupt & ONENAND_INT_READ) { | 1130 | if (interrupt & ONENAND_INT_READ) { |
| 1145 | int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); | 1131 | int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); |
| 1146 | if (ecc & ONENAND_ECC_2BIT_ALL) | 1132 | if (ecc & ONENAND_ECC_2BIT_ALL) { |
| 1133 | printk(KERN_INFO "onenand_bbt_wait: ecc error = 0x%04x" | ||
| 1134 | ", controller error 0x%04x\n", ecc, ctrl); | ||
| 1147 | return ONENAND_BBT_READ_ERROR; | 1135 | return ONENAND_BBT_READ_ERROR; |
| 1136 | } | ||
| 1148 | } else { | 1137 | } else { |
| 1149 | printk(KERN_ERR "onenand_bbt_wait: read timeout!" | 1138 | printk(KERN_ERR "onenand_bbt_wait: read timeout!" |
| 1150 | "ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt); | 1139 | "ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt); |
| 1151 | return ONENAND_BBT_READ_FATAL_ERROR; | 1140 | return ONENAND_BBT_READ_FATAL_ERROR; |
| 1152 | } | 1141 | } |
| 1153 | 1142 | ||
| 1143 | /* Initial bad block case: 0x2400 or 0x0400 */ | ||
| 1144 | if (ctrl & ONENAND_CTRL_ERROR) { | ||
| 1145 | printk(KERN_DEBUG "onenand_bbt_wait: " | ||
| 1146 | "controller error = 0x%04x\n", ctrl); | ||
| 1147 | return ONENAND_BBT_READ_ERROR; | ||
| 1148 | } | ||
| 1149 | |||
| 1154 | return 0; | 1150 | return 0; |
| 1155 | } | 1151 | } |
| 1156 | 1152 | ||
diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c index c5030f94f04e..2d600a1bf2aa 100644 --- a/drivers/mtd/redboot.c +++ b/drivers/mtd/redboot.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: redboot.c,v 1.21 2006/03/30 18:34:37 bjd Exp $ | ||
| 3 | * | ||
| 4 | * Parse RedBoot-style Flash Image System (FIS) tables and | 2 | * Parse RedBoot-style Flash Image System (FIS) tables and |
| 5 | * produce a Linux partition array to match. | 3 | * produce a Linux partition array to match. |
| 6 | */ | 4 | */ |
diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c index c84e45465499..e538c0a72abb 100644 --- a/drivers/mtd/rfd_ftl.c +++ b/drivers/mtd/rfd_ftl.c | |||
| @@ -3,8 +3,6 @@ | |||
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2005 Sean Young <sean@mess.org> | 4 | * Copyright (C) 2005 Sean Young <sean@mess.org> |
| 5 | * | 5 | * |
| 6 | * $Id: rfd_ftl.c,v 1.8 2006/01/15 12:51:44 sean Exp $ | ||
| 7 | * | ||
| 8 | * This type of flash translation layer (FTL) is used by the Embedded BIOS | 6 | * This type of flash translation layer (FTL) is used by the Embedded BIOS |
| 9 | * by General Software. It is known as the Resident Flash Disk (RFD), see: | 7 | * by General Software. It is known as the Resident Flash Disk (RFD), see: |
| 10 | * | 8 | * |
diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index 7a14980f3472..18d3eeb7eab2 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c | |||
| @@ -482,7 +482,7 @@ static int ep93xx_alloc_buffers(struct ep93xx_priv *ep) | |||
| 482 | goto err; | 482 | goto err; |
| 483 | 483 | ||
| 484 | d = dma_map_single(NULL, page, PAGE_SIZE, DMA_FROM_DEVICE); | 484 | d = dma_map_single(NULL, page, PAGE_SIZE, DMA_FROM_DEVICE); |
| 485 | if (dma_mapping_error(d)) { | 485 | if (dma_mapping_error(NULL, d)) { |
| 486 | free_page((unsigned long)page); | 486 | free_page((unsigned long)page); |
| 487 | goto err; | 487 | goto err; |
| 488 | } | 488 | } |
| @@ -505,7 +505,7 @@ static int ep93xx_alloc_buffers(struct ep93xx_priv *ep) | |||
| 505 | goto err; | 505 | goto err; |
| 506 | 506 | ||
| 507 | d = dma_map_single(NULL, page, PAGE_SIZE, DMA_TO_DEVICE); | 507 | d = dma_map_single(NULL, page, PAGE_SIZE, DMA_TO_DEVICE); |
| 508 | if (dma_mapping_error(d)) { | 508 | if (dma_mapping_error(NULL, d)) { |
| 509 | free_page((unsigned long)page); | 509 | free_page((unsigned long)page); |
| 510 | goto err; | 510 | goto err; |
| 511 | } | 511 | } |
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 0263bef9cc6d..af251a5df844 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c | |||
| @@ -814,7 +814,7 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp, | |||
| 814 | } | 814 | } |
| 815 | 815 | ||
| 816 | /* release skb */ | 816 | /* release skb */ |
| 817 | BUG_TRAP(skb); | 817 | WARN_ON(!skb); |
| 818 | dev_kfree_skb(skb); | 818 | dev_kfree_skb(skb); |
| 819 | tx_buf->first_bd = 0; | 819 | tx_buf->first_bd = 0; |
| 820 | tx_buf->skb = NULL; | 820 | tx_buf->skb = NULL; |
| @@ -837,9 +837,9 @@ static inline u16 bnx2x_tx_avail(struct bnx2x_fastpath *fp) | |||
| 837 | used = SUB_S16(prod, cons) + (s16)NUM_TX_RINGS; | 837 | used = SUB_S16(prod, cons) + (s16)NUM_TX_RINGS; |
| 838 | 838 | ||
| 839 | #ifdef BNX2X_STOP_ON_ERROR | 839 | #ifdef BNX2X_STOP_ON_ERROR |
| 840 | BUG_TRAP(used >= 0); | 840 | WARN_ON(used < 0); |
| 841 | BUG_TRAP(used <= fp->bp->tx_ring_size); | 841 | WARN_ON(used > fp->bp->tx_ring_size); |
| 842 | BUG_TRAP((fp->bp->tx_ring_size - used) <= MAX_TX_AVAIL); | 842 | WARN_ON((fp->bp->tx_ring_size - used) > MAX_TX_AVAIL); |
| 843 | #endif | 843 | #endif |
| 844 | 844 | ||
| 845 | return (s16)(fp->bp->tx_ring_size) - used; | 845 | return (s16)(fp->bp->tx_ring_size) - used; |
| @@ -1020,7 +1020,7 @@ static inline int bnx2x_alloc_rx_sge(struct bnx2x *bp, | |||
| 1020 | 1020 | ||
| 1021 | mapping = pci_map_page(bp->pdev, page, 0, BCM_PAGE_SIZE*PAGES_PER_SGE, | 1021 | mapping = pci_map_page(bp->pdev, page, 0, BCM_PAGE_SIZE*PAGES_PER_SGE, |
| 1022 | PCI_DMA_FROMDEVICE); | 1022 | PCI_DMA_FROMDEVICE); |
| 1023 | if (unlikely(dma_mapping_error(mapping))) { | 1023 | if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) { |
| 1024 | __free_pages(page, PAGES_PER_SGE_SHIFT); | 1024 | __free_pages(page, PAGES_PER_SGE_SHIFT); |
| 1025 | return -ENOMEM; | 1025 | return -ENOMEM; |
| 1026 | } | 1026 | } |
| @@ -1048,7 +1048,7 @@ static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp, | |||
| 1048 | 1048 | ||
| 1049 | mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size, | 1049 | mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size, |
| 1050 | PCI_DMA_FROMDEVICE); | 1050 | PCI_DMA_FROMDEVICE); |
| 1051 | if (unlikely(dma_mapping_error(mapping))) { | 1051 | if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) { |
| 1052 | dev_kfree_skb(skb); | 1052 | dev_kfree_skb(skb); |
| 1053 | return -ENOMEM; | 1053 | return -ENOMEM; |
| 1054 | } | 1054 | } |
| @@ -4374,7 +4374,7 @@ static void bnx2x_init_rx_rings(struct bnx2x *bp) | |||
| 4374 | } | 4374 | } |
| 4375 | ring_prod = NEXT_RX_IDX(ring_prod); | 4375 | ring_prod = NEXT_RX_IDX(ring_prod); |
| 4376 | cqe_ring_prod = NEXT_RCQ_IDX(cqe_ring_prod); | 4376 | cqe_ring_prod = NEXT_RCQ_IDX(cqe_ring_prod); |
| 4377 | BUG_TRAP(ring_prod > i); | 4377 | WARN_ON(ring_prod <= i); |
| 4378 | } | 4378 | } |
| 4379 | 4379 | ||
| 4380 | fp->rx_bd_prod = ring_prod; | 4380 | fp->rx_bd_prod = ring_prod; |
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 83768df27806..f1936d51b458 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c | |||
| @@ -576,6 +576,18 @@ static void cas_spare_recover(struct cas *cp, const gfp_t flags) | |||
| 576 | list_for_each_safe(elem, tmp, &list) { | 576 | list_for_each_safe(elem, tmp, &list) { |
| 577 | cas_page_t *page = list_entry(elem, cas_page_t, list); | 577 | cas_page_t *page = list_entry(elem, cas_page_t, list); |
| 578 | 578 | ||
| 579 | /* | ||
| 580 | * With the lockless pagecache, cassini buffering scheme gets | ||
| 581 | * slightly less accurate: we might find that a page has an | ||
| 582 | * elevated reference count here, due to a speculative ref, | ||
| 583 | * and skip it as in-use. Ideally we would be able to reclaim | ||
| 584 | * it. However this would be such a rare case, it doesn't | ||
| 585 | * matter too much as we should pick it up the next time round. | ||
| 586 | * | ||
| 587 | * Importantly, if we find that the page has a refcount of 1 | ||
| 588 | * here (our refcount), then we know it is definitely not inuse | ||
| 589 | * so we can reuse it. | ||
| 590 | */ | ||
| 579 | if (page_count(page->buffer) > 1) | 591 | if (page_count(page->buffer) > 1) |
| 580 | continue; | 592 | continue; |
| 581 | 593 | ||
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index a96331c875e6..1b0861d73ab7 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c | |||
| @@ -386,7 +386,7 @@ static inline int add_one_rx_buf(void *va, unsigned int len, | |||
| 386 | dma_addr_t mapping; | 386 | dma_addr_t mapping; |
| 387 | 387 | ||
| 388 | mapping = pci_map_single(pdev, va, len, PCI_DMA_FROMDEVICE); | 388 | mapping = pci_map_single(pdev, va, len, PCI_DMA_FROMDEVICE); |
| 389 | if (unlikely(pci_dma_mapping_error(mapping))) | 389 | if (unlikely(pci_dma_mapping_error(pdev, mapping))) |
| 390 | return -ENOMEM; | 390 | return -ENOMEM; |
| 391 | 391 | ||
| 392 | pci_unmap_addr_set(sd, dma_addr, mapping); | 392 | pci_unmap_addr_set(sd, dma_addr, mapping); |
diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 1037b1332312..19d32a227be1 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c | |||
| @@ -1790,7 +1790,7 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) | |||
| 1790 | rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data, | 1790 | rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data, |
| 1791 | RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL); | 1791 | RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL); |
| 1792 | 1792 | ||
| 1793 | if (pci_dma_mapping_error(rx->dma_addr)) { | 1793 | if (pci_dma_mapping_error(nic->pdev, rx->dma_addr)) { |
| 1794 | dev_kfree_skb_any(rx->skb); | 1794 | dev_kfree_skb_any(rx->skb); |
| 1795 | rx->skb = NULL; | 1795 | rx->skb = NULL; |
| 1796 | rx->dma_addr = 0; | 1796 | rx->dma_addr = 0; |
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index a14561f40db0..9350564065e7 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c | |||
| @@ -1090,7 +1090,7 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter) | |||
| 1090 | tx_ring->buffer_info[i].dma = | 1090 | tx_ring->buffer_info[i].dma = |
| 1091 | pci_map_single(pdev, skb->data, skb->len, | 1091 | pci_map_single(pdev, skb->data, skb->len, |
| 1092 | PCI_DMA_TODEVICE); | 1092 | PCI_DMA_TODEVICE); |
| 1093 | if (pci_dma_mapping_error(tx_ring->buffer_info[i].dma)) { | 1093 | if (pci_dma_mapping_error(pdev, tx_ring->buffer_info[i].dma)) { |
| 1094 | ret_val = 4; | 1094 | ret_val = 4; |
| 1095 | goto err_nomem; | 1095 | goto err_nomem; |
| 1096 | } | 1096 | } |
| @@ -1153,7 +1153,7 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter) | |||
| 1153 | rx_ring->buffer_info[i].dma = | 1153 | rx_ring->buffer_info[i].dma = |
| 1154 | pci_map_single(pdev, skb->data, 2048, | 1154 | pci_map_single(pdev, skb->data, 2048, |
| 1155 | PCI_DMA_FROMDEVICE); | 1155 | PCI_DMA_FROMDEVICE); |
| 1156 | if (pci_dma_mapping_error(rx_ring->buffer_info[i].dma)) { | 1156 | if (pci_dma_mapping_error(pdev, rx_ring->buffer_info[i].dma)) { |
| 1157 | ret_val = 8; | 1157 | ret_val = 8; |
| 1158 | goto err_nomem; | 1158 | goto err_nomem; |
| 1159 | } | 1159 | } |
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 9c0f56b3c518..d13677899767 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c | |||
| @@ -195,7 +195,7 @@ map_skb: | |||
| 195 | buffer_info->dma = pci_map_single(pdev, skb->data, | 195 | buffer_info->dma = pci_map_single(pdev, skb->data, |
| 196 | adapter->rx_buffer_len, | 196 | adapter->rx_buffer_len, |
| 197 | PCI_DMA_FROMDEVICE); | 197 | PCI_DMA_FROMDEVICE); |
| 198 | if (pci_dma_mapping_error(buffer_info->dma)) { | 198 | if (pci_dma_mapping_error(pdev, buffer_info->dma)) { |
| 199 | dev_err(&pdev->dev, "RX DMA map failed\n"); | 199 | dev_err(&pdev->dev, "RX DMA map failed\n"); |
| 200 | adapter->rx_dma_failed++; | 200 | adapter->rx_dma_failed++; |
| 201 | break; | 201 | break; |
| @@ -265,7 +265,7 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, | |||
| 265 | ps_page->page, | 265 | ps_page->page, |
| 266 | 0, PAGE_SIZE, | 266 | 0, PAGE_SIZE, |
| 267 | PCI_DMA_FROMDEVICE); | 267 | PCI_DMA_FROMDEVICE); |
| 268 | if (pci_dma_mapping_error(ps_page->dma)) { | 268 | if (pci_dma_mapping_error(pdev, ps_page->dma)) { |
| 269 | dev_err(&adapter->pdev->dev, | 269 | dev_err(&adapter->pdev->dev, |
| 270 | "RX DMA page map failed\n"); | 270 | "RX DMA page map failed\n"); |
| 271 | adapter->rx_dma_failed++; | 271 | adapter->rx_dma_failed++; |
| @@ -300,7 +300,7 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, | |||
| 300 | buffer_info->dma = pci_map_single(pdev, skb->data, | 300 | buffer_info->dma = pci_map_single(pdev, skb->data, |
| 301 | adapter->rx_ps_bsize0, | 301 | adapter->rx_ps_bsize0, |
| 302 | PCI_DMA_FROMDEVICE); | 302 | PCI_DMA_FROMDEVICE); |
| 303 | if (pci_dma_mapping_error(buffer_info->dma)) { | 303 | if (pci_dma_mapping_error(pdev, buffer_info->dma)) { |
| 304 | dev_err(&pdev->dev, "RX DMA map failed\n"); | 304 | dev_err(&pdev->dev, "RX DMA map failed\n"); |
| 305 | adapter->rx_dma_failed++; | 305 | adapter->rx_dma_failed++; |
| 306 | /* cleanup skb */ | 306 | /* cleanup skb */ |
| @@ -3344,7 +3344,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter, | |||
| 3344 | skb->data + offset, | 3344 | skb->data + offset, |
| 3345 | size, | 3345 | size, |
| 3346 | PCI_DMA_TODEVICE); | 3346 | PCI_DMA_TODEVICE); |
| 3347 | if (pci_dma_mapping_error(buffer_info->dma)) { | 3347 | if (pci_dma_mapping_error(adapter->pdev, buffer_info->dma)) { |
| 3348 | dev_err(&adapter->pdev->dev, "TX DMA map failed\n"); | 3348 | dev_err(&adapter->pdev->dev, "TX DMA map failed\n"); |
| 3349 | adapter->tx_dma_failed++; | 3349 | adapter->tx_dma_failed++; |
| 3350 | return -1; | 3350 | return -1; |
| @@ -3382,7 +3382,8 @@ static int e1000_tx_map(struct e1000_adapter *adapter, | |||
| 3382 | offset, | 3382 | offset, |
| 3383 | size, | 3383 | size, |
| 3384 | PCI_DMA_TODEVICE); | 3384 | PCI_DMA_TODEVICE); |
| 3385 | if (pci_dma_mapping_error(buffer_info->dma)) { | 3385 | if (pci_dma_mapping_error(adapter->pdev, |
| 3386 | buffer_info->dma)) { | ||
| 3386 | dev_err(&adapter->pdev->dev, | 3387 | dev_err(&adapter->pdev->dev, |
| 3387 | "TX DMA page map failed\n"); | 3388 | "TX DMA page map failed\n"); |
| 3388 | adapter->tx_dma_failed++; | 3389 | adapter->tx_dma_failed++; |
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index e5a6e2e84540..91ec9fdc7184 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c | |||
| @@ -260,7 +260,7 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc | |||
| 260 | dma_addr = dma_map_single(&adapter->vdev->dev, skb->data, | 260 | dma_addr = dma_map_single(&adapter->vdev->dev, skb->data, |
| 261 | pool->buff_size, DMA_FROM_DEVICE); | 261 | pool->buff_size, DMA_FROM_DEVICE); |
| 262 | 262 | ||
| 263 | if (dma_mapping_error(dma_addr)) | 263 | if (dma_mapping_error((&adapter->vdev->dev, dma_addr)) |
| 264 | goto failure; | 264 | goto failure; |
| 265 | 265 | ||
| 266 | pool->free_map[free_index] = IBM_VETH_INVALID_MAP; | 266 | pool->free_map[free_index] = IBM_VETH_INVALID_MAP; |
| @@ -294,7 +294,7 @@ failure: | |||
| 294 | pool->consumer_index = pool->size - 1; | 294 | pool->consumer_index = pool->size - 1; |
| 295 | else | 295 | else |
| 296 | pool->consumer_index--; | 296 | pool->consumer_index--; |
| 297 | if (!dma_mapping_error(dma_addr)) | 297 | if (!dma_mapping_error((&adapter->vdev->dev, dma_addr)) |
| 298 | dma_unmap_single(&adapter->vdev->dev, | 298 | dma_unmap_single(&adapter->vdev->dev, |
| 299 | pool->dma_addr[index], pool->buff_size, | 299 | pool->dma_addr[index], pool->buff_size, |
| 300 | DMA_FROM_DEVICE); | 300 | DMA_FROM_DEVICE); |
| @@ -448,11 +448,11 @@ static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter) | |||
| 448 | static void ibmveth_cleanup(struct ibmveth_adapter *adapter) | 448 | static void ibmveth_cleanup(struct ibmveth_adapter *adapter) |
| 449 | { | 449 | { |
| 450 | int i; | 450 | int i; |
| 451 | struct device *dev = &adapter->vdev->dev; | ||
| 451 | 452 | ||
| 452 | if(adapter->buffer_list_addr != NULL) { | 453 | if(adapter->buffer_list_addr != NULL) { |
| 453 | if(!dma_mapping_error(adapter->buffer_list_dma)) { | 454 | if (!dma_mapping_error(dev, adapter->buffer_list_dma)) { |
| 454 | dma_unmap_single(&adapter->vdev->dev, | 455 | dma_unmap_single(dev, adapter->buffer_list_dma, 4096, |
| 455 | adapter->buffer_list_dma, 4096, | ||
| 456 | DMA_BIDIRECTIONAL); | 456 | DMA_BIDIRECTIONAL); |
| 457 | adapter->buffer_list_dma = DMA_ERROR_CODE; | 457 | adapter->buffer_list_dma = DMA_ERROR_CODE; |
| 458 | } | 458 | } |
| @@ -461,9 +461,8 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter) | |||
| 461 | } | 461 | } |
| 462 | 462 | ||
| 463 | if(adapter->filter_list_addr != NULL) { | 463 | if(adapter->filter_list_addr != NULL) { |
| 464 | if(!dma_mapping_error(adapter->filter_list_dma)) { | 464 | if (!dma_mapping_error(dev, adapter->filter_list_dma)) { |
| 465 | dma_unmap_single(&adapter->vdev->dev, | 465 | dma_unmap_single(dev, adapter->filter_list_dma, 4096, |
| 466 | adapter->filter_list_dma, 4096, | ||
| 467 | DMA_BIDIRECTIONAL); | 466 | DMA_BIDIRECTIONAL); |
| 468 | adapter->filter_list_dma = DMA_ERROR_CODE; | 467 | adapter->filter_list_dma = DMA_ERROR_CODE; |
| 469 | } | 468 | } |
| @@ -472,8 +471,8 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter) | |||
| 472 | } | 471 | } |
| 473 | 472 | ||
| 474 | if(adapter->rx_queue.queue_addr != NULL) { | 473 | if(adapter->rx_queue.queue_addr != NULL) { |
| 475 | if(!dma_mapping_error(adapter->rx_queue.queue_dma)) { | 474 | if (!dma_mapping_error(dev, adapter->rx_queue.queue_dma)) { |
| 476 | dma_unmap_single(&adapter->vdev->dev, | 475 | dma_unmap_single(dev, |
| 477 | adapter->rx_queue.queue_dma, | 476 | adapter->rx_queue.queue_dma, |
| 478 | adapter->rx_queue.queue_len, | 477 | adapter->rx_queue.queue_len, |
| 479 | DMA_BIDIRECTIONAL); | 478 | DMA_BIDIRECTIONAL); |
| @@ -535,6 +534,7 @@ static int ibmveth_open(struct net_device *netdev) | |||
| 535 | int rc; | 534 | int rc; |
| 536 | union ibmveth_buf_desc rxq_desc; | 535 | union ibmveth_buf_desc rxq_desc; |
| 537 | int i; | 536 | int i; |
| 537 | struct device *dev; | ||
| 538 | 538 | ||
| 539 | ibmveth_debug_printk("open starting\n"); | 539 | ibmveth_debug_printk("open starting\n"); |
| 540 | 540 | ||
| @@ -563,17 +563,19 @@ static int ibmveth_open(struct net_device *netdev) | |||
| 563 | return -ENOMEM; | 563 | return -ENOMEM; |
| 564 | } | 564 | } |
| 565 | 565 | ||
| 566 | adapter->buffer_list_dma = dma_map_single(&adapter->vdev->dev, | 566 | dev = &adapter->vdev->dev; |
| 567 | |||
| 568 | adapter->buffer_list_dma = dma_map_single(dev, | ||
| 567 | adapter->buffer_list_addr, 4096, DMA_BIDIRECTIONAL); | 569 | adapter->buffer_list_addr, 4096, DMA_BIDIRECTIONAL); |
| 568 | adapter->filter_list_dma = dma_map_single(&adapter->vdev->dev, | 570 | adapter->filter_list_dma = dma_map_single(dev, |
| 569 | adapter->filter_list_addr, 4096, DMA_BIDIRECTIONAL); | 571 | adapter->filter_list_addr, 4096, DMA_BIDIRECTIONAL); |
| 570 | adapter->rx_queue.queue_dma = dma_map_single(&adapter->vdev->dev, | 572 | adapter->rx_queue.queue_dma = dma_map_single(dev, |
| 571 | adapter->rx_queue.queue_addr, | 573 | adapter->rx_queue.queue_addr, |
| 572 | adapter->rx_queue.queue_len, DMA_BIDIRECTIONAL); | 574 | adapter->rx_queue.queue_len, DMA_BIDIRECTIONAL); |
| 573 | 575 | ||
| 574 | if((dma_mapping_error(adapter->buffer_list_dma) ) || | 576 | if ((dma_mapping_error(dev, adapter->buffer_list_dma)) || |
| 575 | (dma_mapping_error(adapter->filter_list_dma)) || | 577 | (dma_mapping_error(dev, adapter->filter_list_dma)) || |
| 576 | (dma_mapping_error(adapter->rx_queue.queue_dma))) { | 578 | (dma_mapping_error(dev, adapter->rx_queue.queue_dma))) { |
| 577 | ibmveth_error_printk("unable to map filter or buffer list pages\n"); | 579 | ibmveth_error_printk("unable to map filter or buffer list pages\n"); |
| 578 | ibmveth_cleanup(adapter); | 580 | ibmveth_cleanup(adapter); |
| 579 | napi_disable(&adapter->napi); | 581 | napi_disable(&adapter->napi); |
| @@ -645,7 +647,7 @@ static int ibmveth_open(struct net_device *netdev) | |||
| 645 | adapter->bounce_buffer_dma = | 647 | adapter->bounce_buffer_dma = |
| 646 | dma_map_single(&adapter->vdev->dev, adapter->bounce_buffer, | 648 | dma_map_single(&adapter->vdev->dev, adapter->bounce_buffer, |
| 647 | netdev->mtu + IBMVETH_BUFF_OH, DMA_BIDIRECTIONAL); | 649 | netdev->mtu + IBMVETH_BUFF_OH, DMA_BIDIRECTIONAL); |
| 648 | if (dma_mapping_error(adapter->bounce_buffer_dma)) { | 650 | if (dma_mapping_error(dev, adapter->bounce_buffer_dma)) { |
| 649 | ibmveth_error_printk("unable to map bounce buffer\n"); | 651 | ibmveth_error_printk("unable to map bounce buffer\n"); |
| 650 | ibmveth_cleanup(adapter); | 652 | ibmveth_cleanup(adapter); |
| 651 | napi_disable(&adapter->napi); | 653 | napi_disable(&adapter->napi); |
| @@ -922,7 +924,7 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) | |||
| 922 | buf[1] = 0; | 924 | buf[1] = 0; |
| 923 | } | 925 | } |
| 924 | 926 | ||
| 925 | if (dma_mapping_error(data_dma_addr)) { | 927 | if (dma_mapping_error((&adapter->vdev->dev, data_dma_addr)) { |
| 926 | if (!firmware_has_feature(FW_FEATURE_CMO)) | 928 | if (!firmware_has_feature(FW_FEATURE_CMO)) |
| 927 | ibmveth_error_printk("tx: unable to map xmit buffer\n"); | 929 | ibmveth_error_printk("tx: unable to map xmit buffer\n"); |
| 928 | skb_copy_from_linear_data(skb, adapter->bounce_buffer, | 930 | skb_copy_from_linear_data(skb, adapter->bounce_buffer, |
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index b8d0639c1cdf..c46864d626b2 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c | |||
| @@ -1128,7 +1128,7 @@ static int veth_transmit_to_one(struct sk_buff *skb, HvLpIndex rlp, | |||
| 1128 | msg->data.addr[0] = dma_map_single(port->dev, skb->data, | 1128 | msg->data.addr[0] = dma_map_single(port->dev, skb->data, |
| 1129 | skb->len, DMA_TO_DEVICE); | 1129 | skb->len, DMA_TO_DEVICE); |
| 1130 | 1130 | ||
| 1131 | if (dma_mapping_error(msg->data.addr[0])) | 1131 | if (dma_mapping_error(port->dev, msg->data.addr[0])) |
| 1132 | goto recycle_and_drop; | 1132 | goto recycle_and_drop; |
| 1133 | 1133 | ||
| 1134 | msg->dev = port->dev; | 1134 | msg->dev = port->dev; |
| @@ -1226,7 +1226,7 @@ static void veth_recycle_msg(struct veth_lpar_connection *cnx, | |||
| 1226 | dma_address = msg->data.addr[0]; | 1226 | dma_address = msg->data.addr[0]; |
| 1227 | dma_length = msg->data.len[0]; | 1227 | dma_length = msg->data.len[0]; |
| 1228 | 1228 | ||
| 1229 | if (!dma_mapping_error(dma_address)) | 1229 | if (!dma_mapping_error(msg->dev, dma_address)) |
| 1230 | dma_unmap_single(msg->dev, dma_address, dma_length, | 1230 | dma_unmap_single(msg->dev, dma_address, dma_length, |
| 1231 | DMA_TO_DEVICE); | 1231 | DMA_TO_DEVICE); |
| 1232 | 1232 | ||
diff --git a/drivers/net/mlx4/alloc.c b/drivers/net/mlx4/alloc.c index f9d6b4dca180..096bca54bcf7 100644 --- a/drivers/net/mlx4/alloc.c +++ b/drivers/net/mlx4/alloc.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. | 2 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. |
| 3 | * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. | ||
| 3 | * | 4 | * |
| 4 | * This software is available to you under a choice of one of two | 5 | * This software is available to you under a choice of one of two |
| 5 | * licenses. You may choose to be licensed under the terms of the GNU | 6 | * licenses. You may choose to be licensed under the terms of the GNU |
diff --git a/drivers/net/mlx4/catas.c b/drivers/net/mlx4/catas.c index aa9528779044..f094ee00c416 100644 --- a/drivers/net/mlx4/catas.c +++ b/drivers/net/mlx4/catas.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. | 2 | * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. |
| 3 | * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. | ||
| 3 | * | 4 | * |
| 4 | * This software is available to you under a choice of one of two | 5 | * This software is available to you under a choice of one of two |
| 5 | * licenses. You may choose to be licensed under the terms of the GNU | 6 | * licenses. You may choose to be licensed under the terms of the GNU |
diff --git a/drivers/net/mlx4/cmd.c b/drivers/net/mlx4/cmd.c index 04d5bc69a6f8..2845a0560b84 100644 --- a/drivers/net/mlx4/cmd.c +++ b/drivers/net/mlx4/cmd.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. | 2 | * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. |
| 3 | * Copyright (c) 2005 Mellanox Technologies. All rights reserved. | 3 | * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. |
| 4 | * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. | 4 | * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. |
| 5 | * | 5 | * |
| 6 | * This software is available to you under a choice of one of two | 6 | * This software is available to you under a choice of one of two |
diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c index 95e87a2f8896..9bb50e3f8974 100644 --- a/drivers/net/mlx4/cq.c +++ b/drivers/net/mlx4/cq.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. | 2 | * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. |
| 3 | * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. | 3 | * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. |
| 4 | * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. | 4 | * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. |
| 5 | * Copyright (c) 2005 Mellanox Technologies. All rights reserved. | 5 | * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. |
| 6 | * Copyright (c) 2004 Voltaire, Inc. All rights reserved. | 6 | * Copyright (c) 2004 Voltaire, Inc. All rights reserved. |
| 7 | * | 7 | * |
| 8 | * This software is available to you under a choice of one of two | 8 | * This software is available to you under a choice of one of two |
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index ea3a09aaa844..8a8b56135a58 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2005 Mellanox Technologies. All rights reserved. | 2 | * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. |
| 3 | * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. | 3 | * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. |
| 4 | * | 4 | * |
| 5 | * This software is available to you under a choice of one of two | 5 | * This software is available to you under a choice of one of two |
| @@ -526,7 +526,7 @@ int mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt) | |||
| 526 | return -ENOMEM; | 526 | return -ENOMEM; |
| 527 | priv->eq_table.icm_dma = pci_map_page(dev->pdev, priv->eq_table.icm_page, 0, | 527 | priv->eq_table.icm_dma = pci_map_page(dev->pdev, priv->eq_table.icm_page, 0, |
| 528 | PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); | 528 | PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); |
| 529 | if (pci_dma_mapping_error(priv->eq_table.icm_dma)) { | 529 | if (pci_dma_mapping_error(dev->pdev, priv->eq_table.icm_dma)) { |
| 530 | __free_page(priv->eq_table.icm_page); | 530 | __free_page(priv->eq_table.icm_page); |
| 531 | return -ENOMEM; | 531 | return -ENOMEM; |
| 532 | } | 532 | } |
diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c index 57278224ba1e..7e32955da982 100644 --- a/drivers/net/mlx4/fw.c +++ b/drivers/net/mlx4/fw.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. | 2 | * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. |
| 3 | * Copyright (c) 2005 Mellanox Technologies. All rights reserved. | 3 | * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. |
| 4 | * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. | 4 | * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. |
| 5 | * | 5 | * |
| 6 | * This software is available to you under a choice of one of two | 6 | * This software is available to you under a choice of one of two |
diff --git a/drivers/net/mlx4/fw.h b/drivers/net/mlx4/fw.h index fbf0e22be122..decbb5c2ad41 100644 --- a/drivers/net/mlx4/fw.h +++ b/drivers/net/mlx4/fw.h | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. | 2 | * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. |
| 3 | * Copyright (c) 2005 Mellanox Technologies. All rights reserved. | 3 | * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. |
| 4 | * Copyright (c) 2006, 2007 Cisco Systems. All rights reserved. | 4 | * Copyright (c) 2006, 2007 Cisco Systems. All rights reserved. |
| 5 | * | 5 | * |
| 6 | * This software is available to you under a choice of one of two | 6 | * This software is available to you under a choice of one of two |
diff --git a/drivers/net/mlx4/icm.c b/drivers/net/mlx4/icm.c index 2a5bef6388fe..baf4bf66062c 100644 --- a/drivers/net/mlx4/icm.c +++ b/drivers/net/mlx4/icm.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2005 Mellanox Technologies. All rights reserved. | 2 | * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. |
| 3 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. | 3 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. |
| 4 | * | 4 | * |
| 5 | * This software is available to you under a choice of one of two | 5 | * This software is available to you under a choice of one of two |
diff --git a/drivers/net/mlx4/icm.h b/drivers/net/mlx4/icm.h index 6c44edf35847..ab56a2f89b65 100644 --- a/drivers/net/mlx4/icm.h +++ b/drivers/net/mlx4/icm.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2005 Mellanox Technologies. All rights reserved. | 2 | * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. |
| 3 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. | 3 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. |
| 4 | * | 4 | * |
| 5 | * This software is available to you under a choice of one of two | 5 | * This software is available to you under a choice of one of two |
diff --git a/drivers/net/mlx4/intf.c b/drivers/net/mlx4/intf.c index 4a6c4d526f1b..0e7eb1038f9f 100644 --- a/drivers/net/mlx4/intf.c +++ b/drivers/net/mlx4/intf.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. | 2 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. |
| 3 | * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. | ||
| 3 | * | 4 | * |
| 4 | * This software is available to you under a choice of one of two | 5 | * This software is available to you under a choice of one of two |
| 5 | * licenses. You may choose to be licensed under the terms of the GNU | 6 | * licenses. You may choose to be licensed under the terms of the GNU |
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 8e1d24cda1b0..1252a919de2e 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. | 2 | * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. |
| 3 | * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. | 3 | * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. |
| 4 | * Copyright (c) 2005 Mellanox Technologies. All rights reserved. | 4 | * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. |
| 5 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. | 5 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. |
| 6 | * | 6 | * |
| 7 | * This software is available to you under a choice of one of two | 7 | * This software is available to you under a choice of one of two |
diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c index b4b57870ddfd..c83f88ce0736 100644 --- a/drivers/net/mlx4/mcg.c +++ b/drivers/net/mlx4/mcg.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. | 2 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. |
| 3 | * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. | ||
| 3 | * | 4 | * |
| 4 | * This software is available to you under a choice of one of two | 5 | * This software is available to you under a choice of one of two |
| 5 | * licenses. You may choose to be licensed under the terms of the GNU | 6 | * licenses. You may choose to be licensed under the terms of the GNU |
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index 78038499cff5..5337e3ac3e78 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. | 2 | * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. |
| 3 | * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. | 3 | * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. |
| 4 | * Copyright (c) 2005, 2006, 2007 Cisco Systems. All rights reserved. | 4 | * Copyright (c) 2005, 2006, 2007 Cisco Systems. All rights reserved. |
| 5 | * Copyright (c) 2005 Mellanox Technologies. All rights reserved. | 5 | * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. |
| 6 | * Copyright (c) 2004 Voltaire, Inc. All rights reserved. | 6 | * Copyright (c) 2004 Voltaire, Inc. All rights reserved. |
| 7 | * | 7 | * |
| 8 | * This software is available to you under a choice of one of two | 8 | * This software is available to you under a choice of one of two |
diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index a3c04c5f12c2..62071d9c4a55 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2004 Topspin Communications. All rights reserved. | 2 | * Copyright (c) 2004 Topspin Communications. All rights reserved. |
| 3 | * Copyright (c) 2005 Mellanox Technologies. All rights reserved. | 3 | * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. |
| 4 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. | 4 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. |
| 5 | * | 5 | * |
| 6 | * This software is available to you under a choice of one of two | 6 | * This software is available to you under a choice of one of two |
diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c index ee5484c44a18..c49a86044bf7 100644 --- a/drivers/net/mlx4/qp.c +++ b/drivers/net/mlx4/qp.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2004 Topspin Communications. All rights reserved. | 2 | * Copyright (c) 2004 Topspin Communications. All rights reserved. |
| 3 | * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. | 3 | * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. |
| 4 | * Copyright (c) 2005 Mellanox Technologies. All rights reserved. | 4 | * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. |
| 5 | * Copyright (c) 2004 Voltaire, Inc. All rights reserved. | 5 | * Copyright (c) 2004 Voltaire, Inc. All rights reserved. |
| 6 | * | 6 | * |
| 7 | * This software is available to you under a choice of one of two | 7 | * This software is available to you under a choice of one of two |
diff --git a/drivers/net/mlx4/reset.c b/drivers/net/mlx4/reset.c index e199715fabd0..3951b884c0fb 100644 --- a/drivers/net/mlx4/reset.c +++ b/drivers/net/mlx4/reset.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. | 2 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. |
| 3 | * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. | ||
| 3 | * | 4 | * |
| 4 | * This software is available to you under a choice of one of two | 5 | * This software is available to you under a choice of one of two |
| 5 | * licenses. You may choose to be licensed under the terms of the GNU | 6 | * licenses. You may choose to be licensed under the terms of the GNU |
diff --git a/drivers/net/mlx4/srq.c b/drivers/net/mlx4/srq.c index d23f46d692ef..533eb6db24b3 100644 --- a/drivers/net/mlx4/srq.c +++ b/drivers/net/mlx4/srq.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. | 2 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. |
| 3 | * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. | ||
| 3 | * | 4 | * |
| 4 | * This software is available to you under a choice of one of two | 5 | * This software is available to you under a choice of one of two |
| 5 | * licenses. You may choose to be licensed under the terms of the GNU | 6 | * licenses. You may choose to be licensed under the terms of the GNU |
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 993d87c9296f..edc0fd588985 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c | |||
| @@ -650,7 +650,7 @@ static void pasemi_mac_replenish_rx_ring(const struct net_device *dev, | |||
| 650 | mac->bufsz - LOCAL_SKB_ALIGN, | 650 | mac->bufsz - LOCAL_SKB_ALIGN, |
| 651 | PCI_DMA_FROMDEVICE); | 651 | PCI_DMA_FROMDEVICE); |
| 652 | 652 | ||
| 653 | if (unlikely(dma_mapping_error(dma))) { | 653 | if (unlikely(pci_dma_mapping_error(mac->dma_pdev, dma))) { |
| 654 | dev_kfree_skb_irq(info->skb); | 654 | dev_kfree_skb_irq(info->skb); |
| 655 | break; | 655 | break; |
| 656 | } | 656 | } |
| @@ -1519,7 +1519,7 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) | |||
| 1519 | map[0] = pci_map_single(mac->dma_pdev, skb->data, skb_headlen(skb), | 1519 | map[0] = pci_map_single(mac->dma_pdev, skb->data, skb_headlen(skb), |
| 1520 | PCI_DMA_TODEVICE); | 1520 | PCI_DMA_TODEVICE); |
| 1521 | map_size[0] = skb_headlen(skb); | 1521 | map_size[0] = skb_headlen(skb); |
| 1522 | if (dma_mapping_error(map[0])) | 1522 | if (pci_dma_mapping_error(mac->dma_pdev, map[0])) |
| 1523 | goto out_err_nolock; | 1523 | goto out_err_nolock; |
| 1524 | 1524 | ||
| 1525 | for (i = 0; i < nfrags; i++) { | 1525 | for (i = 0; i < nfrags; i++) { |
| @@ -1529,7 +1529,7 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) | |||
| 1529 | frag->page_offset, frag->size, | 1529 | frag->page_offset, frag->size, |
| 1530 | PCI_DMA_TODEVICE); | 1530 | PCI_DMA_TODEVICE); |
| 1531 | map_size[i+1] = frag->size; | 1531 | map_size[i+1] = frag->size; |
| 1532 | if (dma_mapping_error(map[i+1])) { | 1532 | if (pci_dma_mapping_error(mac->dma_pdev, map[i+1])) { |
| 1533 | nfrags = i; | 1533 | nfrags = i; |
| 1534 | goto out_err_nolock; | 1534 | goto out_err_nolock; |
| 1535 | } | 1535 | } |
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 739b3ab7bccc..ddccc074a76a 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c | |||
| @@ -581,12 +581,12 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
| 581 | if (file == ppp->owner) | 581 | if (file == ppp->owner) |
| 582 | ppp_shutdown_interface(ppp); | 582 | ppp_shutdown_interface(ppp); |
| 583 | } | 583 | } |
| 584 | if (atomic_read(&file->f_count) <= 2) { | 584 | if (atomic_long_read(&file->f_count) <= 2) { |
| 585 | ppp_release(NULL, file); | 585 | ppp_release(NULL, file); |
| 586 | err = 0; | 586 | err = 0; |
| 587 | } else | 587 | } else |
| 588 | printk(KERN_DEBUG "PPPIOCDETACH file->f_count=%d\n", | 588 | printk(KERN_DEBUG "PPPIOCDETACH file->f_count=%ld\n", |
| 589 | atomic_read(&file->f_count)); | 589 | atomic_long_read(&file->f_count)); |
| 590 | unlock_kernel(); | 590 | unlock_kernel(); |
| 591 | return err; | 591 | return err; |
| 592 | } | 592 | } |
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index e7d48a352beb..e82b37bbd6c3 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c | |||
| @@ -328,7 +328,7 @@ static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev, | |||
| 328 | qdev->lrg_buffer_len - | 328 | qdev->lrg_buffer_len - |
| 329 | QL_HEADER_SPACE, | 329 | QL_HEADER_SPACE, |
| 330 | PCI_DMA_FROMDEVICE); | 330 | PCI_DMA_FROMDEVICE); |
| 331 | err = pci_dma_mapping_error(map); | 331 | err = pci_dma_mapping_error(qdev->pdev, map); |
| 332 | if(err) { | 332 | if(err) { |
| 333 | printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", | 333 | printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", |
| 334 | qdev->ndev->name, err); | 334 | qdev->ndev->name, err); |
| @@ -1919,7 +1919,7 @@ static int ql_populate_free_queue(struct ql3_adapter *qdev) | |||
| 1919 | QL_HEADER_SPACE, | 1919 | QL_HEADER_SPACE, |
| 1920 | PCI_DMA_FROMDEVICE); | 1920 | PCI_DMA_FROMDEVICE); |
| 1921 | 1921 | ||
| 1922 | err = pci_dma_mapping_error(map); | 1922 | err = pci_dma_mapping_error(qdev->pdev, map); |
| 1923 | if(err) { | 1923 | if(err) { |
| 1924 | printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", | 1924 | printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", |
| 1925 | qdev->ndev->name, err); | 1925 | qdev->ndev->name, err); |
| @@ -2454,7 +2454,7 @@ static int ql_send_map(struct ql3_adapter *qdev, | |||
| 2454 | */ | 2454 | */ |
| 2455 | map = pci_map_single(qdev->pdev, skb->data, len, PCI_DMA_TODEVICE); | 2455 | map = pci_map_single(qdev->pdev, skb->data, len, PCI_DMA_TODEVICE); |
| 2456 | 2456 | ||
| 2457 | err = pci_dma_mapping_error(map); | 2457 | err = pci_dma_mapping_error(qdev->pdev, map); |
| 2458 | if(err) { | 2458 | if(err) { |
| 2459 | printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", | 2459 | printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", |
| 2460 | qdev->ndev->name, err); | 2460 | qdev->ndev->name, err); |
| @@ -2487,7 +2487,7 @@ static int ql_send_map(struct ql3_adapter *qdev, | |||
| 2487 | sizeof(struct oal), | 2487 | sizeof(struct oal), |
| 2488 | PCI_DMA_TODEVICE); | 2488 | PCI_DMA_TODEVICE); |
| 2489 | 2489 | ||
| 2490 | err = pci_dma_mapping_error(map); | 2490 | err = pci_dma_mapping_error(qdev->pdev, map); |
| 2491 | if(err) { | 2491 | if(err) { |
| 2492 | 2492 | ||
| 2493 | printk(KERN_ERR "%s: PCI mapping outbound address list with error: %d\n", | 2493 | printk(KERN_ERR "%s: PCI mapping outbound address list with error: %d\n", |
| @@ -2514,7 +2514,7 @@ static int ql_send_map(struct ql3_adapter *qdev, | |||
| 2514 | frag->page_offset, frag->size, | 2514 | frag->page_offset, frag->size, |
| 2515 | PCI_DMA_TODEVICE); | 2515 | PCI_DMA_TODEVICE); |
| 2516 | 2516 | ||
| 2517 | err = pci_dma_mapping_error(map); | 2517 | err = pci_dma_mapping_error(qdev->pdev, map); |
| 2518 | if(err) { | 2518 | if(err) { |
| 2519 | printk(KERN_ERR "%s: PCI mapping frags failed with error: %d\n", | 2519 | printk(KERN_ERR "%s: PCI mapping frags failed with error: %d\n", |
| 2520 | qdev->ndev->name, err); | 2520 | qdev->ndev->name, err); |
| @@ -2916,7 +2916,7 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev) | |||
| 2916 | QL_HEADER_SPACE, | 2916 | QL_HEADER_SPACE, |
| 2917 | PCI_DMA_FROMDEVICE); | 2917 | PCI_DMA_FROMDEVICE); |
| 2918 | 2918 | ||
| 2919 | err = pci_dma_mapping_error(map); | 2919 | err = pci_dma_mapping_error(qdev->pdev, map); |
| 2920 | if(err) { | 2920 | if(err) { |
| 2921 | printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", | 2921 | printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", |
| 2922 | qdev->ndev->name, err); | 2922 | qdev->ndev->name, err); |
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 9dae40ccf048..86d77d05190a 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c | |||
| @@ -2512,8 +2512,8 @@ static void stop_nic(struct s2io_nic *nic) | |||
| 2512 | * Return Value: | 2512 | * Return Value: |
| 2513 | * SUCCESS on success or an appropriate -ve value on failure. | 2513 | * SUCCESS on success or an appropriate -ve value on failure. |
| 2514 | */ | 2514 | */ |
| 2515 | 2515 | static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, | |
| 2516 | static int fill_rx_buffers(struct ring_info *ring, int from_card_up) | 2516 | int from_card_up) |
| 2517 | { | 2517 | { |
| 2518 | struct sk_buff *skb; | 2518 | struct sk_buff *skb; |
| 2519 | struct RxD_t *rxdp; | 2519 | struct RxD_t *rxdp; |
| @@ -2602,7 +2602,8 @@ static int fill_rx_buffers(struct ring_info *ring, int from_card_up) | |||
| 2602 | rxdp1->Buffer0_ptr = pci_map_single | 2602 | rxdp1->Buffer0_ptr = pci_map_single |
| 2603 | (ring->pdev, skb->data, size - NET_IP_ALIGN, | 2603 | (ring->pdev, skb->data, size - NET_IP_ALIGN, |
| 2604 | PCI_DMA_FROMDEVICE); | 2604 | PCI_DMA_FROMDEVICE); |
| 2605 | if(pci_dma_mapping_error(rxdp1->Buffer0_ptr)) | 2605 | if (pci_dma_mapping_error(nic->pdev, |
| 2606 | rxdp1->Buffer0_ptr)) | ||
| 2606 | goto pci_map_failed; | 2607 | goto pci_map_failed; |
| 2607 | 2608 | ||
| 2608 | rxdp->Control_2 = | 2609 | rxdp->Control_2 = |
| @@ -2636,7 +2637,8 @@ static int fill_rx_buffers(struct ring_info *ring, int from_card_up) | |||
| 2636 | rxdp3->Buffer0_ptr = | 2637 | rxdp3->Buffer0_ptr = |
| 2637 | pci_map_single(ring->pdev, ba->ba_0, | 2638 | pci_map_single(ring->pdev, ba->ba_0, |
| 2638 | BUF0_LEN, PCI_DMA_FROMDEVICE); | 2639 | BUF0_LEN, PCI_DMA_FROMDEVICE); |
| 2639 | if (pci_dma_mapping_error(rxdp3->Buffer0_ptr)) | 2640 | if (pci_dma_mapping_error(nic->pdev, |
| 2641 | rxdp3->Buffer0_ptr)) | ||
| 2640 | goto pci_map_failed; | 2642 | goto pci_map_failed; |
| 2641 | } else | 2643 | } else |
| 2642 | pci_dma_sync_single_for_device(ring->pdev, | 2644 | pci_dma_sync_single_for_device(ring->pdev, |
| @@ -2655,7 +2657,8 @@ static int fill_rx_buffers(struct ring_info *ring, int from_card_up) | |||
| 2655 | (ring->pdev, skb->data, ring->mtu + 4, | 2657 | (ring->pdev, skb->data, ring->mtu + 4, |
| 2656 | PCI_DMA_FROMDEVICE); | 2658 | PCI_DMA_FROMDEVICE); |
| 2657 | 2659 | ||
| 2658 | if (pci_dma_mapping_error(rxdp3->Buffer2_ptr)) | 2660 | if (pci_dma_mapping_error(nic->pdev, |
| 2661 | rxdp3->Buffer2_ptr)) | ||
| 2659 | goto pci_map_failed; | 2662 | goto pci_map_failed; |
| 2660 | 2663 | ||
| 2661 | if (from_card_up) { | 2664 | if (from_card_up) { |
| @@ -2664,8 +2667,8 @@ static int fill_rx_buffers(struct ring_info *ring, int from_card_up) | |||
| 2664 | ba->ba_1, BUF1_LEN, | 2667 | ba->ba_1, BUF1_LEN, |
| 2665 | PCI_DMA_FROMDEVICE); | 2668 | PCI_DMA_FROMDEVICE); |
| 2666 | 2669 | ||
| 2667 | if (pci_dma_mapping_error | 2670 | if (pci_dma_mapping_error(nic->pdev, |
| 2668 | (rxdp3->Buffer1_ptr)) { | 2671 | rxdp3->Buffer1_ptr)) { |
| 2669 | pci_unmap_single | 2672 | pci_unmap_single |
| 2670 | (ring->pdev, | 2673 | (ring->pdev, |
| 2671 | (dma_addr_t)(unsigned long) | 2674 | (dma_addr_t)(unsigned long) |
| @@ -2806,9 +2809,9 @@ static void free_rx_buffers(struct s2io_nic *sp) | |||
| 2806 | } | 2809 | } |
| 2807 | } | 2810 | } |
| 2808 | 2811 | ||
| 2809 | static int s2io_chk_rx_buffers(struct ring_info *ring) | 2812 | static int s2io_chk_rx_buffers(struct s2io_nic *nic, struct ring_info *ring) |
| 2810 | { | 2813 | { |
| 2811 | if (fill_rx_buffers(ring, 0) == -ENOMEM) { | 2814 | if (fill_rx_buffers(nic, ring, 0) == -ENOMEM) { |
| 2812 | DBG_PRINT(INFO_DBG, "%s:Out of memory", ring->dev->name); | 2815 | DBG_PRINT(INFO_DBG, "%s:Out of memory", ring->dev->name); |
| 2813 | DBG_PRINT(INFO_DBG, " in Rx Intr!!\n"); | 2816 | DBG_PRINT(INFO_DBG, " in Rx Intr!!\n"); |
| 2814 | } | 2817 | } |
| @@ -2848,7 +2851,7 @@ static int s2io_poll_msix(struct napi_struct *napi, int budget) | |||
| 2848 | return 0; | 2851 | return 0; |
| 2849 | 2852 | ||
| 2850 | pkts_processed = rx_intr_handler(ring, budget); | 2853 | pkts_processed = rx_intr_handler(ring, budget); |
| 2851 | s2io_chk_rx_buffers(ring); | 2854 | s2io_chk_rx_buffers(nic, ring); |
| 2852 | 2855 | ||
| 2853 | if (pkts_processed < budget_org) { | 2856 | if (pkts_processed < budget_org) { |
| 2854 | netif_rx_complete(dev, napi); | 2857 | netif_rx_complete(dev, napi); |
| @@ -2882,7 +2885,7 @@ static int s2io_poll_inta(struct napi_struct *napi, int budget) | |||
| 2882 | for (i = 0; i < config->rx_ring_num; i++) { | 2885 | for (i = 0; i < config->rx_ring_num; i++) { |
| 2883 | ring = &mac_control->rings[i]; | 2886 | ring = &mac_control->rings[i]; |
| 2884 | ring_pkts_processed = rx_intr_handler(ring, budget); | 2887 | ring_pkts_processed = rx_intr_handler(ring, budget); |
| 2885 | s2io_chk_rx_buffers(ring); | 2888 | s2io_chk_rx_buffers(nic, ring); |
| 2886 | pkts_processed += ring_pkts_processed; | 2889 | pkts_processed += ring_pkts_processed; |
| 2887 | budget -= ring_pkts_processed; | 2890 | budget -= ring_pkts_processed; |
| 2888 | if (budget <= 0) | 2891 | if (budget <= 0) |
| @@ -2939,7 +2942,8 @@ static void s2io_netpoll(struct net_device *dev) | |||
| 2939 | rx_intr_handler(&mac_control->rings[i], 0); | 2942 | rx_intr_handler(&mac_control->rings[i], 0); |
| 2940 | 2943 | ||
| 2941 | for (i = 0; i < config->rx_ring_num; i++) { | 2944 | for (i = 0; i < config->rx_ring_num; i++) { |
| 2942 | if (fill_rx_buffers(&mac_control->rings[i], 0) == -ENOMEM) { | 2945 | if (fill_rx_buffers(nic, &mac_control->rings[i], 0) == |
| 2946 | -ENOMEM) { | ||
| 2943 | DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name); | 2947 | DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name); |
| 2944 | DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n"); | 2948 | DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n"); |
| 2945 | break; | 2949 | break; |
| @@ -4235,14 +4239,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 4235 | txdp->Buffer_Pointer = pci_map_single(sp->pdev, | 4239 | txdp->Buffer_Pointer = pci_map_single(sp->pdev, |
| 4236 | fifo->ufo_in_band_v, | 4240 | fifo->ufo_in_band_v, |
| 4237 | sizeof(u64), PCI_DMA_TODEVICE); | 4241 | sizeof(u64), PCI_DMA_TODEVICE); |
| 4238 | if (pci_dma_mapping_error(txdp->Buffer_Pointer)) | 4242 | if (pci_dma_mapping_error(sp->pdev, txdp->Buffer_Pointer)) |
| 4239 | goto pci_map_failed; | 4243 | goto pci_map_failed; |
| 4240 | txdp++; | 4244 | txdp++; |
| 4241 | } | 4245 | } |
| 4242 | 4246 | ||
| 4243 | txdp->Buffer_Pointer = pci_map_single | 4247 | txdp->Buffer_Pointer = pci_map_single |
| 4244 | (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE); | 4248 | (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE); |
| 4245 | if (pci_dma_mapping_error(txdp->Buffer_Pointer)) | 4249 | if (pci_dma_mapping_error(sp->pdev, txdp->Buffer_Pointer)) |
| 4246 | goto pci_map_failed; | 4250 | goto pci_map_failed; |
| 4247 | 4251 | ||
| 4248 | txdp->Host_Control = (unsigned long) skb; | 4252 | txdp->Host_Control = (unsigned long) skb; |
| @@ -4345,7 +4349,7 @@ static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id) | |||
| 4345 | netif_rx_schedule(dev, &ring->napi); | 4349 | netif_rx_schedule(dev, &ring->napi); |
| 4346 | } else { | 4350 | } else { |
| 4347 | rx_intr_handler(ring, 0); | 4351 | rx_intr_handler(ring, 0); |
| 4348 | s2io_chk_rx_buffers(ring); | 4352 | s2io_chk_rx_buffers(sp, ring); |
| 4349 | } | 4353 | } |
| 4350 | 4354 | ||
| 4351 | return IRQ_HANDLED; | 4355 | return IRQ_HANDLED; |
| @@ -4826,7 +4830,7 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) | |||
| 4826 | */ | 4830 | */ |
| 4827 | if (!config->napi) { | 4831 | if (!config->napi) { |
| 4828 | for (i = 0; i < config->rx_ring_num; i++) | 4832 | for (i = 0; i < config->rx_ring_num; i++) |
| 4829 | s2io_chk_rx_buffers(&mac_control->rings[i]); | 4833 | s2io_chk_rx_buffers(sp, &mac_control->rings[i]); |
| 4830 | } | 4834 | } |
| 4831 | writeq(sp->general_int_mask, &bar0->general_int_mask); | 4835 | writeq(sp->general_int_mask, &bar0->general_int_mask); |
| 4832 | readl(&bar0->general_int_status); | 4836 | readl(&bar0->general_int_status); |
| @@ -6859,7 +6863,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, | |||
| 6859 | pci_map_single( sp->pdev, (*skb)->data, | 6863 | pci_map_single( sp->pdev, (*skb)->data, |
| 6860 | size - NET_IP_ALIGN, | 6864 | size - NET_IP_ALIGN, |
| 6861 | PCI_DMA_FROMDEVICE); | 6865 | PCI_DMA_FROMDEVICE); |
| 6862 | if (pci_dma_mapping_error(rxdp1->Buffer0_ptr)) | 6866 | if (pci_dma_mapping_error(sp->pdev, rxdp1->Buffer0_ptr)) |
| 6863 | goto memalloc_failed; | 6867 | goto memalloc_failed; |
| 6864 | rxdp->Host_Control = (unsigned long) (*skb); | 6868 | rxdp->Host_Control = (unsigned long) (*skb); |
| 6865 | } | 6869 | } |
| @@ -6886,12 +6890,13 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, | |||
| 6886 | pci_map_single(sp->pdev, (*skb)->data, | 6890 | pci_map_single(sp->pdev, (*skb)->data, |
| 6887 | dev->mtu + 4, | 6891 | dev->mtu + 4, |
| 6888 | PCI_DMA_FROMDEVICE); | 6892 | PCI_DMA_FROMDEVICE); |
| 6889 | if (pci_dma_mapping_error(rxdp3->Buffer2_ptr)) | 6893 | if (pci_dma_mapping_error(sp->pdev, rxdp3->Buffer2_ptr)) |
| 6890 | goto memalloc_failed; | 6894 | goto memalloc_failed; |
| 6891 | rxdp3->Buffer0_ptr = *temp0 = | 6895 | rxdp3->Buffer0_ptr = *temp0 = |
| 6892 | pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN, | 6896 | pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN, |
| 6893 | PCI_DMA_FROMDEVICE); | 6897 | PCI_DMA_FROMDEVICE); |
| 6894 | if (pci_dma_mapping_error(rxdp3->Buffer0_ptr)) { | 6898 | if (pci_dma_mapping_error(sp->pdev, |
| 6899 | rxdp3->Buffer0_ptr)) { | ||
| 6895 | pci_unmap_single (sp->pdev, | 6900 | pci_unmap_single (sp->pdev, |
| 6896 | (dma_addr_t)rxdp3->Buffer2_ptr, | 6901 | (dma_addr_t)rxdp3->Buffer2_ptr, |
| 6897 | dev->mtu + 4, PCI_DMA_FROMDEVICE); | 6902 | dev->mtu + 4, PCI_DMA_FROMDEVICE); |
| @@ -6903,7 +6908,8 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, | |||
| 6903 | rxdp3->Buffer1_ptr = *temp1 = | 6908 | rxdp3->Buffer1_ptr = *temp1 = |
| 6904 | pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN, | 6909 | pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN, |
| 6905 | PCI_DMA_FROMDEVICE); | 6910 | PCI_DMA_FROMDEVICE); |
| 6906 | if (pci_dma_mapping_error(rxdp3->Buffer1_ptr)) { | 6911 | if (pci_dma_mapping_error(sp->pdev, |
| 6912 | rxdp3->Buffer1_ptr)) { | ||
| 6907 | pci_unmap_single (sp->pdev, | 6913 | pci_unmap_single (sp->pdev, |
| 6908 | (dma_addr_t)rxdp3->Buffer0_ptr, | 6914 | (dma_addr_t)rxdp3->Buffer0_ptr, |
| 6909 | BUF0_LEN, PCI_DMA_FROMDEVICE); | 6915 | BUF0_LEN, PCI_DMA_FROMDEVICE); |
| @@ -7187,7 +7193,7 @@ static int s2io_card_up(struct s2io_nic * sp) | |||
| 7187 | 7193 | ||
| 7188 | for (i = 0; i < config->rx_ring_num; i++) { | 7194 | for (i = 0; i < config->rx_ring_num; i++) { |
| 7189 | mac_control->rings[i].mtu = dev->mtu; | 7195 | mac_control->rings[i].mtu = dev->mtu; |
| 7190 | ret = fill_rx_buffers(&mac_control->rings[i], 1); | 7196 | ret = fill_rx_buffers(sp, &mac_control->rings[i], 1); |
| 7191 | if (ret) { | 7197 | if (ret) { |
| 7192 | DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n", | 7198 | DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n", |
| 7193 | dev->name); | 7199 | dev->name); |
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index 601b001437c0..0d27dd39bc09 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c | |||
| @@ -233,7 +233,7 @@ static inline int efx_init_rx_buffer_skb(struct efx_rx_queue *rx_queue, | |||
| 233 | rx_buf->data, rx_buf->len, | 233 | rx_buf->data, rx_buf->len, |
| 234 | PCI_DMA_FROMDEVICE); | 234 | PCI_DMA_FROMDEVICE); |
| 235 | 235 | ||
| 236 | if (unlikely(pci_dma_mapping_error(rx_buf->dma_addr))) { | 236 | if (unlikely(pci_dma_mapping_error(efx->pci_dev, rx_buf->dma_addr))) { |
| 237 | dev_kfree_skb_any(rx_buf->skb); | 237 | dev_kfree_skb_any(rx_buf->skb); |
| 238 | rx_buf->skb = NULL; | 238 | rx_buf->skb = NULL; |
| 239 | return -EIO; | 239 | return -EIO; |
| @@ -275,7 +275,7 @@ static inline int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue, | |||
| 275 | 0, efx_rx_buf_size(efx), | 275 | 0, efx_rx_buf_size(efx), |
| 276 | PCI_DMA_FROMDEVICE); | 276 | PCI_DMA_FROMDEVICE); |
| 277 | 277 | ||
| 278 | if (unlikely(pci_dma_mapping_error(dma_addr))) { | 278 | if (unlikely(pci_dma_mapping_error(efx->pci_dev, dma_addr))) { |
| 279 | __free_pages(rx_buf->page, efx->rx_buffer_order); | 279 | __free_pages(rx_buf->page, efx->rx_buffer_order); |
| 280 | rx_buf->page = NULL; | 280 | rx_buf->page = NULL; |
| 281 | return -EIO; | 281 | return -EIO; |
diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index 5cdd082ab8f6..5e8374ab28ee 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c | |||
| @@ -172,7 +172,7 @@ static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue, | |||
| 172 | 172 | ||
| 173 | /* Process all fragments */ | 173 | /* Process all fragments */ |
| 174 | while (1) { | 174 | while (1) { |
| 175 | if (unlikely(pci_dma_mapping_error(dma_addr))) | 175 | if (unlikely(pci_dma_mapping_error(pci_dev, dma_addr))) |
| 176 | goto pci_err; | 176 | goto pci_err; |
| 177 | 177 | ||
| 178 | /* Store fields for marking in the per-fragment final | 178 | /* Store fields for marking in the per-fragment final |
| @@ -661,7 +661,8 @@ efx_tsoh_heap_alloc(struct efx_tx_queue *tx_queue, size_t header_len) | |||
| 661 | tsoh->dma_addr = pci_map_single(tx_queue->efx->pci_dev, | 661 | tsoh->dma_addr = pci_map_single(tx_queue->efx->pci_dev, |
| 662 | TSOH_BUFFER(tsoh), header_len, | 662 | TSOH_BUFFER(tsoh), header_len, |
| 663 | PCI_DMA_TODEVICE); | 663 | PCI_DMA_TODEVICE); |
| 664 | if (unlikely(pci_dma_mapping_error(tsoh->dma_addr))) { | 664 | if (unlikely(pci_dma_mapping_error(tx_queue->efx->pci_dev, |
| 665 | tsoh->dma_addr))) { | ||
| 665 | kfree(tsoh); | 666 | kfree(tsoh); |
| 666 | return NULL; | 667 | return NULL; |
| 667 | } | 668 | } |
| @@ -863,7 +864,7 @@ static inline int tso_get_fragment(struct tso_state *st, struct efx_nic *efx, | |||
| 863 | 864 | ||
| 864 | st->ifc.unmap_addr = pci_map_page(efx->pci_dev, page, page_off, | 865 | st->ifc.unmap_addr = pci_map_page(efx->pci_dev, page, page_off, |
| 865 | len, PCI_DMA_TODEVICE); | 866 | len, PCI_DMA_TODEVICE); |
| 866 | if (likely(!pci_dma_mapping_error(st->ifc.unmap_addr))) { | 867 | if (likely(!pci_dma_mapping_error(efx->pci_dev, st->ifc.unmap_addr))) { |
| 867 | st->ifc.unmap_len = len; | 868 | st->ifc.unmap_len = len; |
| 868 | st->ifc.len = len; | 869 | st->ifc.len = len; |
| 869 | st->ifc.dma_addr = st->ifc.unmap_addr; | 870 | st->ifc.dma_addr = st->ifc.unmap_addr; |
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 00aa0b108cb9..b6435d0d71f9 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c | |||
| @@ -452,7 +452,7 @@ spider_net_prepare_rx_descr(struct spider_net_card *card, | |||
| 452 | /* iommu-map the skb */ | 452 | /* iommu-map the skb */ |
| 453 | buf = pci_map_single(card->pdev, descr->skb->data, | 453 | buf = pci_map_single(card->pdev, descr->skb->data, |
| 454 | SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE); | 454 | SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE); |
| 455 | if (pci_dma_mapping_error(buf)) { | 455 | if (pci_dma_mapping_error(card->pdev, buf)) { |
| 456 | dev_kfree_skb_any(descr->skb); | 456 | dev_kfree_skb_any(descr->skb); |
| 457 | descr->skb = NULL; | 457 | descr->skb = NULL; |
| 458 | if (netif_msg_rx_err(card) && net_ratelimit()) | 458 | if (netif_msg_rx_err(card) && net_ratelimit()) |
| @@ -691,7 +691,7 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, | |||
| 691 | unsigned long flags; | 691 | unsigned long flags; |
| 692 | 692 | ||
| 693 | buf = pci_map_single(card->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); | 693 | buf = pci_map_single(card->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); |
| 694 | if (pci_dma_mapping_error(buf)) { | 694 | if (pci_dma_mapping_error(card->pdev, buf)) { |
| 695 | if (netif_msg_tx_err(card) && net_ratelimit()) | 695 | if (netif_msg_tx_err(card) && net_ratelimit()) |
| 696 | dev_err(&card->netdev->dev, "could not iommu-map packet (%p, %i). " | 696 | dev_err(&card->netdev->dev, "could not iommu-map packet (%p, %i). " |
| 697 | "Dropping packet\n", skb->data, skb->len); | 697 | "Dropping packet\n", skb->data, skb->len); |
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index a645e5028c14..8487ace9d2e3 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c | |||
| @@ -506,7 +506,7 @@ static void *alloc_rxbuf_page(struct pci_dev *hwdev, dma_addr_t *dma_handle) | |||
| 506 | return NULL; | 506 | return NULL; |
| 507 | *dma_handle = pci_map_single(hwdev, buf, PAGE_SIZE, | 507 | *dma_handle = pci_map_single(hwdev, buf, PAGE_SIZE, |
| 508 | PCI_DMA_FROMDEVICE); | 508 | PCI_DMA_FROMDEVICE); |
| 509 | if (pci_dma_mapping_error(*dma_handle)) { | 509 | if (pci_dma_mapping_error(hwdev, *dma_handle)) { |
| 510 | free_page((unsigned long)buf); | 510 | free_page((unsigned long)buf); |
| 511 | return NULL; | 511 | return NULL; |
| 512 | } | 512 | } |
| @@ -536,7 +536,7 @@ static struct sk_buff *alloc_rxbuf_skb(struct net_device *dev, | |||
| 536 | return NULL; | 536 | return NULL; |
| 537 | *dma_handle = pci_map_single(hwdev, skb->data, RX_BUF_SIZE, | 537 | *dma_handle = pci_map_single(hwdev, skb->data, RX_BUF_SIZE, |
| 538 | PCI_DMA_FROMDEVICE); | 538 | PCI_DMA_FROMDEVICE); |
| 539 | if (pci_dma_mapping_error(*dma_handle)) { | 539 | if (pci_dma_mapping_error(hwdev, *dma_handle)) { |
| 540 | dev_kfree_skb_any(skb); | 540 | dev_kfree_skb_any(skb); |
| 541 | return NULL; | 541 | return NULL; |
| 542 | } | 542 | } |
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 217d506527a9..d9769c527346 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c | |||
| @@ -1166,7 +1166,7 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) | |||
| 1166 | bf->skb = skb; | 1166 | bf->skb = skb; |
| 1167 | bf->skbaddr = pci_map_single(sc->pdev, | 1167 | bf->skbaddr = pci_map_single(sc->pdev, |
| 1168 | skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE); | 1168 | skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE); |
| 1169 | if (unlikely(pci_dma_mapping_error(bf->skbaddr))) { | 1169 | if (unlikely(pci_dma_mapping_error(sc->pdev, bf->skbaddr))) { |
| 1170 | ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__); | 1170 | ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__); |
| 1171 | dev_kfree_skb(skb); | 1171 | dev_kfree_skb(skb); |
| 1172 | bf->skb = NULL; | 1172 | bf->skb = NULL; |
| @@ -1918,7 +1918,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) | |||
| 1918 | ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "skb %p [data %p len %u] " | 1918 | ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "skb %p [data %p len %u] " |
| 1919 | "skbaddr %llx\n", skb, skb->data, skb->len, | 1919 | "skbaddr %llx\n", skb, skb->data, skb->len, |
| 1920 | (unsigned long long)bf->skbaddr); | 1920 | (unsigned long long)bf->skbaddr); |
| 1921 | if (pci_dma_mapping_error(bf->skbaddr)) { | 1921 | if (pci_dma_mapping_error(sc->pdev, bf->skbaddr)) { |
| 1922 | ATH5K_ERR(sc, "beacon DMA mapping failed\n"); | 1922 | ATH5K_ERR(sc, "beacon DMA mapping failed\n"); |
| 1923 | return -EIO; | 1923 | return -EIO; |
| 1924 | } | 1924 | } |
diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c index 0338b0912674..e97059415ab4 100644 --- a/drivers/parport/ieee1284.c +++ b/drivers/parport/ieee1284.c | |||
| @@ -199,8 +199,6 @@ int parport_wait_peripheral(struct parport *port, | |||
| 199 | /* 40ms of slow polling. */ | 199 | /* 40ms of slow polling. */ |
| 200 | deadline = jiffies + msecs_to_jiffies(40); | 200 | deadline = jiffies + msecs_to_jiffies(40); |
| 201 | while (time_before (jiffies, deadline)) { | 201 | while (time_before (jiffies, deadline)) { |
| 202 | int ret; | ||
| 203 | |||
| 204 | if (signal_pending (current)) | 202 | if (signal_pending (current)) |
| 205 | return -EINTR; | 203 | return -EINTR; |
| 206 | 204 | ||
diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c index 802a81d47367..00e1d9620f7c 100644 --- a/drivers/parport/parport_cs.c +++ b/drivers/parport/parport_cs.c | |||
| @@ -235,7 +235,7 @@ failed: | |||
| 235 | 235 | ||
| 236 | ======================================================================*/ | 236 | ======================================================================*/ |
| 237 | 237 | ||
| 238 | void parport_cs_release(struct pcmcia_device *link) | 238 | static void parport_cs_release(struct pcmcia_device *link) |
| 239 | { | 239 | { |
| 240 | parport_info_t *info = link->priv; | 240 | parport_info_t *info = link->priv; |
| 241 | 241 | ||
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index e0c2a4584ec6..8a846adf1dcf 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c | |||
| @@ -2867,7 +2867,7 @@ static struct parport_pc_pci { | |||
| 2867 | * and 840 locks up if you write 1 to bit 2! */ | 2867 | * and 840 locks up if you write 1 to bit 2! */ |
| 2868 | /* oxsemi_952 */ { 1, { { 0, 1 }, } }, | 2868 | /* oxsemi_952 */ { 1, { { 0, 1 }, } }, |
| 2869 | /* oxsemi_954 */ { 1, { { 0, -1 }, } }, | 2869 | /* oxsemi_954 */ { 1, { { 0, -1 }, } }, |
| 2870 | /* oxsemi_840 */ { 1, { { 0, -1 }, } }, | 2870 | /* oxsemi_840 */ { 1, { { 0, 1 }, } }, |
| 2871 | /* aks_0100 */ { 1, { { 0, -1 }, } }, | 2871 | /* aks_0100 */ { 1, { { 0, -1 }, } }, |
| 2872 | /* mobility_pp */ { 1, { { 0, 1 }, } }, | 2872 | /* mobility_pp */ { 1, { { 0, 1 }, } }, |
| 2873 | /* netmos_9705 */ { 1, { { 0, -1 }, } }, /* untested */ | 2873 | /* netmos_9705 */ { 1, { { 0, -1 }, } }, /* untested */ |
diff --git a/drivers/parport/procfs.c b/drivers/parport/procfs.c index d950fc34320a..554e11f9e1ce 100644 --- a/drivers/parport/procfs.c +++ b/drivers/parport/procfs.c | |||
| @@ -429,9 +429,6 @@ struct parport_default_sysctl_table | |||
| 429 | ctl_table dev_dir[2]; | 429 | ctl_table dev_dir[2]; |
| 430 | }; | 430 | }; |
| 431 | 431 | ||
| 432 | extern unsigned long parport_default_timeslice; | ||
| 433 | extern int parport_default_spintime; | ||
| 434 | |||
| 435 | static struct parport_default_sysctl_table | 432 | static struct parport_default_sysctl_table |
| 436 | parport_default_sysctl_table = { | 433 | parport_default_sysctl_table = { |
| 437 | .sysctl_header = NULL, | 434 | .sysctl_header = NULL, |
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 420a77540f41..8c21446996f2 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c | |||
| @@ -149,10 +149,10 @@ soc_common_pcmcia_config_skt(struct soc_pcmcia_socket *skt, socket_state_t *stat | |||
| 149 | */ | 149 | */ |
| 150 | if (skt->irq_state != 1 && state->io_irq) { | 150 | if (skt->irq_state != 1 && state->io_irq) { |
| 151 | skt->irq_state = 1; | 151 | skt->irq_state = 1; |
| 152 | set_irq_type(skt->irq, IRQT_FALLING); | 152 | set_irq_type(skt->irq, IRQ_TYPE_EDGE_FALLING); |
| 153 | } else if (skt->irq_state == 1 && state->io_irq == 0) { | 153 | } else if (skt->irq_state == 1 && state->io_irq == 0) { |
| 154 | skt->irq_state = 0; | 154 | skt->irq_state = 0; |
| 155 | set_irq_type(skt->irq, IRQT_NOEDGE); | 155 | set_irq_type(skt->irq, IRQ_TYPE_NONE); |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | skt->cs_state = *state; | 158 | skt->cs_state = *state; |
| @@ -527,7 +527,7 @@ int soc_pcmcia_request_irqs(struct soc_pcmcia_socket *skt, | |||
| 527 | IRQF_DISABLED, irqs[i].str, skt); | 527 | IRQF_DISABLED, irqs[i].str, skt); |
| 528 | if (res) | 528 | if (res) |
| 529 | break; | 529 | break; |
| 530 | set_irq_type(irqs[i].irq, IRQT_NOEDGE); | 530 | set_irq_type(irqs[i].irq, IRQ_TYPE_NONE); |
| 531 | } | 531 | } |
| 532 | 532 | ||
| 533 | if (res) { | 533 | if (res) { |
| @@ -560,7 +560,7 @@ void soc_pcmcia_disable_irqs(struct soc_pcmcia_socket *skt, | |||
| 560 | 560 | ||
| 561 | for (i = 0; i < nr; i++) | 561 | for (i = 0; i < nr; i++) |
| 562 | if (irqs[i].sock == skt->nr) | 562 | if (irqs[i].sock == skt->nr) |
| 563 | set_irq_type(irqs[i].irq, IRQT_NOEDGE); | 563 | set_irq_type(irqs[i].irq, IRQ_TYPE_NONE); |
| 564 | } | 564 | } |
| 565 | EXPORT_SYMBOL(soc_pcmcia_disable_irqs); | 565 | EXPORT_SYMBOL(soc_pcmcia_disable_irqs); |
| 566 | 566 | ||
| @@ -571,8 +571,8 @@ void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt, | |||
| 571 | 571 | ||
| 572 | for (i = 0; i < nr; i++) | 572 | for (i = 0; i < nr; i++) |
| 573 | if (irqs[i].sock == skt->nr) { | 573 | if (irqs[i].sock == skt->nr) { |
| 574 | set_irq_type(irqs[i].irq, IRQT_RISING); | 574 | set_irq_type(irqs[i].irq, IRQ_TYPE_EDGE_RISING); |
| 575 | set_irq_type(irqs[i].irq, IRQT_BOTHEDGE); | 575 | set_irq_type(irqs[i].irq, IRQ_TYPE_EDGE_BOTH); |
| 576 | } | 576 | } |
| 577 | } | 577 | } |
| 578 | EXPORT_SYMBOL(soc_pcmcia_enable_irqs); | 578 | EXPORT_SYMBOL(soc_pcmcia_enable_irqs); |
diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h index e3fa9a2d9a3d..9fd7bb9b7dce 100644 --- a/drivers/pnp/base.h +++ b/drivers/pnp/base.h | |||
| @@ -19,7 +19,6 @@ struct pnp_id *pnp_add_id(struct pnp_dev *dev, char *id); | |||
| 19 | int pnp_interface_attach_device(struct pnp_dev *dev); | 19 | int pnp_interface_attach_device(struct pnp_dev *dev); |
| 20 | 20 | ||
| 21 | int pnp_add_card(struct pnp_card *card); | 21 | int pnp_add_card(struct pnp_card *card); |
| 22 | struct pnp_id *pnp_add_card_id(struct pnp_card *card, char *id); | ||
| 23 | void pnp_remove_card(struct pnp_card *card); | 22 | void pnp_remove_card(struct pnp_card *card); |
| 24 | int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev); | 23 | int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev); |
| 25 | void pnp_remove_card_device(struct pnp_dev *dev); | 24 | void pnp_remove_card_device(struct pnp_dev *dev); |
diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c index a762a4176736..e75b060daa95 100644 --- a/drivers/pnp/card.c +++ b/drivers/pnp/card.c | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <linux/ctype.h> | 8 | #include <linux/ctype.h> |
| 9 | #include <linux/slab.h> | 9 | #include <linux/slab.h> |
| 10 | #include <linux/pnp.h> | 10 | #include <linux/pnp.h> |
| 11 | #include <linux/dma-mapping.h> | ||
| 11 | #include "base.h" | 12 | #include "base.h" |
| 12 | 13 | ||
| 13 | LIST_HEAD(pnp_cards); | 14 | LIST_HEAD(pnp_cards); |
| @@ -101,7 +102,7 @@ static int card_probe(struct pnp_card *card, struct pnp_card_driver *drv) | |||
| 101 | * @id: pointer to a pnp_id structure | 102 | * @id: pointer to a pnp_id structure |
| 102 | * @card: pointer to the desired card | 103 | * @card: pointer to the desired card |
| 103 | */ | 104 | */ |
| 104 | struct pnp_id *pnp_add_card_id(struct pnp_card *card, char *id) | 105 | static struct pnp_id *pnp_add_card_id(struct pnp_card *card, char *id) |
| 105 | { | 106 | { |
| 106 | struct pnp_id *dev_id, *ptr; | 107 | struct pnp_id *dev_id, *ptr; |
| 107 | 108 | ||
| @@ -167,6 +168,9 @@ struct pnp_card *pnp_alloc_card(struct pnp_protocol *protocol, int id, char *pnp | |||
| 167 | sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number, | 168 | sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number, |
| 168 | card->number); | 169 | card->number); |
| 169 | 170 | ||
| 171 | card->dev.coherent_dma_mask = DMA_24BIT_MASK; | ||
| 172 | card->dev.dma_mask = &card->dev.coherent_dma_mask; | ||
| 173 | |||
| 170 | dev_id = pnp_add_card_id(card, pnpid); | 174 | dev_id = pnp_add_card_id(card, pnpid); |
| 171 | if (!dev_id) { | 175 | if (!dev_id) { |
| 172 | kfree(card); | 176 | kfree(card); |
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index 55f55ed72dc7..0bdf9b8a5e58 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c | |||
| @@ -245,15 +245,17 @@ static void quirk_system_pci_resources(struct pnp_dev *dev) | |||
| 245 | */ | 245 | */ |
| 246 | for_each_pci_dev(pdev) { | 246 | for_each_pci_dev(pdev) { |
| 247 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { | 247 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { |
| 248 | if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM) || | 248 | unsigned int type; |
| 249 | pci_resource_len(pdev, i) == 0) | 249 | |
| 250 | type = pci_resource_flags(pdev, i) & | ||
| 251 | (IORESOURCE_IO | IORESOURCE_MEM); | ||
| 252 | if (!type || pci_resource_len(pdev, i) == 0) | ||
| 250 | continue; | 253 | continue; |
| 251 | 254 | ||
| 252 | pci_start = pci_resource_start(pdev, i); | 255 | pci_start = pci_resource_start(pdev, i); |
| 253 | pci_end = pci_resource_end(pdev, i); | 256 | pci_end = pci_resource_end(pdev, i); |
| 254 | for (j = 0; | 257 | for (j = 0; |
| 255 | (res = pnp_get_resource(dev, IORESOURCE_MEM, j)); | 258 | (res = pnp_get_resource(dev, type, j)); j++) { |
| 256 | j++) { | ||
| 257 | if (res->start == 0 && res->end == 0) | 259 | if (res->start == 0 && res->end == 0) |
| 258 | continue; | 260 | continue; |
| 259 | 261 | ||
| @@ -283,9 +285,10 @@ static void quirk_system_pci_resources(struct pnp_dev *dev) | |||
| 283 | * the PCI region, and that might prevent a PCI | 285 | * the PCI region, and that might prevent a PCI |
| 284 | * driver from requesting its resources. | 286 | * driver from requesting its resources. |
| 285 | */ | 287 | */ |
| 286 | dev_warn(&dev->dev, "mem resource " | 288 | dev_warn(&dev->dev, "%s resource " |
| 287 | "(0x%llx-0x%llx) overlaps %s BAR %d " | 289 | "(0x%llx-0x%llx) overlaps %s BAR %d " |
| 288 | "(0x%llx-0x%llx), disabling\n", | 290 | "(0x%llx-0x%llx), disabling\n", |
| 291 | pnp_resource_type_name(res), | ||
| 289 | (unsigned long long) pnp_start, | 292 | (unsigned long long) pnp_start, |
| 290 | (unsigned long long) pnp_end, | 293 | (unsigned long long) pnp_end, |
| 291 | pci_name(pdev), i, | 294 | pci_name(pdev), i, |
diff --git a/drivers/s390/kvm/Makefile b/drivers/s390/kvm/Makefile index 4a5ec39f9ca6..0815690ac1e0 100644 --- a/drivers/s390/kvm/Makefile +++ b/drivers/s390/kvm/Makefile | |||
| @@ -6,4 +6,4 @@ | |||
| 6 | # it under the terms of the GNU General Public License (version 2 only) | 6 | # it under the terms of the GNU General Public License (version 2 only) |
| 7 | # as published by the Free Software Foundation. | 7 | # as published by the Free Software Foundation. |
| 8 | 8 | ||
| 9 | obj-$(CONFIG_VIRTIO) += kvm_virtio.o | 9 | obj-$(CONFIG_S390_GUEST) += kvm_virtio.o |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index c3ad89e302bd..cebb25e36e82 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
| @@ -3321,7 +3321,7 @@ int qeth_change_mtu(struct net_device *dev, int new_mtu) | |||
| 3321 | struct qeth_card *card; | 3321 | struct qeth_card *card; |
| 3322 | char dbf_text[15]; | 3322 | char dbf_text[15]; |
| 3323 | 3323 | ||
| 3324 | card = netdev_priv(dev); | 3324 | card = dev->ml_priv; |
| 3325 | 3325 | ||
| 3326 | QETH_DBF_TEXT(TRACE, 4, "chgmtu"); | 3326 | QETH_DBF_TEXT(TRACE, 4, "chgmtu"); |
| 3327 | sprintf(dbf_text, "%8x", new_mtu); | 3327 | sprintf(dbf_text, "%8x", new_mtu); |
| @@ -3343,7 +3343,7 @@ struct net_device_stats *qeth_get_stats(struct net_device *dev) | |||
| 3343 | { | 3343 | { |
| 3344 | struct qeth_card *card; | 3344 | struct qeth_card *card; |
| 3345 | 3345 | ||
| 3346 | card = netdev_priv(dev); | 3346 | card = dev->ml_priv; |
| 3347 | 3347 | ||
| 3348 | QETH_DBF_TEXT(TRACE, 5, "getstat"); | 3348 | QETH_DBF_TEXT(TRACE, 5, "getstat"); |
| 3349 | 3349 | ||
| @@ -3395,7 +3395,7 @@ void qeth_tx_timeout(struct net_device *dev) | |||
| 3395 | { | 3395 | { |
| 3396 | struct qeth_card *card; | 3396 | struct qeth_card *card; |
| 3397 | 3397 | ||
| 3398 | card = netdev_priv(dev); | 3398 | card = dev->ml_priv; |
| 3399 | card->stats.tx_errors++; | 3399 | card->stats.tx_errors++; |
| 3400 | qeth_schedule_recovery(card); | 3400 | qeth_schedule_recovery(card); |
| 3401 | } | 3401 | } |
| @@ -3403,7 +3403,7 @@ EXPORT_SYMBOL_GPL(qeth_tx_timeout); | |||
| 3403 | 3403 | ||
| 3404 | int qeth_mdio_read(struct net_device *dev, int phy_id, int regnum) | 3404 | int qeth_mdio_read(struct net_device *dev, int phy_id, int regnum) |
| 3405 | { | 3405 | { |
| 3406 | struct qeth_card *card = netdev_priv(dev); | 3406 | struct qeth_card *card = dev->ml_priv; |
| 3407 | int rc = 0; | 3407 | int rc = 0; |
| 3408 | 3408 | ||
| 3409 | switch (regnum) { | 3409 | switch (regnum) { |
| @@ -4253,7 +4253,7 @@ EXPORT_SYMBOL_GPL(qeth_core_get_stats_count); | |||
| 4253 | void qeth_core_get_ethtool_stats(struct net_device *dev, | 4253 | void qeth_core_get_ethtool_stats(struct net_device *dev, |
| 4254 | struct ethtool_stats *stats, u64 *data) | 4254 | struct ethtool_stats *stats, u64 *data) |
| 4255 | { | 4255 | { |
| 4256 | struct qeth_card *card = netdev_priv(dev); | 4256 | struct qeth_card *card = dev->ml_priv; |
| 4257 | data[0] = card->stats.rx_packets - | 4257 | data[0] = card->stats.rx_packets - |
| 4258 | card->perf_stats.initial_rx_packets; | 4258 | card->perf_stats.initial_rx_packets; |
| 4259 | data[1] = card->perf_stats.bufs_rec; | 4259 | data[1] = card->perf_stats.bufs_rec; |
| @@ -4313,7 +4313,7 @@ EXPORT_SYMBOL_GPL(qeth_core_get_strings); | |||
| 4313 | void qeth_core_get_drvinfo(struct net_device *dev, | 4313 | void qeth_core_get_drvinfo(struct net_device *dev, |
| 4314 | struct ethtool_drvinfo *info) | 4314 | struct ethtool_drvinfo *info) |
| 4315 | { | 4315 | { |
| 4316 | struct qeth_card *card = netdev_priv(dev); | 4316 | struct qeth_card *card = dev->ml_priv; |
| 4317 | if (card->options.layer2) | 4317 | if (card->options.layer2) |
| 4318 | strcpy(info->driver, "qeth_l2"); | 4318 | strcpy(info->driver, "qeth_l2"); |
| 4319 | else | 4319 | else |
| @@ -4331,7 +4331,7 @@ EXPORT_SYMBOL_GPL(qeth_core_get_drvinfo); | |||
| 4331 | int qeth_core_ethtool_get_settings(struct net_device *netdev, | 4331 | int qeth_core_ethtool_get_settings(struct net_device *netdev, |
| 4332 | struct ethtool_cmd *ecmd) | 4332 | struct ethtool_cmd *ecmd) |
| 4333 | { | 4333 | { |
| 4334 | struct qeth_card *card = netdev_priv(netdev); | 4334 | struct qeth_card *card = netdev->ml_priv; |
| 4335 | enum qeth_link_types link_type; | 4335 | enum qeth_link_types link_type; |
| 4336 | 4336 | ||
| 4337 | if ((card->info.type == QETH_CARD_TYPE_IQD) || (card->info.guestlan)) | 4337 | if ((card->info.type == QETH_CARD_TYPE_IQD) || (card->info.guestlan)) |
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 3fbc3bdec0c5..a8b069cd9a4c 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c | |||
| @@ -35,7 +35,7 @@ static int qeth_l2_recover(void *); | |||
| 35 | 35 | ||
| 36 | static int qeth_l2_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | 36 | static int qeth_l2_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) |
| 37 | { | 37 | { |
| 38 | struct qeth_card *card = netdev_priv(dev); | 38 | struct qeth_card *card = dev->ml_priv; |
| 39 | struct mii_ioctl_data *mii_data; | 39 | struct mii_ioctl_data *mii_data; |
| 40 | int rc = 0; | 40 | int rc = 0; |
| 41 | 41 | ||
| @@ -317,7 +317,7 @@ static void qeth_l2_process_vlans(struct qeth_card *card, int clear) | |||
| 317 | 317 | ||
| 318 | static void qeth_l2_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) | 318 | static void qeth_l2_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) |
| 319 | { | 319 | { |
| 320 | struct qeth_card *card = netdev_priv(dev); | 320 | struct qeth_card *card = dev->ml_priv; |
| 321 | struct qeth_vlan_vid *id; | 321 | struct qeth_vlan_vid *id; |
| 322 | 322 | ||
| 323 | QETH_DBF_TEXT_(TRACE, 4, "aid:%d", vid); | 323 | QETH_DBF_TEXT_(TRACE, 4, "aid:%d", vid); |
| @@ -334,7 +334,7 @@ static void qeth_l2_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) | |||
| 334 | static void qeth_l2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) | 334 | static void qeth_l2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) |
| 335 | { | 335 | { |
| 336 | struct qeth_vlan_vid *id, *tmpid = NULL; | 336 | struct qeth_vlan_vid *id, *tmpid = NULL; |
| 337 | struct qeth_card *card = netdev_priv(dev); | 337 | struct qeth_card *card = dev->ml_priv; |
| 338 | 338 | ||
| 339 | QETH_DBF_TEXT_(TRACE, 4, "kid:%d", vid); | 339 | QETH_DBF_TEXT_(TRACE, 4, "kid:%d", vid); |
| 340 | spin_lock_bh(&card->vlanlock); | 340 | spin_lock_bh(&card->vlanlock); |
| @@ -566,7 +566,7 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card) | |||
| 566 | static int qeth_l2_set_mac_address(struct net_device *dev, void *p) | 566 | static int qeth_l2_set_mac_address(struct net_device *dev, void *p) |
| 567 | { | 567 | { |
| 568 | struct sockaddr *addr = p; | 568 | struct sockaddr *addr = p; |
| 569 | struct qeth_card *card = netdev_priv(dev); | 569 | struct qeth_card *card = dev->ml_priv; |
| 570 | int rc = 0; | 570 | int rc = 0; |
| 571 | 571 | ||
| 572 | QETH_DBF_TEXT(TRACE, 3, "setmac"); | 572 | QETH_DBF_TEXT(TRACE, 3, "setmac"); |
| @@ -590,7 +590,7 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p) | |||
| 590 | 590 | ||
| 591 | static void qeth_l2_set_multicast_list(struct net_device *dev) | 591 | static void qeth_l2_set_multicast_list(struct net_device *dev) |
| 592 | { | 592 | { |
| 593 | struct qeth_card *card = netdev_priv(dev); | 593 | struct qeth_card *card = dev->ml_priv; |
| 594 | struct dev_mc_list *dm; | 594 | struct dev_mc_list *dm; |
| 595 | 595 | ||
| 596 | if (card->info.type == QETH_CARD_TYPE_OSN) | 596 | if (card->info.type == QETH_CARD_TYPE_OSN) |
| @@ -612,7 +612,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 612 | int rc; | 612 | int rc; |
| 613 | struct qeth_hdr *hdr = NULL; | 613 | struct qeth_hdr *hdr = NULL; |
| 614 | int elements = 0; | 614 | int elements = 0; |
| 615 | struct qeth_card *card = netdev_priv(dev); | 615 | struct qeth_card *card = dev->ml_priv; |
| 616 | struct sk_buff *new_skb = skb; | 616 | struct sk_buff *new_skb = skb; |
| 617 | int ipv = qeth_get_ip_version(skb); | 617 | int ipv = qeth_get_ip_version(skb); |
| 618 | int cast_type = qeth_get_cast_type(card, skb); | 618 | int cast_type = qeth_get_cast_type(card, skb); |
| @@ -767,7 +767,7 @@ static void qeth_l2_qdio_input_handler(struct ccw_device *ccwdev, | |||
| 767 | 767 | ||
| 768 | static int qeth_l2_open(struct net_device *dev) | 768 | static int qeth_l2_open(struct net_device *dev) |
| 769 | { | 769 | { |
| 770 | struct qeth_card *card = netdev_priv(dev); | 770 | struct qeth_card *card = dev->ml_priv; |
| 771 | 771 | ||
| 772 | QETH_DBF_TEXT(TRACE, 4, "qethopen"); | 772 | QETH_DBF_TEXT(TRACE, 4, "qethopen"); |
| 773 | if (card->state != CARD_STATE_SOFTSETUP) | 773 | if (card->state != CARD_STATE_SOFTSETUP) |
| @@ -791,7 +791,7 @@ static int qeth_l2_open(struct net_device *dev) | |||
| 791 | 791 | ||
| 792 | static int qeth_l2_stop(struct net_device *dev) | 792 | static int qeth_l2_stop(struct net_device *dev) |
| 793 | { | 793 | { |
| 794 | struct qeth_card *card = netdev_priv(dev); | 794 | struct qeth_card *card = dev->ml_priv; |
| 795 | 795 | ||
| 796 | QETH_DBF_TEXT(TRACE, 4, "qethstop"); | 796 | QETH_DBF_TEXT(TRACE, 4, "qethstop"); |
| 797 | netif_tx_disable(dev); | 797 | netif_tx_disable(dev); |
| @@ -838,7 +838,7 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev) | |||
| 838 | 838 | ||
| 839 | static int qeth_l2_ethtool_set_tso(struct net_device *dev, u32 data) | 839 | static int qeth_l2_ethtool_set_tso(struct net_device *dev, u32 data) |
| 840 | { | 840 | { |
| 841 | struct qeth_card *card = netdev_priv(dev); | 841 | struct qeth_card *card = dev->ml_priv; |
| 842 | 842 | ||
| 843 | if (data) { | 843 | if (data) { |
| 844 | if (card->options.large_send == QETH_LARGE_SEND_NO) { | 844 | if (card->options.large_send == QETH_LARGE_SEND_NO) { |
| @@ -894,7 +894,7 @@ static int qeth_l2_setup_netdev(struct qeth_card *card) | |||
| 894 | if (!card->dev) | 894 | if (!card->dev) |
| 895 | return -ENODEV; | 895 | return -ENODEV; |
| 896 | 896 | ||
| 897 | card->dev->priv = card; | 897 | card->dev->ml_priv = card; |
| 898 | card->dev->tx_timeout = &qeth_tx_timeout; | 898 | card->dev->tx_timeout = &qeth_tx_timeout; |
| 899 | card->dev->watchdog_timeo = QETH_TX_TIMEOUT; | 899 | card->dev->watchdog_timeo = QETH_TX_TIMEOUT; |
| 900 | card->dev->open = qeth_l2_open; | 900 | card->dev->open = qeth_l2_open; |
| @@ -1178,7 +1178,7 @@ int qeth_osn_assist(struct net_device *dev, void *data, int data_len) | |||
| 1178 | QETH_DBF_TEXT(TRACE, 2, "osnsdmc"); | 1178 | QETH_DBF_TEXT(TRACE, 2, "osnsdmc"); |
| 1179 | if (!dev) | 1179 | if (!dev) |
| 1180 | return -ENODEV; | 1180 | return -ENODEV; |
| 1181 | card = netdev_priv(dev); | 1181 | card = dev->ml_priv; |
| 1182 | if (!card) | 1182 | if (!card) |
| 1183 | return -ENODEV; | 1183 | return -ENODEV; |
| 1184 | if ((card->state != CARD_STATE_UP) && | 1184 | if ((card->state != CARD_STATE_UP) && |
| @@ -1201,7 +1201,7 @@ int qeth_osn_register(unsigned char *read_dev_no, struct net_device **dev, | |||
| 1201 | *dev = qeth_l2_netdev_by_devno(read_dev_no); | 1201 | *dev = qeth_l2_netdev_by_devno(read_dev_no); |
| 1202 | if (*dev == NULL) | 1202 | if (*dev == NULL) |
| 1203 | return -ENODEV; | 1203 | return -ENODEV; |
| 1204 | card = netdev_priv(*dev); | 1204 | card = (*dev)->ml_priv; |
| 1205 | if (!card) | 1205 | if (!card) |
| 1206 | return -ENODEV; | 1206 | return -ENODEV; |
| 1207 | if ((assist_cb == NULL) || (data_cb == NULL)) | 1207 | if ((assist_cb == NULL) || (data_cb == NULL)) |
| @@ -1219,7 +1219,7 @@ void qeth_osn_deregister(struct net_device *dev) | |||
| 1219 | QETH_DBF_TEXT(TRACE, 2, "osndereg"); | 1219 | QETH_DBF_TEXT(TRACE, 2, "osndereg"); |
| 1220 | if (!dev) | 1220 | if (!dev) |
| 1221 | return; | 1221 | return; |
| 1222 | card = netdev_priv(dev); | 1222 | card = dev->ml_priv; |
| 1223 | if (!card) | 1223 | if (!card) |
| 1224 | return; | 1224 | return; |
| 1225 | card->osn_info.assist_cb = NULL; | 1225 | card->osn_info.assist_cb = NULL; |
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 38de31b55708..3e1d13857350 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
| @@ -1813,7 +1813,7 @@ static void qeth_l3_free_vlan_addresses(struct qeth_card *card, | |||
| 1813 | static void qeth_l3_vlan_rx_register(struct net_device *dev, | 1813 | static void qeth_l3_vlan_rx_register(struct net_device *dev, |
| 1814 | struct vlan_group *grp) | 1814 | struct vlan_group *grp) |
| 1815 | { | 1815 | { |
| 1816 | struct qeth_card *card = netdev_priv(dev); | 1816 | struct qeth_card *card = dev->ml_priv; |
| 1817 | unsigned long flags; | 1817 | unsigned long flags; |
| 1818 | 1818 | ||
| 1819 | QETH_DBF_TEXT(TRACE, 4, "vlanreg"); | 1819 | QETH_DBF_TEXT(TRACE, 4, "vlanreg"); |
| @@ -1825,7 +1825,7 @@ static void qeth_l3_vlan_rx_register(struct net_device *dev, | |||
| 1825 | static void qeth_l3_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) | 1825 | static void qeth_l3_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) |
| 1826 | { | 1826 | { |
| 1827 | struct net_device *vlandev; | 1827 | struct net_device *vlandev; |
| 1828 | struct qeth_card *card = (struct qeth_card *) dev->priv; | 1828 | struct qeth_card *card = dev->ml_priv; |
| 1829 | struct in_device *in_dev; | 1829 | struct in_device *in_dev; |
| 1830 | 1830 | ||
| 1831 | if (card->info.type == QETH_CARD_TYPE_IQD) | 1831 | if (card->info.type == QETH_CARD_TYPE_IQD) |
| @@ -1851,7 +1851,7 @@ static void qeth_l3_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) | |||
| 1851 | 1851 | ||
| 1852 | static void qeth_l3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) | 1852 | static void qeth_l3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) |
| 1853 | { | 1853 | { |
| 1854 | struct qeth_card *card = netdev_priv(dev); | 1854 | struct qeth_card *card = dev->ml_priv; |
| 1855 | unsigned long flags; | 1855 | unsigned long flags; |
| 1856 | 1856 | ||
| 1857 | QETH_DBF_TEXT_(TRACE, 4, "kid:%d", vid); | 1857 | QETH_DBF_TEXT_(TRACE, 4, "kid:%d", vid); |
| @@ -2013,7 +2013,7 @@ static int qeth_l3_verify_vlan_dev(struct net_device *dev, | |||
| 2013 | } | 2013 | } |
| 2014 | } | 2014 | } |
| 2015 | 2015 | ||
| 2016 | if (rc && !(netdev_priv(vlan_dev_real_dev(dev)) == (void *)card)) | 2016 | if (rc && !(vlan_dev_real_dev(dev)->ml_priv == (void *)card)) |
| 2017 | return 0; | 2017 | return 0; |
| 2018 | 2018 | ||
| 2019 | return rc; | 2019 | return rc; |
| @@ -2047,9 +2047,9 @@ static struct qeth_card *qeth_l3_get_card_from_dev(struct net_device *dev) | |||
| 2047 | 2047 | ||
| 2048 | rc = qeth_l3_verify_dev(dev); | 2048 | rc = qeth_l3_verify_dev(dev); |
| 2049 | if (rc == QETH_REAL_CARD) | 2049 | if (rc == QETH_REAL_CARD) |
| 2050 | card = netdev_priv(dev); | 2050 | card = dev->ml_priv; |
| 2051 | else if (rc == QETH_VLAN_CARD) | 2051 | else if (rc == QETH_VLAN_CARD) |
| 2052 | card = netdev_priv(vlan_dev_real_dev(dev)); | 2052 | card = vlan_dev_real_dev(dev)->ml_priv; |
| 2053 | if (card && card->options.layer2) | 2053 | if (card && card->options.layer2) |
| 2054 | card = NULL; | 2054 | card = NULL; |
| 2055 | QETH_DBF_TEXT_(TRACE, 4, "%d", rc); | 2055 | QETH_DBF_TEXT_(TRACE, 4, "%d", rc); |
| @@ -2110,7 +2110,7 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode) | |||
| 2110 | 2110 | ||
| 2111 | static void qeth_l3_set_multicast_list(struct net_device *dev) | 2111 | static void qeth_l3_set_multicast_list(struct net_device *dev) |
| 2112 | { | 2112 | { |
| 2113 | struct qeth_card *card = netdev_priv(dev); | 2113 | struct qeth_card *card = dev->ml_priv; |
| 2114 | 2114 | ||
| 2115 | QETH_DBF_TEXT(TRACE, 3, "setmulti"); | 2115 | QETH_DBF_TEXT(TRACE, 3, "setmulti"); |
| 2116 | qeth_l3_delete_mc_addresses(card); | 2116 | qeth_l3_delete_mc_addresses(card); |
| @@ -2438,7 +2438,7 @@ static int qeth_l3_arp_flush_cache(struct qeth_card *card) | |||
| 2438 | 2438 | ||
| 2439 | static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | 2439 | static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) |
| 2440 | { | 2440 | { |
| 2441 | struct qeth_card *card = netdev_priv(dev); | 2441 | struct qeth_card *card = dev->ml_priv; |
| 2442 | struct qeth_arp_cache_entry arp_entry; | 2442 | struct qeth_arp_cache_entry arp_entry; |
| 2443 | struct mii_ioctl_data *mii_data; | 2443 | struct mii_ioctl_data *mii_data; |
| 2444 | int rc = 0; | 2444 | int rc = 0; |
| @@ -2595,7 +2595,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 2595 | u16 *tag; | 2595 | u16 *tag; |
| 2596 | struct qeth_hdr *hdr = NULL; | 2596 | struct qeth_hdr *hdr = NULL; |
| 2597 | int elements_needed = 0; | 2597 | int elements_needed = 0; |
| 2598 | struct qeth_card *card = netdev_priv(dev); | 2598 | struct qeth_card *card = dev->ml_priv; |
| 2599 | struct sk_buff *new_skb = NULL; | 2599 | struct sk_buff *new_skb = NULL; |
| 2600 | int ipv = qeth_get_ip_version(skb); | 2600 | int ipv = qeth_get_ip_version(skb); |
| 2601 | int cast_type = qeth_get_cast_type(card, skb); | 2601 | int cast_type = qeth_get_cast_type(card, skb); |
| @@ -2763,7 +2763,7 @@ tx_drop: | |||
| 2763 | 2763 | ||
| 2764 | static int qeth_l3_open(struct net_device *dev) | 2764 | static int qeth_l3_open(struct net_device *dev) |
| 2765 | { | 2765 | { |
| 2766 | struct qeth_card *card = netdev_priv(dev); | 2766 | struct qeth_card *card = dev->ml_priv; |
| 2767 | 2767 | ||
| 2768 | QETH_DBF_TEXT(TRACE, 4, "qethopen"); | 2768 | QETH_DBF_TEXT(TRACE, 4, "qethopen"); |
| 2769 | if (card->state != CARD_STATE_SOFTSETUP) | 2769 | if (card->state != CARD_STATE_SOFTSETUP) |
| @@ -2780,7 +2780,7 @@ static int qeth_l3_open(struct net_device *dev) | |||
| 2780 | 2780 | ||
| 2781 | static int qeth_l3_stop(struct net_device *dev) | 2781 | static int qeth_l3_stop(struct net_device *dev) |
| 2782 | { | 2782 | { |
| 2783 | struct qeth_card *card = netdev_priv(dev); | 2783 | struct qeth_card *card = dev->ml_priv; |
| 2784 | 2784 | ||
| 2785 | QETH_DBF_TEXT(TRACE, 4, "qethstop"); | 2785 | QETH_DBF_TEXT(TRACE, 4, "qethstop"); |
| 2786 | netif_tx_disable(dev); | 2786 | netif_tx_disable(dev); |
| @@ -2792,14 +2792,14 @@ static int qeth_l3_stop(struct net_device *dev) | |||
| 2792 | 2792 | ||
| 2793 | static u32 qeth_l3_ethtool_get_rx_csum(struct net_device *dev) | 2793 | static u32 qeth_l3_ethtool_get_rx_csum(struct net_device *dev) |
| 2794 | { | 2794 | { |
| 2795 | struct qeth_card *card = netdev_priv(dev); | 2795 | struct qeth_card *card = dev->ml_priv; |
| 2796 | 2796 | ||
| 2797 | return (card->options.checksum_type == HW_CHECKSUMMING); | 2797 | return (card->options.checksum_type == HW_CHECKSUMMING); |
| 2798 | } | 2798 | } |
| 2799 | 2799 | ||
| 2800 | static int qeth_l3_ethtool_set_rx_csum(struct net_device *dev, u32 data) | 2800 | static int qeth_l3_ethtool_set_rx_csum(struct net_device *dev, u32 data) |
| 2801 | { | 2801 | { |
| 2802 | struct qeth_card *card = netdev_priv(dev); | 2802 | struct qeth_card *card = dev->ml_priv; |
| 2803 | enum qeth_card_states old_state; | 2803 | enum qeth_card_states old_state; |
| 2804 | enum qeth_checksum_types csum_type; | 2804 | enum qeth_checksum_types csum_type; |
| 2805 | 2805 | ||
| @@ -2825,7 +2825,7 @@ static int qeth_l3_ethtool_set_rx_csum(struct net_device *dev, u32 data) | |||
| 2825 | 2825 | ||
| 2826 | static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data) | 2826 | static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data) |
| 2827 | { | 2827 | { |
| 2828 | struct qeth_card *card = netdev_priv(dev); | 2828 | struct qeth_card *card = dev->ml_priv; |
| 2829 | 2829 | ||
| 2830 | if (data) { | 2830 | if (data) { |
| 2831 | if (card->options.large_send == QETH_LARGE_SEND_NO) { | 2831 | if (card->options.large_send == QETH_LARGE_SEND_NO) { |
| @@ -2915,7 +2915,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) | |||
| 2915 | return -ENODEV; | 2915 | return -ENODEV; |
| 2916 | 2916 | ||
| 2917 | card->dev->hard_start_xmit = qeth_l3_hard_start_xmit; | 2917 | card->dev->hard_start_xmit = qeth_l3_hard_start_xmit; |
| 2918 | card->dev->priv = card; | 2918 | card->dev->ml_priv = card; |
| 2919 | card->dev->tx_timeout = &qeth_tx_timeout; | 2919 | card->dev->tx_timeout = &qeth_tx_timeout; |
| 2920 | card->dev->watchdog_timeo = QETH_TX_TIMEOUT; | 2920 | card->dev->watchdog_timeo = QETH_TX_TIMEOUT; |
| 2921 | card->dev->open = qeth_l3_open; | 2921 | card->dev->open = qeth_l3_open; |
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 7045511f9ad2..b92c19bb6876 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | Written By: Adam Radford <linuxraid@amcc.com> | 4 | Written By: Adam Radford <linuxraid@amcc.com> |
| 5 | Modifications By: Tom Couch <linuxraid@amcc.com> | 5 | Modifications By: Tom Couch <linuxraid@amcc.com> |
| 6 | 6 | ||
| 7 | Copyright (C) 2004-2007 Applied Micro Circuits Corporation. | 7 | Copyright (C) 2004-2008 Applied Micro Circuits Corporation. |
| 8 | 8 | ||
| 9 | This program is free software; you can redistribute it and/or modify | 9 | This program is free software; you can redistribute it and/or modify |
| 10 | it under the terms of the GNU General Public License as published by | 10 | it under the terms of the GNU General Public License as published by |
| @@ -71,6 +71,10 @@ | |||
| 71 | Add support for 9650SE controllers. | 71 | Add support for 9650SE controllers. |
| 72 | 2.26.02.009 - Fix dma mask setting to fallback to 32-bit if 64-bit fails. | 72 | 2.26.02.009 - Fix dma mask setting to fallback to 32-bit if 64-bit fails. |
| 73 | 2.26.02.010 - Add support for 9690SA controllers. | 73 | 2.26.02.010 - Add support for 9690SA controllers. |
| 74 | 2.26.02.011 - Increase max AENs drained to 256. | ||
| 75 | Add MSI support and "use_msi" module parameter. | ||
| 76 | Fix bug in twa_get_param() on 4GB+. | ||
| 77 | Use pci_resource_len() for ioremap(). | ||
| 74 | */ | 78 | */ |
| 75 | 79 | ||
| 76 | #include <linux/module.h> | 80 | #include <linux/module.h> |
| @@ -95,7 +99,7 @@ | |||
| 95 | #include "3w-9xxx.h" | 99 | #include "3w-9xxx.h" |
| 96 | 100 | ||
| 97 | /* Globals */ | 101 | /* Globals */ |
| 98 | #define TW_DRIVER_VERSION "2.26.02.010" | 102 | #define TW_DRIVER_VERSION "2.26.02.011" |
| 99 | static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT]; | 103 | static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT]; |
| 100 | static unsigned int twa_device_extension_count; | 104 | static unsigned int twa_device_extension_count; |
| 101 | static int twa_major = -1; | 105 | static int twa_major = -1; |
| @@ -107,6 +111,10 @@ MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver"); | |||
| 107 | MODULE_LICENSE("GPL"); | 111 | MODULE_LICENSE("GPL"); |
| 108 | MODULE_VERSION(TW_DRIVER_VERSION); | 112 | MODULE_VERSION(TW_DRIVER_VERSION); |
| 109 | 113 | ||
| 114 | static int use_msi = 0; | ||
| 115 | module_param(use_msi, int, S_IRUGO); | ||
| 116 | MODULE_PARM_DESC(use_msi, "Use Message Signaled Interrupts. Default: 0"); | ||
| 117 | |||
| 110 | /* Function prototypes */ | 118 | /* Function prototypes */ |
| 111 | static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header); | 119 | static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header); |
| 112 | static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id); | 120 | static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id); |
| @@ -1038,7 +1046,6 @@ static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int tabl | |||
| 1038 | TW_Command_Full *full_command_packet; | 1046 | TW_Command_Full *full_command_packet; |
| 1039 | TW_Command *command_packet; | 1047 | TW_Command *command_packet; |
| 1040 | TW_Param_Apache *param; | 1048 | TW_Param_Apache *param; |
| 1041 | unsigned long param_value; | ||
| 1042 | void *retval = NULL; | 1049 | void *retval = NULL; |
| 1043 | 1050 | ||
| 1044 | /* Setup the command packet */ | 1051 | /* Setup the command packet */ |
| @@ -1057,9 +1064,8 @@ static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int tabl | |||
| 1057 | param->table_id = cpu_to_le16(table_id | 0x8000); | 1064 | param->table_id = cpu_to_le16(table_id | 0x8000); |
| 1058 | param->parameter_id = cpu_to_le16(parameter_id); | 1065 | param->parameter_id = cpu_to_le16(parameter_id); |
| 1059 | param->parameter_size_bytes = cpu_to_le16(parameter_size_bytes); | 1066 | param->parameter_size_bytes = cpu_to_le16(parameter_size_bytes); |
| 1060 | param_value = tw_dev->generic_buffer_phys[request_id]; | ||
| 1061 | 1067 | ||
| 1062 | command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(param_value); | 1068 | command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); |
| 1063 | command_packet->byte8_offset.param.sgl[0].length = cpu_to_le32(TW_SECTOR_SIZE); | 1069 | command_packet->byte8_offset.param.sgl[0].length = cpu_to_le32(TW_SECTOR_SIZE); |
| 1064 | 1070 | ||
| 1065 | /* Post the command packet to the board */ | 1071 | /* Post the command packet to the board */ |
| @@ -2000,7 +2006,7 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id | |||
| 2000 | { | 2006 | { |
| 2001 | struct Scsi_Host *host = NULL; | 2007 | struct Scsi_Host *host = NULL; |
| 2002 | TW_Device_Extension *tw_dev; | 2008 | TW_Device_Extension *tw_dev; |
| 2003 | u32 mem_addr; | 2009 | unsigned long mem_addr, mem_len; |
| 2004 | int retval = -ENODEV; | 2010 | int retval = -ENODEV; |
| 2005 | 2011 | ||
| 2006 | retval = pci_enable_device(pdev); | 2012 | retval = pci_enable_device(pdev); |
| @@ -2045,13 +2051,16 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id | |||
| 2045 | goto out_free_device_extension; | 2051 | goto out_free_device_extension; |
| 2046 | } | 2052 | } |
| 2047 | 2053 | ||
| 2048 | if (pdev->device == PCI_DEVICE_ID_3WARE_9000) | 2054 | if (pdev->device == PCI_DEVICE_ID_3WARE_9000) { |
| 2049 | mem_addr = pci_resource_start(pdev, 1); | 2055 | mem_addr = pci_resource_start(pdev, 1); |
| 2050 | else | 2056 | mem_len = pci_resource_len(pdev, 1); |
| 2057 | } else { | ||
| 2051 | mem_addr = pci_resource_start(pdev, 2); | 2058 | mem_addr = pci_resource_start(pdev, 2); |
| 2059 | mem_len = pci_resource_len(pdev, 2); | ||
| 2060 | } | ||
| 2052 | 2061 | ||
| 2053 | /* Save base address */ | 2062 | /* Save base address */ |
| 2054 | tw_dev->base_addr = ioremap(mem_addr, PAGE_SIZE); | 2063 | tw_dev->base_addr = ioremap(mem_addr, mem_len); |
| 2055 | if (!tw_dev->base_addr) { | 2064 | if (!tw_dev->base_addr) { |
| 2056 | TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap"); | 2065 | TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap"); |
| 2057 | goto out_release_mem_region; | 2066 | goto out_release_mem_region; |
| @@ -2086,7 +2095,7 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id | |||
| 2086 | 2095 | ||
| 2087 | pci_set_drvdata(pdev, host); | 2096 | pci_set_drvdata(pdev, host); |
| 2088 | 2097 | ||
| 2089 | printk(KERN_WARNING "3w-9xxx: scsi%d: Found a 3ware 9000 Storage Controller at 0x%x, IRQ: %d.\n", | 2098 | printk(KERN_WARNING "3w-9xxx: scsi%d: Found a 3ware 9000 Storage Controller at 0x%lx, IRQ: %d.\n", |
| 2090 | host->host_no, mem_addr, pdev->irq); | 2099 | host->host_no, mem_addr, pdev->irq); |
| 2091 | printk(KERN_WARNING "3w-9xxx: scsi%d: Firmware %s, BIOS %s, Ports: %d.\n", | 2100 | printk(KERN_WARNING "3w-9xxx: scsi%d: Firmware %s, BIOS %s, Ports: %d.\n", |
| 2092 | host->host_no, | 2101 | host->host_no, |
| @@ -2097,6 +2106,11 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id | |||
| 2097 | le32_to_cpu(*(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE, | 2106 | le32_to_cpu(*(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE, |
| 2098 | TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH))); | 2107 | TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH))); |
| 2099 | 2108 | ||
| 2109 | /* Try to enable MSI */ | ||
| 2110 | if (use_msi && (pdev->device != PCI_DEVICE_ID_3WARE_9000) && | ||
| 2111 | !pci_enable_msi(pdev)) | ||
| 2112 | set_bit(TW_USING_MSI, &tw_dev->flags); | ||
| 2113 | |||
| 2100 | /* Now setup the interrupt handler */ | 2114 | /* Now setup the interrupt handler */ |
| 2101 | retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev); | 2115 | retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev); |
| 2102 | if (retval) { | 2116 | if (retval) { |
| @@ -2120,6 +2134,8 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id | |||
| 2120 | return 0; | 2134 | return 0; |
| 2121 | 2135 | ||
| 2122 | out_remove_host: | 2136 | out_remove_host: |
| 2137 | if (test_bit(TW_USING_MSI, &tw_dev->flags)) | ||
| 2138 | pci_disable_msi(pdev); | ||
| 2123 | scsi_remove_host(host); | 2139 | scsi_remove_host(host); |
| 2124 | out_iounmap: | 2140 | out_iounmap: |
| 2125 | iounmap(tw_dev->base_addr); | 2141 | iounmap(tw_dev->base_addr); |
| @@ -2151,6 +2167,10 @@ static void twa_remove(struct pci_dev *pdev) | |||
| 2151 | /* Shutdown the card */ | 2167 | /* Shutdown the card */ |
| 2152 | __twa_shutdown(tw_dev); | 2168 | __twa_shutdown(tw_dev); |
| 2153 | 2169 | ||
| 2170 | /* Disable MSI if enabled */ | ||
| 2171 | if (test_bit(TW_USING_MSI, &tw_dev->flags)) | ||
| 2172 | pci_disable_msi(pdev); | ||
| 2173 | |||
| 2154 | /* Free IO remapping */ | 2174 | /* Free IO remapping */ |
| 2155 | iounmap(tw_dev->base_addr); | 2175 | iounmap(tw_dev->base_addr); |
| 2156 | 2176 | ||
diff --git a/drivers/scsi/3w-9xxx.h b/drivers/scsi/3w-9xxx.h index d14a9479e389..1729a8785fea 100644 --- a/drivers/scsi/3w-9xxx.h +++ b/drivers/scsi/3w-9xxx.h | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | Written By: Adam Radford <linuxraid@amcc.com> | 4 | Written By: Adam Radford <linuxraid@amcc.com> |
| 5 | Modifications By: Tom Couch <linuxraid@amcc.com> | 5 | Modifications By: Tom Couch <linuxraid@amcc.com> |
| 6 | 6 | ||
| 7 | Copyright (C) 2004-2007 Applied Micro Circuits Corporation. | 7 | Copyright (C) 2004-2008 Applied Micro Circuits Corporation. |
| 8 | 8 | ||
| 9 | This program is free software; you can redistribute it and/or modify | 9 | This program is free software; you can redistribute it and/or modify |
| 10 | it under the terms of the GNU General Public License as published by | 10 | it under the terms of the GNU General Public License as published by |
| @@ -319,8 +319,8 @@ static twa_message_type twa_error_table[] = { | |||
| 319 | 319 | ||
| 320 | /* Compatibility defines */ | 320 | /* Compatibility defines */ |
| 321 | #define TW_9000_ARCH_ID 0x5 | 321 | #define TW_9000_ARCH_ID 0x5 |
| 322 | #define TW_CURRENT_DRIVER_SRL 30 | 322 | #define TW_CURRENT_DRIVER_SRL 35 |
| 323 | #define TW_CURRENT_DRIVER_BUILD 80 | 323 | #define TW_CURRENT_DRIVER_BUILD 0 |
| 324 | #define TW_CURRENT_DRIVER_BRANCH 0 | 324 | #define TW_CURRENT_DRIVER_BRANCH 0 |
| 325 | 325 | ||
| 326 | /* Phase defines */ | 326 | /* Phase defines */ |
| @@ -352,8 +352,9 @@ static twa_message_type twa_error_table[] = { | |||
| 352 | #define TW_MAX_RESET_TRIES 2 | 352 | #define TW_MAX_RESET_TRIES 2 |
| 353 | #define TW_MAX_CMDS_PER_LUN 254 | 353 | #define TW_MAX_CMDS_PER_LUN 254 |
| 354 | #define TW_MAX_RESPONSE_DRAIN 256 | 354 | #define TW_MAX_RESPONSE_DRAIN 256 |
| 355 | #define TW_MAX_AEN_DRAIN 40 | 355 | #define TW_MAX_AEN_DRAIN 255 |
| 356 | #define TW_IN_RESET 2 | 356 | #define TW_IN_RESET 2 |
| 357 | #define TW_USING_MSI 3 | ||
| 357 | #define TW_IN_ATTENTION_LOOP 4 | 358 | #define TW_IN_ATTENTION_LOOP 4 |
| 358 | #define TW_MAX_SECTORS 256 | 359 | #define TW_MAX_SECTORS 256 |
| 359 | #define TW_AEN_WAIT_TIME 1000 | 360 | #define TW_AEN_WAIT_TIME 1000 |
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 26be540d1dd3..c7f06298bd3c 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig | |||
| @@ -63,6 +63,7 @@ comment "SCSI support type (disk, tape, CD-ROM)" | |||
| 63 | config BLK_DEV_SD | 63 | config BLK_DEV_SD |
| 64 | tristate "SCSI disk support" | 64 | tristate "SCSI disk support" |
| 65 | depends on SCSI | 65 | depends on SCSI |
| 66 | select CRC_T10DIF | ||
| 66 | ---help--- | 67 | ---help--- |
| 67 | If you want to use SCSI hard disks, Fibre Channel disks, | 68 | If you want to use SCSI hard disks, Fibre Channel disks, |
| 68 | Serial ATA (SATA) or Parallel ATA (PATA) hard disks, | 69 | Serial ATA (SATA) or Parallel ATA (PATA) hard disks, |
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index a8149677de23..72fd5043cfa1 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile | |||
| @@ -151,6 +151,8 @@ scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o | |||
| 151 | scsi_tgt-y += scsi_tgt_lib.o scsi_tgt_if.o | 151 | scsi_tgt-y += scsi_tgt_lib.o scsi_tgt_if.o |
| 152 | 152 | ||
| 153 | sd_mod-objs := sd.o | 153 | sd_mod-objs := sd.o |
| 154 | sd_mod-$(CONFIG_BLK_DEV_INTEGRITY) += sd_dif.o | ||
| 155 | |||
| 154 | sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o | 156 | sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o |
| 155 | ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \ | 157 | ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \ |
| 156 | := -DCONFIG_NCR53C8XX_PREFETCH -DSCSI_NCR_BIG_ENDIAN \ | 158 | := -DCONFIG_NCR53C8XX_PREFETCH -DSCSI_NCR_BIG_ENDIAN \ |
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 8591585e5cc5..218777bfc143 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c | |||
| @@ -2278,7 +2278,7 @@ do { \ | |||
| 2278 | #define ASC_DBG(lvl, format, arg...) { \ | 2278 | #define ASC_DBG(lvl, format, arg...) { \ |
| 2279 | if (asc_dbglvl >= (lvl)) \ | 2279 | if (asc_dbglvl >= (lvl)) \ |
| 2280 | printk(KERN_DEBUG "%s: %s: " format, DRV_NAME, \ | 2280 | printk(KERN_DEBUG "%s: %s: " format, DRV_NAME, \ |
| 2281 | __FUNCTION__ , ## arg); \ | 2281 | __func__ , ## arg); \ |
| 2282 | } | 2282 | } |
| 2283 | 2283 | ||
| 2284 | #define ASC_DBG_PRT_SCSI_HOST(lvl, s) \ | 2284 | #define ASC_DBG_PRT_SCSI_HOST(lvl, s) \ |
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 0899cb61e3dd..b5a868d85eb4 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c | |||
| @@ -288,20 +288,20 @@ static LIST_HEAD(aha152x_host_list); | |||
| 288 | #define DO_LOCK(flags) \ | 288 | #define DO_LOCK(flags) \ |
| 289 | do { \ | 289 | do { \ |
| 290 | if(spin_is_locked(&QLOCK)) { \ | 290 | if(spin_is_locked(&QLOCK)) { \ |
| 291 | DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \ | 291 | DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __func__, __LINE__, QLOCKER, QLOCKERL); \ |
| 292 | } \ | 292 | } \ |
| 293 | DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \ | 293 | DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \ |
| 294 | spin_lock_irqsave(&QLOCK,flags); \ | 294 | spin_lock_irqsave(&QLOCK,flags); \ |
| 295 | DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \ | 295 | DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \ |
| 296 | QLOCKER=__FUNCTION__; \ | 296 | QLOCKER=__func__; \ |
| 297 | QLOCKERL=__LINE__; \ | 297 | QLOCKERL=__LINE__; \ |
| 298 | } while(0) | 298 | } while(0) |
| 299 | 299 | ||
| 300 | #define DO_UNLOCK(flags) \ | 300 | #define DO_UNLOCK(flags) \ |
| 301 | do { \ | 301 | do { \ |
| 302 | DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \ | 302 | DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __func__, __LINE__, QLOCKER, QLOCKERL); \ |
| 303 | spin_unlock_irqrestore(&QLOCK,flags); \ | 303 | spin_unlock_irqrestore(&QLOCK,flags); \ |
| 304 | DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \ | 304 | DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \ |
| 305 | QLOCKER="(not locked)"; \ | 305 | QLOCKER="(not locked)"; \ |
| 306 | QLOCKERL=0; \ | 306 | QLOCKERL=0; \ |
| 307 | } while(0) | 307 | } while(0) |
diff --git a/drivers/scsi/aic94xx/aic94xx.h b/drivers/scsi/aic94xx/aic94xx.h index 2ef459e9cda1..2863a9d22851 100644 --- a/drivers/scsi/aic94xx/aic94xx.h +++ b/drivers/scsi/aic94xx/aic94xx.h | |||
| @@ -39,9 +39,9 @@ | |||
| 39 | 39 | ||
| 40 | #ifdef ASD_ENTER_EXIT | 40 | #ifdef ASD_ENTER_EXIT |
| 41 | #define ENTER printk(KERN_NOTICE "%s: ENTER %s\n", ASD_DRIVER_NAME, \ | 41 | #define ENTER printk(KERN_NOTICE "%s: ENTER %s\n", ASD_DRIVER_NAME, \ |
| 42 | __FUNCTION__) | 42 | __func__) |
| 43 | #define EXIT printk(KERN_NOTICE "%s: --EXIT %s\n", ASD_DRIVER_NAME, \ | 43 | #define EXIT printk(KERN_NOTICE "%s: --EXIT %s\n", ASD_DRIVER_NAME, \ |
| 44 | __FUNCTION__) | 44 | __func__) |
| 45 | #else | 45 | #else |
| 46 | #define ENTER | 46 | #define ENTER |
| 47 | #define EXIT | 47 | #define EXIT |
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c index 83a78222896d..eb9dc3195fdf 100644 --- a/drivers/scsi/aic94xx/aic94xx_hwi.c +++ b/drivers/scsi/aic94xx/aic94xx_hwi.c | |||
| @@ -1359,7 +1359,7 @@ int asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask) | |||
| 1359 | struct asd_ascb *ascb_list; | 1359 | struct asd_ascb *ascb_list; |
| 1360 | 1360 | ||
| 1361 | if (!phy_mask) { | 1361 | if (!phy_mask) { |
| 1362 | asd_printk("%s called with phy_mask of 0!?\n", __FUNCTION__); | 1362 | asd_printk("%s called with phy_mask of 0!?\n", __func__); |
| 1363 | return 0; | 1363 | return 0; |
| 1364 | } | 1364 | } |
| 1365 | 1365 | ||
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c index 46643319c520..ca55013b6ae5 100644 --- a/drivers/scsi/aic94xx/aic94xx_scb.c +++ b/drivers/scsi/aic94xx/aic94xx_scb.c | |||
| @@ -211,7 +211,7 @@ static void asd_form_port(struct asd_ha_struct *asd_ha, struct asd_phy *phy) | |||
| 211 | phy->asd_port = port; | 211 | phy->asd_port = port; |
| 212 | } | 212 | } |
| 213 | ASD_DPRINTK("%s: updating phy_mask 0x%x for phy%d\n", | 213 | ASD_DPRINTK("%s: updating phy_mask 0x%x for phy%d\n", |
| 214 | __FUNCTION__, phy->asd_port->phy_mask, sas_phy->id); | 214 | __func__, phy->asd_port->phy_mask, sas_phy->id); |
| 215 | asd_update_port_links(asd_ha, phy); | 215 | asd_update_port_links(asd_ha, phy); |
| 216 | spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags); | 216 | spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags); |
| 217 | } | 217 | } |
| @@ -294,7 +294,7 @@ static void asd_link_reset_err_tasklet(struct asd_ascb *ascb, | |||
| 294 | struct asd_ascb *cp = asd_ascb_alloc_list(ascb->ha, &num, | 294 | struct asd_ascb *cp = asd_ascb_alloc_list(ascb->ha, &num, |
| 295 | GFP_ATOMIC); | 295 | GFP_ATOMIC); |
| 296 | if (!cp) { | 296 | if (!cp) { |
| 297 | asd_printk("%s: out of memory\n", __FUNCTION__); | 297 | asd_printk("%s: out of memory\n", __func__); |
| 298 | goto out; | 298 | goto out; |
| 299 | } | 299 | } |
| 300 | ASD_DPRINTK("phy%d: retries:0 performing link reset seq\n", | 300 | ASD_DPRINTK("phy%d: retries:0 performing link reset seq\n", |
| @@ -446,7 +446,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb, | |||
| 446 | struct domain_device *failed_dev = NULL; | 446 | struct domain_device *failed_dev = NULL; |
| 447 | 447 | ||
| 448 | ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n", | 448 | ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n", |
| 449 | __FUNCTION__, dl->status_block[3]); | 449 | __func__, dl->status_block[3]); |
| 450 | 450 | ||
| 451 | /* | 451 | /* |
| 452 | * Find the task that caused the abort and abort it first. | 452 | * Find the task that caused the abort and abort it first. |
| @@ -474,7 +474,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb, | |||
| 474 | 474 | ||
| 475 | if (!failed_dev) { | 475 | if (!failed_dev) { |
| 476 | ASD_DPRINTK("%s: Can't find task (tc=%d) to abort!\n", | 476 | ASD_DPRINTK("%s: Can't find task (tc=%d) to abort!\n", |
| 477 | __FUNCTION__, tc_abort); | 477 | __func__, tc_abort); |
| 478 | goto out; | 478 | goto out; |
| 479 | } | 479 | } |
| 480 | 480 | ||
| @@ -502,7 +502,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb, | |||
| 502 | conn_handle = *((u16*)(&dl->status_block[1])); | 502 | conn_handle = *((u16*)(&dl->status_block[1])); |
| 503 | conn_handle = le16_to_cpu(conn_handle); | 503 | conn_handle = le16_to_cpu(conn_handle); |
| 504 | 504 | ||
| 505 | ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __FUNCTION__, | 505 | ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __func__, |
| 506 | dl->status_block[3]); | 506 | dl->status_block[3]); |
| 507 | 507 | ||
| 508 | /* Find the last pending task for the device... */ | 508 | /* Find the last pending task for the device... */ |
| @@ -522,7 +522,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb, | |||
| 522 | 522 | ||
| 523 | if (!last_dev_task) { | 523 | if (!last_dev_task) { |
| 524 | ASD_DPRINTK("%s: Device reset for idle device %d?\n", | 524 | ASD_DPRINTK("%s: Device reset for idle device %d?\n", |
| 525 | __FUNCTION__, conn_handle); | 525 | __func__, conn_handle); |
| 526 | goto out; | 526 | goto out; |
| 527 | } | 527 | } |
| 528 | 528 | ||
| @@ -549,10 +549,10 @@ static void escb_tasklet_complete(struct asd_ascb *ascb, | |||
| 549 | goto out; | 549 | goto out; |
| 550 | } | 550 | } |
| 551 | case SIGNAL_NCQ_ERROR: | 551 | case SIGNAL_NCQ_ERROR: |
| 552 | ASD_DPRINTK("%s: SIGNAL_NCQ_ERROR\n", __FUNCTION__); | 552 | ASD_DPRINTK("%s: SIGNAL_NCQ_ERROR\n", __func__); |
| 553 | goto out; | 553 | goto out; |
| 554 | case CLEAR_NCQ_ERROR: | 554 | case CLEAR_NCQ_ERROR: |
| 555 | ASD_DPRINTK("%s: CLEAR_NCQ_ERROR\n", __FUNCTION__); | 555 | ASD_DPRINTK("%s: CLEAR_NCQ_ERROR\n", __func__); |
| 556 | goto out; | 556 | goto out; |
| 557 | } | 557 | } |
| 558 | 558 | ||
| @@ -560,26 +560,26 @@ static void escb_tasklet_complete(struct asd_ascb *ascb, | |||
| 560 | 560 | ||
| 561 | switch (sb_opcode) { | 561 | switch (sb_opcode) { |
| 562 | case BYTES_DMAED: | 562 | case BYTES_DMAED: |
| 563 | ASD_DPRINTK("%s: phy%d: BYTES_DMAED\n", __FUNCTION__, phy_id); | 563 | ASD_DPRINTK("%s: phy%d: BYTES_DMAED\n", __func__, phy_id); |
| 564 | asd_bytes_dmaed_tasklet(ascb, dl, edb, phy_id); | 564 | asd_bytes_dmaed_tasklet(ascb, dl, edb, phy_id); |
| 565 | break; | 565 | break; |
| 566 | case PRIMITIVE_RECVD: | 566 | case PRIMITIVE_RECVD: |
| 567 | ASD_DPRINTK("%s: phy%d: PRIMITIVE_RECVD\n", __FUNCTION__, | 567 | ASD_DPRINTK("%s: phy%d: PRIMITIVE_RECVD\n", __func__, |
| 568 | phy_id); | 568 | phy_id); |
| 569 | asd_primitive_rcvd_tasklet(ascb, dl, phy_id); | 569 | asd_primitive_rcvd_tasklet(ascb, dl, phy_id); |
| 570 | break; | 570 | break; |
| 571 | case PHY_EVENT: | 571 | case PHY_EVENT: |
| 572 | ASD_DPRINTK("%s: phy%d: PHY_EVENT\n", __FUNCTION__, phy_id); | 572 | ASD_DPRINTK("%s: phy%d: PHY_EVENT\n", __func__, phy_id); |
| 573 | asd_phy_event_tasklet(ascb, dl); | 573 | asd_phy_event_tasklet(ascb, dl); |
| 574 | break; | 574 | break; |
| 575 | case LINK_RESET_ERROR: | 575 | case LINK_RESET_ERROR: |
| 576 | ASD_DPRINTK("%s: phy%d: LINK_RESET_ERROR\n", __FUNCTION__, | 576 | ASD_DPRINTK("%s: phy%d: LINK_RESET_ERROR\n", __func__, |
| 577 | phy_id); | 577 | phy_id); |
| 578 | asd_link_reset_err_tasklet(ascb, dl, phy_id); | 578 | asd_link_reset_err_tasklet(ascb, dl, phy_id); |
| 579 | break; | 579 | break; |
| 580 | case TIMER_EVENT: | 580 | case TIMER_EVENT: |
| 581 | ASD_DPRINTK("%s: phy%d: TIMER_EVENT, lost dw sync\n", | 581 | ASD_DPRINTK("%s: phy%d: TIMER_EVENT, lost dw sync\n", |
| 582 | __FUNCTION__, phy_id); | 582 | __func__, phy_id); |
| 583 | asd_turn_led(asd_ha, phy_id, 0); | 583 | asd_turn_led(asd_ha, phy_id, 0); |
| 584 | /* the device is gone */ | 584 | /* the device is gone */ |
| 585 | sas_phy_disconnected(sas_phy); | 585 | sas_phy_disconnected(sas_phy); |
| @@ -587,7 +587,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb, | |||
| 587 | sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT); | 587 | sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT); |
| 588 | break; | 588 | break; |
| 589 | default: | 589 | default: |
| 590 | ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __FUNCTION__, | 590 | ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __func__, |
| 591 | phy_id, sb_opcode); | 591 | phy_id, sb_opcode); |
| 592 | ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n", | 592 | ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n", |
| 593 | edb, dl->opcode); | 593 | edb, dl->opcode); |
| @@ -654,7 +654,7 @@ static void control_phy_tasklet_complete(struct asd_ascb *ascb, | |||
| 654 | 654 | ||
| 655 | if (status != 0) { | 655 | if (status != 0) { |
| 656 | ASD_DPRINTK("%s: phy%d status block opcode:0x%x\n", | 656 | ASD_DPRINTK("%s: phy%d status block opcode:0x%x\n", |
| 657 | __FUNCTION__, phy_id, status); | 657 | __func__, phy_id, status); |
| 658 | goto out; | 658 | goto out; |
| 659 | } | 659 | } |
| 660 | 660 | ||
| @@ -663,7 +663,7 @@ static void control_phy_tasklet_complete(struct asd_ascb *ascb, | |||
| 663 | asd_ha->hw_prof.enabled_phys &= ~(1 << phy_id); | 663 | asd_ha->hw_prof.enabled_phys &= ~(1 << phy_id); |
| 664 | asd_turn_led(asd_ha, phy_id, 0); | 664 | asd_turn_led(asd_ha, phy_id, 0); |
| 665 | asd_control_led(asd_ha, phy_id, 0); | 665 | asd_control_led(asd_ha, phy_id, 0); |
| 666 | ASD_DPRINTK("%s: disable phy%d\n", __FUNCTION__, phy_id); | 666 | ASD_DPRINTK("%s: disable phy%d\n", __func__, phy_id); |
| 667 | break; | 667 | break; |
| 668 | 668 | ||
| 669 | case ENABLE_PHY: | 669 | case ENABLE_PHY: |
| @@ -673,40 +673,40 @@ static void control_phy_tasklet_complete(struct asd_ascb *ascb, | |||
| 673 | get_lrate_mode(phy, oob_mode); | 673 | get_lrate_mode(phy, oob_mode); |
| 674 | asd_turn_led(asd_ha, phy_id, 1); | 674 | asd_turn_led(asd_ha, phy_id, 1); |
| 675 | ASD_DPRINTK("%s: phy%d, lrate:0x%x, proto:0x%x\n", | 675 | ASD_DPRINTK("%s: phy%d, lrate:0x%x, proto:0x%x\n", |
| 676 | __FUNCTION__, phy_id,phy->sas_phy.linkrate, | 676 | __func__, phy_id,phy->sas_phy.linkrate, |
| 677 | phy->sas_phy.iproto); | 677 | phy->sas_phy.iproto); |
| 678 | } else if (oob_status & CURRENT_SPINUP_HOLD) { | 678 | } else if (oob_status & CURRENT_SPINUP_HOLD) { |
| 679 | asd_ha->hw_prof.enabled_phys |= (1 << phy_id); | 679 | asd_ha->hw_prof.enabled_phys |= (1 << phy_id); |
| 680 | asd_turn_led(asd_ha, phy_id, 1); | 680 | asd_turn_led(asd_ha, phy_id, 1); |
| 681 | ASD_DPRINTK("%s: phy%d, spinup hold\n", __FUNCTION__, | 681 | ASD_DPRINTK("%s: phy%d, spinup hold\n", __func__, |
| 682 | phy_id); | 682 | phy_id); |
| 683 | } else if (oob_status & CURRENT_ERR_MASK) { | 683 | } else if (oob_status & CURRENT_ERR_MASK) { |
| 684 | asd_turn_led(asd_ha, phy_id, 0); | 684 | asd_turn_led(asd_ha, phy_id, 0); |
| 685 | ASD_DPRINTK("%s: phy%d: error: oob status:0x%02x\n", | 685 | ASD_DPRINTK("%s: phy%d: error: oob status:0x%02x\n", |
| 686 | __FUNCTION__, phy_id, oob_status); | 686 | __func__, phy_id, oob_status); |
| 687 | } else if (oob_status & (CURRENT_HOT_PLUG_CNCT | 687 | } else if (oob_status & (CURRENT_HOT_PLUG_CNCT |
| 688 | | CURRENT_DEVICE_PRESENT)) { | 688 | | CURRENT_DEVICE_PRESENT)) { |
| 689 | asd_ha->hw_prof.enabled_phys |= (1 << phy_id); | 689 | asd_ha->hw_prof.enabled_phys |= (1 << phy_id); |
| 690 | asd_turn_led(asd_ha, phy_id, 1); | 690 | asd_turn_led(asd_ha, phy_id, 1); |
| 691 | ASD_DPRINTK("%s: phy%d: hot plug or device present\n", | 691 | ASD_DPRINTK("%s: phy%d: hot plug or device present\n", |
| 692 | __FUNCTION__, phy_id); | 692 | __func__, phy_id); |
| 693 | } else { | 693 | } else { |
| 694 | asd_ha->hw_prof.enabled_phys |= (1 << phy_id); | 694 | asd_ha->hw_prof.enabled_phys |= (1 << phy_id); |
| 695 | asd_turn_led(asd_ha, phy_id, 0); | 695 | asd_turn_led(asd_ha, phy_id, 0); |
| 696 | ASD_DPRINTK("%s: phy%d: no device present: " | 696 | ASD_DPRINTK("%s: phy%d: no device present: " |
| 697 | "oob_status:0x%x\n", | 697 | "oob_status:0x%x\n", |
| 698 | __FUNCTION__, phy_id, oob_status); | 698 | __func__, phy_id, oob_status); |
| 699 | } | 699 | } |
| 700 | break; | 700 | break; |
| 701 | case RELEASE_SPINUP_HOLD: | 701 | case RELEASE_SPINUP_HOLD: |
| 702 | case PHY_NO_OP: | 702 | case PHY_NO_OP: |
| 703 | case EXECUTE_HARD_RESET: | 703 | case EXECUTE_HARD_RESET: |
| 704 | ASD_DPRINTK("%s: phy%d: sub_func:0x%x\n", __FUNCTION__, | 704 | ASD_DPRINTK("%s: phy%d: sub_func:0x%x\n", __func__, |
| 705 | phy_id, control_phy->sub_func); | 705 | phy_id, control_phy->sub_func); |
| 706 | /* XXX finish */ | 706 | /* XXX finish */ |
| 707 | break; | 707 | break; |
| 708 | default: | 708 | default: |
| 709 | ASD_DPRINTK("%s: phy%d: sub_func:0x%x?\n", __FUNCTION__, | 709 | ASD_DPRINTK("%s: phy%d: sub_func:0x%x?\n", __func__, |
| 710 | phy_id, control_phy->sub_func); | 710 | phy_id, control_phy->sub_func); |
| 711 | break; | 711 | break; |
| 712 | } | 712 | } |
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c index 326765c9caf8..75d20f72501f 100644 --- a/drivers/scsi/aic94xx/aic94xx_task.c +++ b/drivers/scsi/aic94xx/aic94xx_task.c | |||
| @@ -320,7 +320,7 @@ Again: | |||
| 320 | case TC_RESUME: | 320 | case TC_RESUME: |
| 321 | case TC_PARTIAL_SG_LIST: | 321 | case TC_PARTIAL_SG_LIST: |
| 322 | default: | 322 | default: |
| 323 | ASD_DPRINTK("%s: dl opcode: 0x%x?\n", __FUNCTION__, opcode); | 323 | ASD_DPRINTK("%s: dl opcode: 0x%x?\n", __func__, opcode); |
| 324 | break; | 324 | break; |
| 325 | } | 325 | } |
| 326 | 326 | ||
diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c index 633ff40c736a..d4640ef6d44f 100644 --- a/drivers/scsi/aic94xx/aic94xx_tmf.c +++ b/drivers/scsi/aic94xx/aic94xx_tmf.c | |||
| @@ -75,12 +75,12 @@ static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb, | |||
| 75 | struct done_list_struct *dl) | 75 | struct done_list_struct *dl) |
| 76 | { | 76 | { |
| 77 | struct tasklet_completion_status *tcs = ascb->uldd_task; | 77 | struct tasklet_completion_status *tcs = ascb->uldd_task; |
| 78 | ASD_DPRINTK("%s: here\n", __FUNCTION__); | 78 | ASD_DPRINTK("%s: here\n", __func__); |
| 79 | if (!del_timer(&ascb->timer)) { | 79 | if (!del_timer(&ascb->timer)) { |
| 80 | ASD_DPRINTK("%s: couldn't delete timer\n", __FUNCTION__); | 80 | ASD_DPRINTK("%s: couldn't delete timer\n", __func__); |
| 81 | return; | 81 | return; |
| 82 | } | 82 | } |
| 83 | ASD_DPRINTK("%s: opcode: 0x%x\n", __FUNCTION__, dl->opcode); | 83 | ASD_DPRINTK("%s: opcode: 0x%x\n", __func__, dl->opcode); |
| 84 | tcs->dl_opcode = dl->opcode; | 84 | tcs->dl_opcode = dl->opcode; |
| 85 | complete(ascb->completion); | 85 | complete(ascb->completion); |
| 86 | asd_ascb_free(ascb); | 86 | asd_ascb_free(ascb); |
| @@ -91,7 +91,7 @@ static void asd_clear_nexus_timedout(unsigned long data) | |||
| 91 | struct asd_ascb *ascb = (void *)data; | 91 | struct asd_ascb *ascb = (void *)data; |
| 92 | struct tasklet_completion_status *tcs = ascb->uldd_task; | 92 | struct tasklet_completion_status *tcs = ascb->uldd_task; |
| 93 | 93 | ||
| 94 | ASD_DPRINTK("%s: here\n", __FUNCTION__); | 94 | ASD_DPRINTK("%s: here\n", __func__); |
| 95 | tcs->dl_opcode = TMF_RESP_FUNC_FAILED; | 95 | tcs->dl_opcode = TMF_RESP_FUNC_FAILED; |
| 96 | complete(ascb->completion); | 96 | complete(ascb->completion); |
| 97 | } | 97 | } |
| @@ -103,7 +103,7 @@ static void asd_clear_nexus_timedout(unsigned long data) | |||
| 103 | DECLARE_COMPLETION_ONSTACK(completion); \ | 103 | DECLARE_COMPLETION_ONSTACK(completion); \ |
| 104 | DECLARE_TCS(tcs); \ | 104 | DECLARE_TCS(tcs); \ |
| 105 | \ | 105 | \ |
| 106 | ASD_DPRINTK("%s: PRE\n", __FUNCTION__); \ | 106 | ASD_DPRINTK("%s: PRE\n", __func__); \ |
| 107 | res = 1; \ | 107 | res = 1; \ |
| 108 | ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); \ | 108 | ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); \ |
| 109 | if (!ascb) \ | 109 | if (!ascb) \ |
| @@ -115,12 +115,12 @@ static void asd_clear_nexus_timedout(unsigned long data) | |||
| 115 | scb->header.opcode = CLEAR_NEXUS | 115 | scb->header.opcode = CLEAR_NEXUS |
| 116 | 116 | ||
| 117 | #define CLEAR_NEXUS_POST \ | 117 | #define CLEAR_NEXUS_POST \ |
| 118 | ASD_DPRINTK("%s: POST\n", __FUNCTION__); \ | 118 | ASD_DPRINTK("%s: POST\n", __func__); \ |
| 119 | res = asd_enqueue_internal(ascb, asd_clear_nexus_tasklet_complete, \ | 119 | res = asd_enqueue_internal(ascb, asd_clear_nexus_tasklet_complete, \ |
| 120 | asd_clear_nexus_timedout); \ | 120 | asd_clear_nexus_timedout); \ |
| 121 | if (res) \ | 121 | if (res) \ |
| 122 | goto out_err; \ | 122 | goto out_err; \ |
| 123 | ASD_DPRINTK("%s: clear nexus posted, waiting...\n", __FUNCTION__); \ | 123 | ASD_DPRINTK("%s: clear nexus posted, waiting...\n", __func__); \ |
| 124 | wait_for_completion(&completion); \ | 124 | wait_for_completion(&completion); \ |
| 125 | res = tcs.dl_opcode; \ | 125 | res = tcs.dl_opcode; \ |
| 126 | if (res == TC_NO_ERROR) \ | 126 | if (res == TC_NO_ERROR) \ |
| @@ -417,7 +417,7 @@ int asd_abort_task(struct sas_task *task) | |||
| 417 | if (task->task_state_flags & SAS_TASK_STATE_DONE) { | 417 | if (task->task_state_flags & SAS_TASK_STATE_DONE) { |
| 418 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 418 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
| 419 | res = TMF_RESP_FUNC_COMPLETE; | 419 | res = TMF_RESP_FUNC_COMPLETE; |
| 420 | ASD_DPRINTK("%s: task 0x%p done\n", __FUNCTION__, task); | 420 | ASD_DPRINTK("%s: task 0x%p done\n", __func__, task); |
| 421 | goto out_done; | 421 | goto out_done; |
| 422 | } | 422 | } |
| 423 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 423 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
| @@ -481,7 +481,7 @@ int asd_abort_task(struct sas_task *task) | |||
| 481 | if (task->task_state_flags & SAS_TASK_STATE_DONE) { | 481 | if (task->task_state_flags & SAS_TASK_STATE_DONE) { |
| 482 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 482 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
| 483 | res = TMF_RESP_FUNC_COMPLETE; | 483 | res = TMF_RESP_FUNC_COMPLETE; |
| 484 | ASD_DPRINTK("%s: task 0x%p done\n", __FUNCTION__, task); | 484 | ASD_DPRINTK("%s: task 0x%p done\n", __func__, task); |
| 485 | goto out_done; | 485 | goto out_done; |
| 486 | } | 486 | } |
| 487 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 487 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index a715632e19d4..477542602284 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c | |||
| @@ -240,7 +240,7 @@ static void __fas216_checkmagic(FAS216_Info *info, const char *func) | |||
| 240 | panic("scsi memory space corrupted in %s", func); | 240 | panic("scsi memory space corrupted in %s", func); |
| 241 | } | 241 | } |
| 242 | } | 242 | } |
| 243 | #define fas216_checkmagic(info) __fas216_checkmagic((info), __FUNCTION__) | 243 | #define fas216_checkmagic(info) __fas216_checkmagic((info), __func__) |
| 244 | #else | 244 | #else |
| 245 | #define fas216_checkmagic(info) | 245 | #define fas216_checkmagic(info) |
| 246 | #endif | 246 | #endif |
| @@ -2658,7 +2658,7 @@ int fas216_eh_host_reset(struct scsi_cmnd *SCpnt) | |||
| 2658 | fas216_checkmagic(info); | 2658 | fas216_checkmagic(info); |
| 2659 | 2659 | ||
| 2660 | printk("scsi%d.%c: %s: resetting host\n", | 2660 | printk("scsi%d.%c: %s: resetting host\n", |
| 2661 | info->host->host_no, '0' + SCpnt->device->id, __FUNCTION__); | 2661 | info->host->host_no, '0' + SCpnt->device->id, __func__); |
| 2662 | 2662 | ||
| 2663 | /* | 2663 | /* |
| 2664 | * Reset the SCSI chip. | 2664 | * Reset the SCSI chip. |
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index aa2011b64683..3c257fe0893e 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c | |||
| @@ -930,6 +930,7 @@ static int ch_probe(struct device *dev) | |||
| 930 | if (init) | 930 | if (init) |
| 931 | ch_init_elem(ch); | 931 | ch_init_elem(ch); |
| 932 | 932 | ||
| 933 | dev_set_drvdata(dev, ch); | ||
| 933 | sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name); | 934 | sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name); |
| 934 | 935 | ||
| 935 | return 0; | 936 | return 0; |
diff --git a/drivers/scsi/device_handler/Kconfig b/drivers/scsi/device_handler/Kconfig index 2adc0f666b68..67070257919f 100644 --- a/drivers/scsi/device_handler/Kconfig +++ b/drivers/scsi/device_handler/Kconfig | |||
| @@ -30,3 +30,11 @@ config SCSI_DH_EMC | |||
| 30 | depends on SCSI_DH | 30 | depends on SCSI_DH |
| 31 | help | 31 | help |
| 32 | If you have a EMC CLARiiON select y. Otherwise, say N. | 32 | If you have a EMC CLARiiON select y. Otherwise, say N. |
| 33 | |||
| 34 | config SCSI_DH_ALUA | ||
| 35 | tristate "SPC-3 ALUA Device Handler (EXPERIMENTAL)" | ||
| 36 | depends on SCSI_DH && EXPERIMENTAL | ||
| 37 | help | ||
| 38 | SCSI Device handler for generic SPC-3 Asymmetric Logical Unit | ||
| 39 | Access (ALUA). | ||
| 40 | |||
diff --git a/drivers/scsi/device_handler/Makefile b/drivers/scsi/device_handler/Makefile index 35272e93b1c8..e1d2ea083e15 100644 --- a/drivers/scsi/device_handler/Makefile +++ b/drivers/scsi/device_handler/Makefile | |||
| @@ -5,3 +5,4 @@ obj-$(CONFIG_SCSI_DH) += scsi_dh.o | |||
| 5 | obj-$(CONFIG_SCSI_DH_RDAC) += scsi_dh_rdac.o | 5 | obj-$(CONFIG_SCSI_DH_RDAC) += scsi_dh_rdac.o |
| 6 | obj-$(CONFIG_SCSI_DH_HP_SW) += scsi_dh_hp_sw.o | 6 | obj-$(CONFIG_SCSI_DH_HP_SW) += scsi_dh_hp_sw.o |
| 7 | obj-$(CONFIG_SCSI_DH_EMC) += scsi_dh_emc.o | 7 | obj-$(CONFIG_SCSI_DH_EMC) += scsi_dh_emc.o |
| 8 | obj-$(CONFIG_SCSI_DH_ALUA) += scsi_dh_alua.o | ||
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index ab6c21cd9689..a518f2eff19a 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c | |||
| @@ -24,8 +24,16 @@ | |||
| 24 | #include <scsi/scsi_dh.h> | 24 | #include <scsi/scsi_dh.h> |
| 25 | #include "../scsi_priv.h" | 25 | #include "../scsi_priv.h" |
| 26 | 26 | ||
| 27 | struct scsi_dh_devinfo_list { | ||
| 28 | struct list_head node; | ||
| 29 | char vendor[9]; | ||
| 30 | char model[17]; | ||
| 31 | struct scsi_device_handler *handler; | ||
| 32 | }; | ||
| 33 | |||
| 27 | static DEFINE_SPINLOCK(list_lock); | 34 | static DEFINE_SPINLOCK(list_lock); |
| 28 | static LIST_HEAD(scsi_dh_list); | 35 | static LIST_HEAD(scsi_dh_list); |
| 36 | static LIST_HEAD(scsi_dh_dev_list); | ||
| 29 | 37 | ||
| 30 | static struct scsi_device_handler *get_device_handler(const char *name) | 38 | static struct scsi_device_handler *get_device_handler(const char *name) |
| 31 | { | 39 | { |
| @@ -33,7 +41,7 @@ static struct scsi_device_handler *get_device_handler(const char *name) | |||
| 33 | 41 | ||
| 34 | spin_lock(&list_lock); | 42 | spin_lock(&list_lock); |
| 35 | list_for_each_entry(tmp, &scsi_dh_list, list) { | 43 | list_for_each_entry(tmp, &scsi_dh_list, list) { |
| 36 | if (!strcmp(tmp->name, name)) { | 44 | if (!strncmp(tmp->name, name, strlen(tmp->name))) { |
| 37 | found = tmp; | 45 | found = tmp; |
| 38 | break; | 46 | break; |
| 39 | } | 47 | } |
| @@ -42,11 +50,307 @@ static struct scsi_device_handler *get_device_handler(const char *name) | |||
| 42 | return found; | 50 | return found; |
| 43 | } | 51 | } |
| 44 | 52 | ||
| 53 | |||
| 54 | static struct scsi_device_handler * | ||
| 55 | scsi_dh_cache_lookup(struct scsi_device *sdev) | ||
| 56 | { | ||
| 57 | struct scsi_dh_devinfo_list *tmp; | ||
| 58 | struct scsi_device_handler *found_dh = NULL; | ||
| 59 | |||
| 60 | spin_lock(&list_lock); | ||
| 61 | list_for_each_entry(tmp, &scsi_dh_dev_list, node) { | ||
| 62 | if (!strncmp(sdev->vendor, tmp->vendor, strlen(tmp->vendor)) && | ||
| 63 | !strncmp(sdev->model, tmp->model, strlen(tmp->model))) { | ||
| 64 | found_dh = tmp->handler; | ||
| 65 | break; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | spin_unlock(&list_lock); | ||
| 69 | |||
| 70 | return found_dh; | ||
| 71 | } | ||
| 72 | |||
| 73 | static int scsi_dh_handler_lookup(struct scsi_device_handler *scsi_dh, | ||
| 74 | struct scsi_device *sdev) | ||
| 75 | { | ||
| 76 | int i, found = 0; | ||
| 77 | |||
| 78 | for(i = 0; scsi_dh->devlist[i].vendor; i++) { | ||
| 79 | if (!strncmp(sdev->vendor, scsi_dh->devlist[i].vendor, | ||
| 80 | strlen(scsi_dh->devlist[i].vendor)) && | ||
| 81 | !strncmp(sdev->model, scsi_dh->devlist[i].model, | ||
| 82 | strlen(scsi_dh->devlist[i].model))) { | ||
| 83 | found = 1; | ||
| 84 | break; | ||
| 85 | } | ||
| 86 | } | ||
| 87 | return found; | ||
| 88 | } | ||
| 89 | |||
| 90 | /* | ||
| 91 | * device_handler_match - Attach a device handler to a device | ||
| 92 | * @scsi_dh - The device handler to match against or NULL | ||
| 93 | * @sdev - SCSI device to be tested against @scsi_dh | ||
| 94 | * | ||
| 95 | * Tests @sdev against the device handler @scsi_dh or against | ||
| 96 | * all registered device_handler if @scsi_dh == NULL. | ||
| 97 | * Returns the found device handler or NULL if not found. | ||
| 98 | */ | ||
| 99 | static struct scsi_device_handler * | ||
| 100 | device_handler_match(struct scsi_device_handler *scsi_dh, | ||
| 101 | struct scsi_device *sdev) | ||
| 102 | { | ||
| 103 | struct scsi_device_handler *found_dh = NULL; | ||
| 104 | struct scsi_dh_devinfo_list *tmp; | ||
| 105 | |||
| 106 | found_dh = scsi_dh_cache_lookup(sdev); | ||
| 107 | if (found_dh) | ||
| 108 | return found_dh; | ||
| 109 | |||
| 110 | if (scsi_dh) { | ||
| 111 | if (scsi_dh_handler_lookup(scsi_dh, sdev)) | ||
| 112 | found_dh = scsi_dh; | ||
| 113 | } else { | ||
| 114 | struct scsi_device_handler *tmp_dh; | ||
| 115 | |||
| 116 | spin_lock(&list_lock); | ||
| 117 | list_for_each_entry(tmp_dh, &scsi_dh_list, list) { | ||
| 118 | if (scsi_dh_handler_lookup(tmp_dh, sdev)) | ||
| 119 | found_dh = tmp_dh; | ||
| 120 | } | ||
| 121 | spin_unlock(&list_lock); | ||
| 122 | } | ||
| 123 | |||
| 124 | if (found_dh) { /* If device is found, add it to the cache */ | ||
| 125 | tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); | ||
| 126 | if (tmp) { | ||
| 127 | strncpy(tmp->vendor, sdev->vendor, 8); | ||
| 128 | strncpy(tmp->model, sdev->model, 16); | ||
| 129 | tmp->vendor[8] = '\0'; | ||
| 130 | tmp->model[16] = '\0'; | ||
| 131 | tmp->handler = found_dh; | ||
| 132 | spin_lock(&list_lock); | ||
| 133 | list_add(&tmp->node, &scsi_dh_dev_list); | ||
| 134 | spin_unlock(&list_lock); | ||
| 135 | } else { | ||
| 136 | found_dh = NULL; | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | return found_dh; | ||
| 141 | } | ||
| 142 | |||
| 143 | /* | ||
| 144 | * scsi_dh_handler_attach - Attach a device handler to a device | ||
| 145 | * @sdev - SCSI device the device handler should attach to | ||
| 146 | * @scsi_dh - The device handler to attach | ||
| 147 | */ | ||
| 148 | static int scsi_dh_handler_attach(struct scsi_device *sdev, | ||
| 149 | struct scsi_device_handler *scsi_dh) | ||
| 150 | { | ||
| 151 | int err = 0; | ||
| 152 | |||
| 153 | if (sdev->scsi_dh_data) { | ||
| 154 | if (sdev->scsi_dh_data->scsi_dh != scsi_dh) | ||
| 155 | err = -EBUSY; | ||
| 156 | } else if (scsi_dh->attach) | ||
| 157 | err = scsi_dh->attach(sdev); | ||
| 158 | |||
| 159 | return err; | ||
| 160 | } | ||
| 161 | |||
| 162 | /* | ||
| 163 | * scsi_dh_handler_detach - Detach a device handler from a device | ||
| 164 | * @sdev - SCSI device the device handler should be detached from | ||
| 165 | * @scsi_dh - Device handler to be detached | ||
| 166 | * | ||
| 167 | * Detach from a device handler. If a device handler is specified, | ||
| 168 | * only detach if the currently attached handler matches @scsi_dh. | ||
| 169 | */ | ||
| 170 | static void scsi_dh_handler_detach(struct scsi_device *sdev, | ||
| 171 | struct scsi_device_handler *scsi_dh) | ||
| 172 | { | ||
| 173 | if (!sdev->scsi_dh_data) | ||
| 174 | return; | ||
| 175 | |||
| 176 | if (scsi_dh && scsi_dh != sdev->scsi_dh_data->scsi_dh) | ||
| 177 | return; | ||
| 178 | |||
| 179 | if (!scsi_dh) | ||
| 180 | scsi_dh = sdev->scsi_dh_data->scsi_dh; | ||
| 181 | |||
| 182 | if (scsi_dh && scsi_dh->detach) | ||
| 183 | scsi_dh->detach(sdev); | ||
| 184 | } | ||
| 185 | |||
| 186 | /* | ||
| 187 | * Functions for sysfs attribute 'dh_state' | ||
| 188 | */ | ||
| 189 | static ssize_t | ||
| 190 | store_dh_state(struct device *dev, struct device_attribute *attr, | ||
| 191 | const char *buf, size_t count) | ||
| 192 | { | ||
| 193 | struct scsi_device *sdev = to_scsi_device(dev); | ||
| 194 | struct scsi_device_handler *scsi_dh; | ||
| 195 | int err = -EINVAL; | ||
| 196 | |||
| 197 | if (!sdev->scsi_dh_data) { | ||
| 198 | /* | ||
| 199 | * Attach to a device handler | ||
| 200 | */ | ||
| 201 | if (!(scsi_dh = get_device_handler(buf))) | ||
| 202 | return err; | ||
| 203 | err = scsi_dh_handler_attach(sdev, scsi_dh); | ||
| 204 | } else { | ||
| 205 | scsi_dh = sdev->scsi_dh_data->scsi_dh; | ||
| 206 | if (!strncmp(buf, "detach", 6)) { | ||
| 207 | /* | ||
| 208 | * Detach from a device handler | ||
| 209 | */ | ||
| 210 | scsi_dh_handler_detach(sdev, scsi_dh); | ||
| 211 | err = 0; | ||
| 212 | } else if (!strncmp(buf, "activate", 8)) { | ||
| 213 | /* | ||
| 214 | * Activate a device handler | ||
| 215 | */ | ||
| 216 | if (scsi_dh->activate) | ||
| 217 | err = scsi_dh->activate(sdev); | ||
| 218 | else | ||
| 219 | err = 0; | ||
| 220 | } | ||
| 221 | } | ||
| 222 | |||
| 223 | return err<0?err:count; | ||
| 224 | } | ||
| 225 | |||
| 226 | static ssize_t | ||
| 227 | show_dh_state(struct device *dev, struct device_attribute *attr, char *buf) | ||
| 228 | { | ||
| 229 | struct scsi_device *sdev = to_scsi_device(dev); | ||
| 230 | |||
| 231 | if (!sdev->scsi_dh_data) | ||
| 232 | return snprintf(buf, 20, "detached\n"); | ||
| 233 | |||
| 234 | return snprintf(buf, 20, "%s\n", sdev->scsi_dh_data->scsi_dh->name); | ||
| 235 | } | ||
| 236 | |||
| 237 | static struct device_attribute scsi_dh_state_attr = | ||
| 238 | __ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state, | ||
| 239 | store_dh_state); | ||
| 240 | |||
| 241 | /* | ||
| 242 | * scsi_dh_sysfs_attr_add - Callback for scsi_init_dh | ||
| 243 | */ | ||
| 244 | static int scsi_dh_sysfs_attr_add(struct device *dev, void *data) | ||
| 245 | { | ||
| 246 | struct scsi_device *sdev; | ||
| 247 | int err; | ||
| 248 | |||
| 249 | if (!scsi_is_sdev_device(dev)) | ||
| 250 | return 0; | ||
| 251 | |||
| 252 | sdev = to_scsi_device(dev); | ||
| 253 | |||
| 254 | err = device_create_file(&sdev->sdev_gendev, | ||
| 255 | &scsi_dh_state_attr); | ||
| 256 | |||
| 257 | return 0; | ||
| 258 | } | ||
| 259 | |||
| 260 | /* | ||
| 261 | * scsi_dh_sysfs_attr_remove - Callback for scsi_exit_dh | ||
| 262 | */ | ||
| 263 | static int scsi_dh_sysfs_attr_remove(struct device *dev, void *data) | ||
| 264 | { | ||
| 265 | struct scsi_device *sdev; | ||
| 266 | |||
| 267 | if (!scsi_is_sdev_device(dev)) | ||
| 268 | return 0; | ||
| 269 | |||
| 270 | sdev = to_scsi_device(dev); | ||
| 271 | |||
| 272 | device_remove_file(&sdev->sdev_gendev, | ||
| 273 | &scsi_dh_state_attr); | ||
| 274 | |||
| 275 | return 0; | ||
| 276 | } | ||
| 277 | |||
| 278 | /* | ||
| 279 | * scsi_dh_notifier - notifier chain callback | ||
| 280 | */ | ||
| 281 | static int scsi_dh_notifier(struct notifier_block *nb, | ||
| 282 | unsigned long action, void *data) | ||
| 283 | { | ||
| 284 | struct device *dev = data; | ||
| 285 | struct scsi_device *sdev; | ||
| 286 | int err = 0; | ||
| 287 | struct scsi_device_handler *devinfo = NULL; | ||
| 288 | |||
| 289 | if (!scsi_is_sdev_device(dev)) | ||
| 290 | return 0; | ||
| 291 | |||
| 292 | sdev = to_scsi_device(dev); | ||
| 293 | |||
| 294 | if (action == BUS_NOTIFY_ADD_DEVICE) { | ||
| 295 | devinfo = device_handler_match(NULL, sdev); | ||
| 296 | if (!devinfo) | ||
| 297 | goto out; | ||
| 298 | |||
| 299 | err = scsi_dh_handler_attach(sdev, devinfo); | ||
| 300 | if (!err) | ||
| 301 | err = device_create_file(dev, &scsi_dh_state_attr); | ||
| 302 | } else if (action == BUS_NOTIFY_DEL_DEVICE) { | ||
| 303 | device_remove_file(dev, &scsi_dh_state_attr); | ||
| 304 | scsi_dh_handler_detach(sdev, NULL); | ||
| 305 | } | ||
| 306 | out: | ||
| 307 | return err; | ||
| 308 | } | ||
| 309 | |||
| 310 | /* | ||
| 311 | * scsi_dh_notifier_add - Callback for scsi_register_device_handler | ||
| 312 | */ | ||
| 45 | static int scsi_dh_notifier_add(struct device *dev, void *data) | 313 | static int scsi_dh_notifier_add(struct device *dev, void *data) |
| 46 | { | 314 | { |
| 47 | struct scsi_device_handler *scsi_dh = data; | 315 | struct scsi_device_handler *scsi_dh = data; |
| 316 | struct scsi_device *sdev; | ||
| 317 | |||
| 318 | if (!scsi_is_sdev_device(dev)) | ||
| 319 | return 0; | ||
| 320 | |||
| 321 | if (!get_device(dev)) | ||
| 322 | return 0; | ||
| 323 | |||
| 324 | sdev = to_scsi_device(dev); | ||
| 325 | |||
| 326 | if (device_handler_match(scsi_dh, sdev)) | ||
| 327 | scsi_dh_handler_attach(sdev, scsi_dh); | ||
| 328 | |||
| 329 | put_device(dev); | ||
| 330 | |||
| 331 | return 0; | ||
| 332 | } | ||
| 333 | |||
| 334 | /* | ||
| 335 | * scsi_dh_notifier_remove - Callback for scsi_unregister_device_handler | ||
| 336 | */ | ||
| 337 | static int scsi_dh_notifier_remove(struct device *dev, void *data) | ||
| 338 | { | ||
| 339 | struct scsi_device_handler *scsi_dh = data; | ||
| 340 | struct scsi_device *sdev; | ||
| 341 | |||
| 342 | if (!scsi_is_sdev_device(dev)) | ||
| 343 | return 0; | ||
| 344 | |||
| 345 | if (!get_device(dev)) | ||
| 346 | return 0; | ||
| 347 | |||
| 348 | sdev = to_scsi_device(dev); | ||
| 349 | |||
| 350 | scsi_dh_handler_detach(sdev, scsi_dh); | ||
| 351 | |||
| 352 | put_device(dev); | ||
| 48 | 353 | ||
| 49 | scsi_dh->nb.notifier_call(&scsi_dh->nb, BUS_NOTIFY_ADD_DEVICE, dev); | ||
| 50 | return 0; | 354 | return 0; |
| 51 | } | 355 | } |
| 52 | 356 | ||
| @@ -59,33 +363,19 @@ static int scsi_dh_notifier_add(struct device *dev, void *data) | |||
| 59 | */ | 363 | */ |
| 60 | int scsi_register_device_handler(struct scsi_device_handler *scsi_dh) | 364 | int scsi_register_device_handler(struct scsi_device_handler *scsi_dh) |
| 61 | { | 365 | { |
| 62 | int ret = -EBUSY; | 366 | if (get_device_handler(scsi_dh->name)) |
| 63 | struct scsi_device_handler *tmp; | 367 | return -EBUSY; |
| 64 | 368 | ||
| 65 | tmp = get_device_handler(scsi_dh->name); | ||
| 66 | if (tmp) | ||
| 67 | goto done; | ||
| 68 | |||
| 69 | ret = bus_register_notifier(&scsi_bus_type, &scsi_dh->nb); | ||
| 70 | |||
| 71 | bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add); | ||
| 72 | spin_lock(&list_lock); | 369 | spin_lock(&list_lock); |
| 73 | list_add(&scsi_dh->list, &scsi_dh_list); | 370 | list_add(&scsi_dh->list, &scsi_dh_list); |
| 74 | spin_unlock(&list_lock); | 371 | spin_unlock(&list_lock); |
| 372 | bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add); | ||
| 373 | printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name); | ||
| 75 | 374 | ||
| 76 | done: | 375 | return SCSI_DH_OK; |
| 77 | return ret; | ||
| 78 | } | 376 | } |
| 79 | EXPORT_SYMBOL_GPL(scsi_register_device_handler); | 377 | EXPORT_SYMBOL_GPL(scsi_register_device_handler); |
| 80 | 378 | ||
| 81 | static int scsi_dh_notifier_remove(struct device *dev, void *data) | ||
| 82 | { | ||
| 83 | struct scsi_device_handler *scsi_dh = data; | ||
| 84 | |||
| 85 | scsi_dh->nb.notifier_call(&scsi_dh->nb, BUS_NOTIFY_DEL_DEVICE, dev); | ||
| 86 | return 0; | ||
| 87 | } | ||
| 88 | |||
| 89 | /* | 379 | /* |
| 90 | * scsi_unregister_device_handler - register a device handler personality | 380 | * scsi_unregister_device_handler - register a device handler personality |
| 91 | * module. | 381 | * module. |
| @@ -95,23 +385,26 @@ static int scsi_dh_notifier_remove(struct device *dev, void *data) | |||
| 95 | */ | 385 | */ |
| 96 | int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) | 386 | int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) |
| 97 | { | 387 | { |
| 98 | int ret = -ENODEV; | 388 | struct scsi_dh_devinfo_list *tmp, *pos; |
| 99 | struct scsi_device_handler *tmp; | ||
| 100 | |||
| 101 | tmp = get_device_handler(scsi_dh->name); | ||
| 102 | if (!tmp) | ||
| 103 | goto done; | ||
| 104 | 389 | ||
| 105 | ret = bus_unregister_notifier(&scsi_bus_type, &scsi_dh->nb); | 390 | if (!get_device_handler(scsi_dh->name)) |
| 391 | return -ENODEV; | ||
| 106 | 392 | ||
| 107 | bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, | 393 | bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, |
| 108 | scsi_dh_notifier_remove); | 394 | scsi_dh_notifier_remove); |
| 395 | |||
| 109 | spin_lock(&list_lock); | 396 | spin_lock(&list_lock); |
| 110 | list_del(&scsi_dh->list); | 397 | list_del(&scsi_dh->list); |
| 398 | list_for_each_entry_safe(pos, tmp, &scsi_dh_dev_list, node) { | ||
| 399 | if (pos->handler == scsi_dh) { | ||
| 400 | list_del(&pos->node); | ||
| 401 | kfree(pos); | ||
| 402 | } | ||
| 403 | } | ||
| 111 | spin_unlock(&list_lock); | 404 | spin_unlock(&list_lock); |
| 405 | printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name); | ||
| 112 | 406 | ||
| 113 | done: | 407 | return SCSI_DH_OK; |
| 114 | return ret; | ||
| 115 | } | 408 | } |
| 116 | EXPORT_SYMBOL_GPL(scsi_unregister_device_handler); | 409 | EXPORT_SYMBOL_GPL(scsi_unregister_device_handler); |
| 117 | 410 | ||
| @@ -157,6 +450,97 @@ int scsi_dh_handler_exist(const char *name) | |||
| 157 | } | 450 | } |
| 158 | EXPORT_SYMBOL_GPL(scsi_dh_handler_exist); | 451 | EXPORT_SYMBOL_GPL(scsi_dh_handler_exist); |
| 159 | 452 | ||
| 453 | /* | ||
| 454 | * scsi_dh_handler_attach - Attach device handler | ||
| 455 | * @sdev - sdev the handler should be attached to | ||
| 456 | * @name - name of the handler to attach | ||
| 457 | */ | ||
| 458 | int scsi_dh_attach(struct request_queue *q, const char *name) | ||
| 459 | { | ||
| 460 | unsigned long flags; | ||
| 461 | struct scsi_device *sdev; | ||
| 462 | struct scsi_device_handler *scsi_dh; | ||
| 463 | int err = 0; | ||
| 464 | |||
| 465 | scsi_dh = get_device_handler(name); | ||
| 466 | if (!scsi_dh) | ||
| 467 | return -EINVAL; | ||
| 468 | |||
| 469 | spin_lock_irqsave(q->queue_lock, flags); | ||
| 470 | sdev = q->queuedata; | ||
| 471 | if (!sdev || !get_device(&sdev->sdev_gendev)) | ||
| 472 | err = -ENODEV; | ||
| 473 | spin_unlock_irqrestore(q->queue_lock, flags); | ||
| 474 | |||
| 475 | if (!err) { | ||
| 476 | err = scsi_dh_handler_attach(sdev, scsi_dh); | ||
| 477 | |||
| 478 | put_device(&sdev->sdev_gendev); | ||
| 479 | } | ||
| 480 | return err; | ||
| 481 | } | ||
| 482 | EXPORT_SYMBOL_GPL(scsi_dh_attach); | ||
| 483 | |||
| 484 | /* | ||
| 485 | * scsi_dh_handler_detach - Detach device handler | ||
| 486 | * @sdev - sdev the handler should be detached from | ||
| 487 | * | ||
| 488 | * This function will detach the device handler only | ||
| 489 | * if the sdev is not part of the internal list, ie | ||
| 490 | * if it has been attached manually. | ||
| 491 | */ | ||
| 492 | void scsi_dh_detach(struct request_queue *q) | ||
| 493 | { | ||
| 494 | unsigned long flags; | ||
| 495 | struct scsi_device *sdev; | ||
| 496 | struct scsi_device_handler *scsi_dh = NULL; | ||
| 497 | |||
| 498 | spin_lock_irqsave(q->queue_lock, flags); | ||
| 499 | sdev = q->queuedata; | ||
| 500 | if (!sdev || !get_device(&sdev->sdev_gendev)) | ||
| 501 | sdev = NULL; | ||
| 502 | spin_unlock_irqrestore(q->queue_lock, flags); | ||
| 503 | |||
| 504 | if (!sdev) | ||
| 505 | return; | ||
| 506 | |||
| 507 | if (sdev->scsi_dh_data) { | ||
| 508 | /* if sdev is not on internal list, detach */ | ||
| 509 | scsi_dh = sdev->scsi_dh_data->scsi_dh; | ||
| 510 | if (!device_handler_match(scsi_dh, sdev)) | ||
| 511 | scsi_dh_handler_detach(sdev, scsi_dh); | ||
| 512 | } | ||
| 513 | put_device(&sdev->sdev_gendev); | ||
| 514 | } | ||
| 515 | EXPORT_SYMBOL_GPL(scsi_dh_detach); | ||
| 516 | |||
| 517 | static struct notifier_block scsi_dh_nb = { | ||
| 518 | .notifier_call = scsi_dh_notifier | ||
| 519 | }; | ||
| 520 | |||
| 521 | static int __init scsi_dh_init(void) | ||
| 522 | { | ||
| 523 | int r; | ||
| 524 | |||
| 525 | r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb); | ||
| 526 | |||
| 527 | if (!r) | ||
| 528 | bus_for_each_dev(&scsi_bus_type, NULL, NULL, | ||
| 529 | scsi_dh_sysfs_attr_add); | ||
| 530 | |||
| 531 | return r; | ||
| 532 | } | ||
| 533 | |||
| 534 | static void __exit scsi_dh_exit(void) | ||
| 535 | { | ||
| 536 | bus_for_each_dev(&scsi_bus_type, NULL, NULL, | ||
| 537 | scsi_dh_sysfs_attr_remove); | ||
| 538 | bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb); | ||
| 539 | } | ||
| 540 | |||
| 541 | module_init(scsi_dh_init); | ||
| 542 | module_exit(scsi_dh_exit); | ||
| 543 | |||
| 160 | MODULE_DESCRIPTION("SCSI device handler"); | 544 | MODULE_DESCRIPTION("SCSI device handler"); |
| 161 | MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>"); | 545 | MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>"); |
| 162 | MODULE_LICENSE("GPL"); | 546 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c new file mode 100644 index 000000000000..fcdd73f25625 --- /dev/null +++ b/drivers/scsi/device_handler/scsi_dh_alua.c | |||
| @@ -0,0 +1,802 @@ | |||
| 1 | /* | ||
| 2 | * Generic SCSI-3 ALUA SCSI Device Handler | ||
| 3 | * | ||
| 4 | * Copyright (C) 2007, 2008 Hannes Reinecke, SUSE Linux Products GmbH. | ||
| 5 | * All rights reserved. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | #include <scsi/scsi.h> | ||
| 23 | #include <scsi/scsi_eh.h> | ||
| 24 | #include <scsi/scsi_dh.h> | ||
| 25 | |||
| 26 | #define ALUA_DH_NAME "alua" | ||
| 27 | #define ALUA_DH_VER "1.2" | ||
| 28 | |||
| 29 | #define TPGS_STATE_OPTIMIZED 0x0 | ||
| 30 | #define TPGS_STATE_NONOPTIMIZED 0x1 | ||
| 31 | #define TPGS_STATE_STANDBY 0x2 | ||
| 32 | #define TPGS_STATE_UNAVAILABLE 0x3 | ||
| 33 | #define TPGS_STATE_OFFLINE 0xe | ||
| 34 | #define TPGS_STATE_TRANSITIONING 0xf | ||
| 35 | |||
| 36 | #define TPGS_SUPPORT_NONE 0x00 | ||
| 37 | #define TPGS_SUPPORT_OPTIMIZED 0x01 | ||
| 38 | #define TPGS_SUPPORT_NONOPTIMIZED 0x02 | ||
| 39 | #define TPGS_SUPPORT_STANDBY 0x04 | ||
| 40 | #define TPGS_SUPPORT_UNAVAILABLE 0x08 | ||
| 41 | #define TPGS_SUPPORT_OFFLINE 0x40 | ||
| 42 | #define TPGS_SUPPORT_TRANSITION 0x80 | ||
| 43 | |||
| 44 | #define TPGS_MODE_UNINITIALIZED -1 | ||
| 45 | #define TPGS_MODE_NONE 0x0 | ||
| 46 | #define TPGS_MODE_IMPLICIT 0x1 | ||
| 47 | #define TPGS_MODE_EXPLICIT 0x2 | ||
| 48 | |||
| 49 | #define ALUA_INQUIRY_SIZE 36 | ||
| 50 | #define ALUA_FAILOVER_TIMEOUT (60 * HZ) | ||
| 51 | #define ALUA_FAILOVER_RETRIES 5 | ||
| 52 | |||
| 53 | struct alua_dh_data { | ||
| 54 | int group_id; | ||
| 55 | int rel_port; | ||
| 56 | int tpgs; | ||
| 57 | int state; | ||
| 58 | unsigned char inq[ALUA_INQUIRY_SIZE]; | ||
| 59 | unsigned char *buff; | ||
| 60 | int bufflen; | ||
| 61 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | ||
| 62 | int senselen; | ||
| 63 | }; | ||
| 64 | |||
| 65 | #define ALUA_POLICY_SWITCH_CURRENT 0 | ||
| 66 | #define ALUA_POLICY_SWITCH_ALL 1 | ||
| 67 | |||
| 68 | static inline struct alua_dh_data *get_alua_data(struct scsi_device *sdev) | ||
| 69 | { | ||
| 70 | struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; | ||
| 71 | BUG_ON(scsi_dh_data == NULL); | ||
| 72 | return ((struct alua_dh_data *) scsi_dh_data->buf); | ||
| 73 | } | ||
| 74 | |||
| 75 | static int realloc_buffer(struct alua_dh_data *h, unsigned len) | ||
| 76 | { | ||
| 77 | if (h->buff && h->buff != h->inq) | ||
| 78 | kfree(h->buff); | ||
| 79 | |||
| 80 | h->buff = kmalloc(len, GFP_NOIO); | ||
| 81 | if (!h->buff) { | ||
| 82 | h->buff = h->inq; | ||
| 83 | h->bufflen = ALUA_INQUIRY_SIZE; | ||
| 84 | return 1; | ||
| 85 | } | ||
| 86 | h->bufflen = len; | ||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | static struct request *get_alua_req(struct scsi_device *sdev, | ||
| 91 | void *buffer, unsigned buflen, int rw) | ||
| 92 | { | ||
| 93 | struct request *rq; | ||
| 94 | struct request_queue *q = sdev->request_queue; | ||
| 95 | |||
| 96 | rq = blk_get_request(q, rw, GFP_NOIO); | ||
| 97 | |||
| 98 | if (!rq) { | ||
| 99 | sdev_printk(KERN_INFO, sdev, | ||
| 100 | "%s: blk_get_request failed\n", __func__); | ||
| 101 | return NULL; | ||
| 102 | } | ||
| 103 | |||
| 104 | if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) { | ||
| 105 | blk_put_request(rq); | ||
| 106 | sdev_printk(KERN_INFO, sdev, | ||
| 107 | "%s: blk_rq_map_kern failed\n", __func__); | ||
| 108 | return NULL; | ||
| 109 | } | ||
| 110 | |||
| 111 | rq->cmd_type = REQ_TYPE_BLOCK_PC; | ||
| 112 | rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; | ||
| 113 | rq->retries = ALUA_FAILOVER_RETRIES; | ||
| 114 | rq->timeout = ALUA_FAILOVER_TIMEOUT; | ||
| 115 | |||
| 116 | return rq; | ||
| 117 | } | ||
| 118 | |||
| 119 | /* | ||
| 120 | * submit_std_inquiry - Issue a standard INQUIRY command | ||
| 121 | * @sdev: sdev the command should be send to | ||
| 122 | */ | ||
| 123 | static int submit_std_inquiry(struct scsi_device *sdev, struct alua_dh_data *h) | ||
| 124 | { | ||
| 125 | struct request *rq; | ||
| 126 | int err = SCSI_DH_RES_TEMP_UNAVAIL; | ||
| 127 | |||
| 128 | rq = get_alua_req(sdev, h->inq, ALUA_INQUIRY_SIZE, READ); | ||
| 129 | if (!rq) | ||
| 130 | goto done; | ||
| 131 | |||
| 132 | /* Prepare the command. */ | ||
| 133 | rq->cmd[0] = INQUIRY; | ||
| 134 | rq->cmd[1] = 0; | ||
| 135 | rq->cmd[2] = 0; | ||
| 136 | rq->cmd[4] = ALUA_INQUIRY_SIZE; | ||
| 137 | rq->cmd_len = COMMAND_SIZE(INQUIRY); | ||
| 138 | |||
| 139 | rq->sense = h->sense; | ||
| 140 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
| 141 | rq->sense_len = h->senselen = 0; | ||
| 142 | |||
| 143 | err = blk_execute_rq(rq->q, NULL, rq, 1); | ||
| 144 | if (err == -EIO) { | ||
| 145 | sdev_printk(KERN_INFO, sdev, | ||
| 146 | "%s: std inquiry failed with %x\n", | ||
| 147 | ALUA_DH_NAME, rq->errors); | ||
| 148 | h->senselen = rq->sense_len; | ||
| 149 | err = SCSI_DH_IO; | ||
| 150 | } | ||
| 151 | blk_put_request(rq); | ||
| 152 | done: | ||
| 153 | return err; | ||
| 154 | } | ||
| 155 | |||
| 156 | /* | ||
| 157 | * submit_vpd_inquiry - Issue an INQUIRY VPD page 0x83 command | ||
| 158 | * @sdev: sdev the command should be sent to | ||
| 159 | */ | ||
| 160 | static int submit_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h) | ||
| 161 | { | ||
| 162 | struct request *rq; | ||
| 163 | int err = SCSI_DH_RES_TEMP_UNAVAIL; | ||
| 164 | |||
| 165 | rq = get_alua_req(sdev, h->buff, h->bufflen, READ); | ||
| 166 | if (!rq) | ||
| 167 | goto done; | ||
| 168 | |||
| 169 | /* Prepare the command. */ | ||
| 170 | rq->cmd[0] = INQUIRY; | ||
| 171 | rq->cmd[1] = 1; | ||
| 172 | rq->cmd[2] = 0x83; | ||
| 173 | rq->cmd[4] = h->bufflen; | ||
| 174 | rq->cmd_len = COMMAND_SIZE(INQUIRY); | ||
| 175 | |||
| 176 | rq->sense = h->sense; | ||
| 177 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
| 178 | rq->sense_len = h->senselen = 0; | ||
| 179 | |||
| 180 | err = blk_execute_rq(rq->q, NULL, rq, 1); | ||
| 181 | if (err == -EIO) { | ||
| 182 | sdev_printk(KERN_INFO, sdev, | ||
| 183 | "%s: evpd inquiry failed with %x\n", | ||
| 184 | ALUA_DH_NAME, rq->errors); | ||
| 185 | h->senselen = rq->sense_len; | ||
| 186 | err = SCSI_DH_IO; | ||
| 187 | } | ||
| 188 | blk_put_request(rq); | ||
| 189 | done: | ||
| 190 | return err; | ||
| 191 | } | ||
| 192 | |||
| 193 | /* | ||
| 194 | * submit_rtpg - Issue a REPORT TARGET GROUP STATES command | ||
| 195 | * @sdev: sdev the command should be sent to | ||
| 196 | */ | ||
| 197 | static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) | ||
| 198 | { | ||
| 199 | struct request *rq; | ||
| 200 | int err = SCSI_DH_RES_TEMP_UNAVAIL; | ||
| 201 | |||
| 202 | rq = get_alua_req(sdev, h->buff, h->bufflen, READ); | ||
| 203 | if (!rq) | ||
| 204 | goto done; | ||
| 205 | |||
| 206 | /* Prepare the command. */ | ||
| 207 | rq->cmd[0] = MAINTENANCE_IN; | ||
| 208 | rq->cmd[1] = MI_REPORT_TARGET_PGS; | ||
| 209 | rq->cmd[6] = (h->bufflen >> 24) & 0xff; | ||
| 210 | rq->cmd[7] = (h->bufflen >> 16) & 0xff; | ||
| 211 | rq->cmd[8] = (h->bufflen >> 8) & 0xff; | ||
| 212 | rq->cmd[9] = h->bufflen & 0xff; | ||
| 213 | rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN); | ||
| 214 | |||
| 215 | rq->sense = h->sense; | ||
| 216 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
| 217 | rq->sense_len = h->senselen = 0; | ||
| 218 | |||
| 219 | err = blk_execute_rq(rq->q, NULL, rq, 1); | ||
| 220 | if (err == -EIO) { | ||
| 221 | sdev_printk(KERN_INFO, sdev, | ||
| 222 | "%s: rtpg failed with %x\n", | ||
| 223 | ALUA_DH_NAME, rq->errors); | ||
| 224 | h->senselen = rq->sense_len; | ||
| 225 | err = SCSI_DH_IO; | ||
| 226 | } | ||
| 227 | blk_put_request(rq); | ||
| 228 | done: | ||
| 229 | return err; | ||
| 230 | } | ||
| 231 | |||
| 232 | /* | ||
| 233 | * submit_stpg - Issue a SET TARGET GROUP STATES command | ||
| 234 | * @sdev: sdev the command should be sent to | ||
| 235 | * | ||
| 236 | * Currently we're only setting the current target port group state | ||
| 237 | * to 'active/optimized' and let the array firmware figure out | ||
| 238 | * the states of the remaining groups. | ||
| 239 | */ | ||
| 240 | static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h) | ||
| 241 | { | ||
| 242 | struct request *rq; | ||
| 243 | int err = SCSI_DH_RES_TEMP_UNAVAIL; | ||
| 244 | int stpg_len = 8; | ||
| 245 | |||
| 246 | /* Prepare the data buffer */ | ||
| 247 | memset(h->buff, 0, stpg_len); | ||
| 248 | h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f; | ||
| 249 | h->buff[6] = (h->group_id >> 8) & 0x0f; | ||
| 250 | h->buff[7] = h->group_id & 0x0f; | ||
| 251 | |||
| 252 | rq = get_alua_req(sdev, h->buff, stpg_len, WRITE); | ||
| 253 | if (!rq) | ||
| 254 | goto done; | ||
| 255 | |||
| 256 | /* Prepare the command. */ | ||
| 257 | rq->cmd[0] = MAINTENANCE_OUT; | ||
| 258 | rq->cmd[1] = MO_SET_TARGET_PGS; | ||
| 259 | rq->cmd[6] = (stpg_len >> 24) & 0xff; | ||
| 260 | rq->cmd[7] = (stpg_len >> 16) & 0xff; | ||
| 261 | rq->cmd[8] = (stpg_len >> 8) & 0xff; | ||
| 262 | rq->cmd[9] = stpg_len & 0xff; | ||
| 263 | rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT); | ||
| 264 | |||
| 265 | rq->sense = h->sense; | ||
| 266 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
| 267 | rq->sense_len = h->senselen = 0; | ||
| 268 | |||
| 269 | err = blk_execute_rq(rq->q, NULL, rq, 1); | ||
| 270 | if (err == -EIO) { | ||
| 271 | sdev_printk(KERN_INFO, sdev, | ||
| 272 | "%s: stpg failed with %x\n", | ||
| 273 | ALUA_DH_NAME, rq->errors); | ||
| 274 | h->senselen = rq->sense_len; | ||
| 275 | err = SCSI_DH_IO; | ||
| 276 | } | ||
| 277 | blk_put_request(rq); | ||
| 278 | done: | ||
| 279 | return err; | ||
| 280 | } | ||
| 281 | |||
| 282 | /* | ||
| 283 | * alua_std_inquiry - Evaluate standard INQUIRY command | ||
| 284 | * @sdev: device to be checked | ||
| 285 | * | ||
| 286 | * Just extract the TPGS setting to find out if ALUA | ||
| 287 | * is supported. | ||
| 288 | */ | ||
| 289 | static int alua_std_inquiry(struct scsi_device *sdev, struct alua_dh_data *h) | ||
| 290 | { | ||
| 291 | int err; | ||
| 292 | |||
| 293 | err = submit_std_inquiry(sdev, h); | ||
| 294 | |||
| 295 | if (err != SCSI_DH_OK) | ||
| 296 | return err; | ||
| 297 | |||
| 298 | /* Check TPGS setting */ | ||
| 299 | h->tpgs = (h->inq[5] >> 4) & 0x3; | ||
| 300 | switch (h->tpgs) { | ||
| 301 | case TPGS_MODE_EXPLICIT|TPGS_MODE_IMPLICIT: | ||
| 302 | sdev_printk(KERN_INFO, sdev, | ||
| 303 | "%s: supports implicit and explicit TPGS\n", | ||
| 304 | ALUA_DH_NAME); | ||
| 305 | break; | ||
| 306 | case TPGS_MODE_EXPLICIT: | ||
| 307 | sdev_printk(KERN_INFO, sdev, "%s: supports explicit TPGS\n", | ||
| 308 | ALUA_DH_NAME); | ||
| 309 | break; | ||
| 310 | case TPGS_MODE_IMPLICIT: | ||
| 311 | sdev_printk(KERN_INFO, sdev, "%s: supports implicit TPGS\n", | ||
| 312 | ALUA_DH_NAME); | ||
| 313 | break; | ||
| 314 | default: | ||
| 315 | h->tpgs = TPGS_MODE_NONE; | ||
| 316 | sdev_printk(KERN_INFO, sdev, "%s: not supported\n", | ||
| 317 | ALUA_DH_NAME); | ||
| 318 | err = SCSI_DH_DEV_UNSUPP; | ||
| 319 | break; | ||
| 320 | } | ||
| 321 | |||
| 322 | return err; | ||
| 323 | } | ||
| 324 | |||
| 325 | /* | ||
| 326 | * alua_vpd_inquiry - Evaluate INQUIRY vpd page 0x83 | ||
| 327 | * @sdev: device to be checked | ||
| 328 | * | ||
| 329 | * Extract the relative target port and the target port group | ||
| 330 | * descriptor from the list of identificators. | ||
| 331 | */ | ||
| 332 | static int alua_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h) | ||
| 333 | { | ||
| 334 | int len; | ||
| 335 | unsigned err; | ||
| 336 | unsigned char *d; | ||
| 337 | |||
| 338 | retry: | ||
| 339 | err = submit_vpd_inquiry(sdev, h); | ||
| 340 | |||
| 341 | if (err != SCSI_DH_OK) | ||
| 342 | return err; | ||
| 343 | |||
| 344 | /* Check if vpd page exceeds initial buffer */ | ||
| 345 | len = (h->buff[2] << 8) + h->buff[3] + 4; | ||
| 346 | if (len > h->bufflen) { | ||
| 347 | /* Resubmit with the correct length */ | ||
| 348 | if (realloc_buffer(h, len)) { | ||
| 349 | sdev_printk(KERN_WARNING, sdev, | ||
| 350 | "%s: kmalloc buffer failed\n", | ||
| 351 | ALUA_DH_NAME); | ||
| 352 | /* Temporary failure, bypass */ | ||
| 353 | return SCSI_DH_DEV_TEMP_BUSY; | ||
| 354 | } | ||
| 355 | goto retry; | ||
| 356 | } | ||
| 357 | |||
| 358 | /* | ||
| 359 | * Now look for the correct descriptor. | ||
| 360 | */ | ||
| 361 | d = h->buff + 4; | ||
| 362 | while (d < h->buff + len) { | ||
| 363 | switch (d[1] & 0xf) { | ||
| 364 | case 0x4: | ||
| 365 | /* Relative target port */ | ||
| 366 | h->rel_port = (d[6] << 8) + d[7]; | ||
| 367 | break; | ||
| 368 | case 0x5: | ||
| 369 | /* Target port group */ | ||
| 370 | h->group_id = (d[6] << 8) + d[7]; | ||
| 371 | break; | ||
| 372 | default: | ||
| 373 | break; | ||
| 374 | } | ||
| 375 | d += d[3] + 4; | ||
| 376 | } | ||
| 377 | |||
| 378 | if (h->group_id == -1) { | ||
| 379 | /* | ||
| 380 | * Internal error; TPGS supported but required | ||
| 381 | * VPD identification descriptors not present. | ||
| 382 | * Disable ALUA support | ||
| 383 | */ | ||
| 384 | sdev_printk(KERN_INFO, sdev, | ||
| 385 | "%s: No target port descriptors found\n", | ||
| 386 | ALUA_DH_NAME); | ||
| 387 | h->state = TPGS_STATE_OPTIMIZED; | ||
| 388 | h->tpgs = TPGS_MODE_NONE; | ||
| 389 | err = SCSI_DH_DEV_UNSUPP; | ||
| 390 | } else { | ||
| 391 | sdev_printk(KERN_INFO, sdev, | ||
| 392 | "%s: port group %02x rel port %02x\n", | ||
| 393 | ALUA_DH_NAME, h->group_id, h->rel_port); | ||
| 394 | } | ||
| 395 | |||
| 396 | return err; | ||
| 397 | } | ||
| 398 | |||
| 399 | static char print_alua_state(int state) | ||
| 400 | { | ||
| 401 | switch (state) { | ||
| 402 | case TPGS_STATE_OPTIMIZED: | ||
| 403 | return 'A'; | ||
| 404 | case TPGS_STATE_NONOPTIMIZED: | ||
| 405 | return 'N'; | ||
| 406 | case TPGS_STATE_STANDBY: | ||
| 407 | return 'S'; | ||
| 408 | case TPGS_STATE_UNAVAILABLE: | ||
| 409 | return 'U'; | ||
| 410 | case TPGS_STATE_OFFLINE: | ||
| 411 | return 'O'; | ||
| 412 | case TPGS_STATE_TRANSITIONING: | ||
| 413 | return 'T'; | ||
| 414 | default: | ||
| 415 | return 'X'; | ||
| 416 | } | ||
| 417 | } | ||
| 418 | |||
| 419 | static int alua_check_sense(struct scsi_device *sdev, | ||
| 420 | struct scsi_sense_hdr *sense_hdr) | ||
| 421 | { | ||
| 422 | switch (sense_hdr->sense_key) { | ||
| 423 | case NOT_READY: | ||
| 424 | if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) | ||
| 425 | /* | ||
| 426 | * LUN Not Accessible - ALUA state transition | ||
| 427 | */ | ||
| 428 | return NEEDS_RETRY; | ||
| 429 | if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0b) | ||
| 430 | /* | ||
| 431 | * LUN Not Accessible -- Target port in standby state | ||
| 432 | */ | ||
| 433 | return SUCCESS; | ||
| 434 | if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0c) | ||
| 435 | /* | ||
| 436 | * LUN Not Accessible -- Target port in unavailable state | ||
| 437 | */ | ||
| 438 | return SUCCESS; | ||
| 439 | if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x12) | ||
| 440 | /* | ||
| 441 | * LUN Not Ready -- Offline | ||
| 442 | */ | ||
| 443 | return SUCCESS; | ||
| 444 | break; | ||
| 445 | case UNIT_ATTENTION: | ||
| 446 | if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) | ||
| 447 | /* | ||
| 448 | * Power On, Reset, or Bus Device Reset, just retry. | ||
| 449 | */ | ||
| 450 | return NEEDS_RETRY; | ||
| 451 | if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) { | ||
| 452 | /* | ||
| 453 | * ALUA state changed | ||
| 454 | */ | ||
| 455 | return NEEDS_RETRY; | ||
| 456 | } | ||
| 457 | if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) { | ||
| 458 | /* | ||
| 459 | * Implicit ALUA state transition failed | ||
| 460 | */ | ||
| 461 | return NEEDS_RETRY; | ||
| 462 | } | ||
| 463 | break; | ||
| 464 | } | ||
| 465 | |||
| 466 | return SCSI_RETURN_NOT_HANDLED; | ||
| 467 | } | ||
| 468 | |||
| 469 | /* | ||
| 470 | * alua_stpg - Evaluate SET TARGET GROUP STATES | ||
| 471 | * @sdev: the device to be evaluated | ||
| 472 | * @state: the new target group state | ||
| 473 | * | ||
| 474 | * Send a SET TARGET GROUP STATES command to the device. | ||
| 475 | * We only have to test here if we should resubmit the command; | ||
| 476 | * any other error is assumed as a failure. | ||
| 477 | */ | ||
| 478 | static int alua_stpg(struct scsi_device *sdev, int state, | ||
| 479 | struct alua_dh_data *h) | ||
| 480 | { | ||
| 481 | struct scsi_sense_hdr sense_hdr; | ||
| 482 | unsigned err; | ||
| 483 | int retry = ALUA_FAILOVER_RETRIES; | ||
| 484 | |||
| 485 | retry: | ||
| 486 | err = submit_stpg(sdev, h); | ||
| 487 | if (err == SCSI_DH_IO && h->senselen > 0) { | ||
| 488 | err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, | ||
| 489 | &sense_hdr); | ||
| 490 | if (!err) | ||
| 491 | return SCSI_DH_IO; | ||
| 492 | err = alua_check_sense(sdev, &sense_hdr); | ||
| 493 | if (retry > 0 && err == NEEDS_RETRY) { | ||
| 494 | retry--; | ||
| 495 | goto retry; | ||
| 496 | } | ||
| 497 | sdev_printk(KERN_INFO, sdev, | ||
| 498 | "%s: stpg sense code: %02x/%02x/%02x\n", | ||
| 499 | ALUA_DH_NAME, sense_hdr.sense_key, | ||
| 500 | sense_hdr.asc, sense_hdr.ascq); | ||
| 501 | err = SCSI_DH_IO; | ||
| 502 | } | ||
| 503 | if (err == SCSI_DH_OK) { | ||
| 504 | h->state = state; | ||
| 505 | sdev_printk(KERN_INFO, sdev, | ||
| 506 | "%s: port group %02x switched to state %c\n", | ||
| 507 | ALUA_DH_NAME, h->group_id, | ||
| 508 | print_alua_state(h->state) ); | ||
| 509 | } | ||
| 510 | return err; | ||
| 511 | } | ||
| 512 | |||
| 513 | /* | ||
| 514 | * alua_rtpg - Evaluate REPORT TARGET GROUP STATES | ||
| 515 | * @sdev: the device to be evaluated. | ||
| 516 | * | ||
| 517 | * Evaluate the Target Port Group State. | ||
| 518 | * Returns SCSI_DH_DEV_OFFLINED if the path is | ||
| 519 | * found to be unuseable. | ||
| 520 | */ | ||
| 521 | static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) | ||
| 522 | { | ||
| 523 | struct scsi_sense_hdr sense_hdr; | ||
| 524 | int len, k, off, valid_states = 0; | ||
| 525 | char *ucp; | ||
| 526 | unsigned err; | ||
| 527 | |||
| 528 | retry: | ||
| 529 | err = submit_rtpg(sdev, h); | ||
| 530 | |||
| 531 | if (err == SCSI_DH_IO && h->senselen > 0) { | ||
| 532 | err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, | ||
| 533 | &sense_hdr); | ||
| 534 | if (!err) | ||
| 535 | return SCSI_DH_IO; | ||
| 536 | |||
| 537 | err = alua_check_sense(sdev, &sense_hdr); | ||
| 538 | if (err == NEEDS_RETRY) | ||
| 539 | goto retry; | ||
| 540 | sdev_printk(KERN_INFO, sdev, | ||
| 541 | "%s: rtpg sense code %02x/%02x/%02x\n", | ||
| 542 | ALUA_DH_NAME, sense_hdr.sense_key, | ||
| 543 | sense_hdr.asc, sense_hdr.ascq); | ||
| 544 | err = SCSI_DH_IO; | ||
| 545 | } | ||
| 546 | if (err != SCSI_DH_OK) | ||
| 547 | return err; | ||
| 548 | |||
| 549 | len = (h->buff[0] << 24) + (h->buff[1] << 16) + | ||
| 550 | (h->buff[2] << 8) + h->buff[3] + 4; | ||
| 551 | |||
| 552 | if (len > h->bufflen) { | ||
| 553 | /* Resubmit with the correct length */ | ||
| 554 | if (realloc_buffer(h, len)) { | ||
| 555 | sdev_printk(KERN_WARNING, sdev, | ||
| 556 | "%s: kmalloc buffer failed\n",__func__); | ||
| 557 | /* Temporary failure, bypass */ | ||
| 558 | return SCSI_DH_DEV_TEMP_BUSY; | ||
| 559 | } | ||
| 560 | goto retry; | ||
| 561 | } | ||
| 562 | |||
| 563 | for (k = 4, ucp = h->buff + 4; k < len; k += off, ucp += off) { | ||
| 564 | if (h->group_id == (ucp[2] << 8) + ucp[3]) { | ||
| 565 | h->state = ucp[0] & 0x0f; | ||
| 566 | valid_states = ucp[1]; | ||
| 567 | } | ||
| 568 | off = 8 + (ucp[7] * 4); | ||
| 569 | } | ||
| 570 | |||
| 571 | sdev_printk(KERN_INFO, sdev, | ||
| 572 | "%s: port group %02x state %c supports %c%c%c%c%c%c\n", | ||
| 573 | ALUA_DH_NAME, h->group_id, print_alua_state(h->state), | ||
| 574 | valid_states&TPGS_SUPPORT_TRANSITION?'T':'t', | ||
| 575 | valid_states&TPGS_SUPPORT_OFFLINE?'O':'o', | ||
| 576 | valid_states&TPGS_SUPPORT_UNAVAILABLE?'U':'u', | ||
| 577 | valid_states&TPGS_SUPPORT_STANDBY?'S':'s', | ||
| 578 | valid_states&TPGS_SUPPORT_NONOPTIMIZED?'N':'n', | ||
| 579 | valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a'); | ||
| 580 | |||
| 581 | if (h->tpgs & TPGS_MODE_EXPLICIT) { | ||
| 582 | switch (h->state) { | ||
| 583 | case TPGS_STATE_TRANSITIONING: | ||
| 584 | /* State transition, retry */ | ||
| 585 | goto retry; | ||
| 586 | break; | ||
| 587 | case TPGS_STATE_OFFLINE: | ||
| 588 | /* Path is offline, fail */ | ||
| 589 | err = SCSI_DH_DEV_OFFLINED; | ||
| 590 | break; | ||
| 591 | default: | ||
| 592 | break; | ||
| 593 | } | ||
| 594 | } else { | ||
| 595 | /* Only Implicit ALUA support */ | ||
| 596 | if (h->state == TPGS_STATE_OPTIMIZED || | ||
| 597 | h->state == TPGS_STATE_NONOPTIMIZED || | ||
| 598 | h->state == TPGS_STATE_STANDBY) | ||
| 599 | /* Useable path if active */ | ||
| 600 | err = SCSI_DH_OK; | ||
| 601 | else | ||
| 602 | /* Path unuseable for unavailable/offline */ | ||
| 603 | err = SCSI_DH_DEV_OFFLINED; | ||
| 604 | } | ||
| 605 | return err; | ||
| 606 | } | ||
| 607 | |||
| 608 | /* | ||
| 609 | * alua_initialize - Initialize ALUA state | ||
| 610 | * @sdev: the device to be initialized | ||
| 611 | * | ||
| 612 | * For the prep_fn to work correctly we have | ||
| 613 | * to initialize the ALUA state for the device. | ||
| 614 | */ | ||
| 615 | static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h) | ||
| 616 | { | ||
| 617 | int err; | ||
| 618 | |||
| 619 | err = alua_std_inquiry(sdev, h); | ||
| 620 | if (err != SCSI_DH_OK) | ||
| 621 | goto out; | ||
| 622 | |||
| 623 | err = alua_vpd_inquiry(sdev, h); | ||
| 624 | if (err != SCSI_DH_OK) | ||
| 625 | goto out; | ||
| 626 | |||
| 627 | err = alua_rtpg(sdev, h); | ||
| 628 | if (err != SCSI_DH_OK) | ||
| 629 | goto out; | ||
| 630 | |||
| 631 | out: | ||
| 632 | return err; | ||
| 633 | } | ||
| 634 | |||
| 635 | /* | ||
| 636 | * alua_activate - activate a path | ||
| 637 | * @sdev: device on the path to be activated | ||
| 638 | * | ||
| 639 | * We're currently switching the port group to be activated only and | ||
| 640 | * let the array figure out the rest. | ||
| 641 | * There may be other arrays which require us to switch all port groups | ||
| 642 | * based on a certain policy. But until we actually encounter them it | ||
| 643 | * should be okay. | ||
| 644 | */ | ||
| 645 | static int alua_activate(struct scsi_device *sdev) | ||
| 646 | { | ||
| 647 | struct alua_dh_data *h = get_alua_data(sdev); | ||
| 648 | int err = SCSI_DH_OK; | ||
| 649 | |||
| 650 | if (h->group_id != -1) { | ||
| 651 | err = alua_rtpg(sdev, h); | ||
| 652 | if (err != SCSI_DH_OK) | ||
| 653 | goto out; | ||
| 654 | } | ||
| 655 | |||
| 656 | if (h->tpgs == TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED) | ||
| 657 | err = alua_stpg(sdev, TPGS_STATE_OPTIMIZED, h); | ||
| 658 | |||
| 659 | out: | ||
| 660 | return err; | ||
| 661 | } | ||
| 662 | |||
| 663 | /* | ||
| 664 | * alua_prep_fn - request callback | ||
| 665 | * | ||
| 666 | * Fail I/O to all paths not in state | ||
| 667 | * active/optimized or active/non-optimized. | ||
| 668 | */ | ||
| 669 | static int alua_prep_fn(struct scsi_device *sdev, struct request *req) | ||
| 670 | { | ||
| 671 | struct alua_dh_data *h = get_alua_data(sdev); | ||
| 672 | int ret = BLKPREP_OK; | ||
| 673 | |||
| 674 | if (h->state != TPGS_STATE_OPTIMIZED && | ||
| 675 | h->state != TPGS_STATE_NONOPTIMIZED) { | ||
| 676 | ret = BLKPREP_KILL; | ||
| 677 | req->cmd_flags |= REQ_QUIET; | ||
| 678 | } | ||
| 679 | return ret; | ||
| 680 | |||
| 681 | } | ||
| 682 | |||
| 683 | const struct scsi_dh_devlist alua_dev_list[] = { | ||
| 684 | {"HP", "MSA VOLUME" }, | ||
| 685 | {"HP", "HSV101" }, | ||
| 686 | {"HP", "HSV111" }, | ||
| 687 | {"HP", "HSV200" }, | ||
| 688 | {"HP", "HSV210" }, | ||
| 689 | {"HP", "HSV300" }, | ||
| 690 | {"IBM", "2107900" }, | ||
| 691 | {"IBM", "2145" }, | ||
| 692 | {"Pillar", "Axiom" }, | ||
| 693 | {NULL, NULL} | ||
| 694 | }; | ||
| 695 | |||
| 696 | static int alua_bus_attach(struct scsi_device *sdev); | ||
| 697 | static void alua_bus_detach(struct scsi_device *sdev); | ||
| 698 | |||
| 699 | static struct scsi_device_handler alua_dh = { | ||
| 700 | .name = ALUA_DH_NAME, | ||
| 701 | .module = THIS_MODULE, | ||
| 702 | .devlist = alua_dev_list, | ||
| 703 | .attach = alua_bus_attach, | ||
| 704 | .detach = alua_bus_detach, | ||
| 705 | .prep_fn = alua_prep_fn, | ||
| 706 | .check_sense = alua_check_sense, | ||
| 707 | .activate = alua_activate, | ||
| 708 | }; | ||
| 709 | |||
| 710 | /* | ||
| 711 | * alua_bus_attach - Attach device handler | ||
| 712 | * @sdev: device to be attached to | ||
| 713 | */ | ||
| 714 | static int alua_bus_attach(struct scsi_device *sdev) | ||
| 715 | { | ||
| 716 | struct scsi_dh_data *scsi_dh_data; | ||
| 717 | struct alua_dh_data *h; | ||
| 718 | unsigned long flags; | ||
| 719 | int err = SCSI_DH_OK; | ||
| 720 | |||
| 721 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) | ||
| 722 | + sizeof(*h) , GFP_KERNEL); | ||
| 723 | if (!scsi_dh_data) { | ||
| 724 | sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n", | ||
| 725 | ALUA_DH_NAME); | ||
| 726 | return -ENOMEM; | ||
| 727 | } | ||
| 728 | |||
| 729 | scsi_dh_data->scsi_dh = &alua_dh; | ||
| 730 | h = (struct alua_dh_data *) scsi_dh_data->buf; | ||
| 731 | h->tpgs = TPGS_MODE_UNINITIALIZED; | ||
| 732 | h->state = TPGS_STATE_OPTIMIZED; | ||
| 733 | h->group_id = -1; | ||
| 734 | h->rel_port = -1; | ||
| 735 | h->buff = h->inq; | ||
| 736 | h->bufflen = ALUA_INQUIRY_SIZE; | ||
| 737 | |||
| 738 | err = alua_initialize(sdev, h); | ||
| 739 | if (err != SCSI_DH_OK) | ||
| 740 | goto failed; | ||
| 741 | |||
| 742 | if (!try_module_get(THIS_MODULE)) | ||
| 743 | goto failed; | ||
| 744 | |||
| 745 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
| 746 | sdev->scsi_dh_data = scsi_dh_data; | ||
| 747 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
| 748 | |||
| 749 | return 0; | ||
| 750 | |||
| 751 | failed: | ||
| 752 | kfree(scsi_dh_data); | ||
| 753 | sdev_printk(KERN_ERR, sdev, "%s: not attached\n", ALUA_DH_NAME); | ||
| 754 | return -EINVAL; | ||
| 755 | } | ||
| 756 | |||
| 757 | /* | ||
| 758 | * alua_bus_detach - Detach device handler | ||
| 759 | * @sdev: device to be detached from | ||
| 760 | */ | ||
| 761 | static void alua_bus_detach(struct scsi_device *sdev) | ||
| 762 | { | ||
| 763 | struct scsi_dh_data *scsi_dh_data; | ||
| 764 | struct alua_dh_data *h; | ||
| 765 | unsigned long flags; | ||
| 766 | |||
| 767 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
| 768 | scsi_dh_data = sdev->scsi_dh_data; | ||
| 769 | sdev->scsi_dh_data = NULL; | ||
| 770 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
| 771 | |||
| 772 | h = (struct alua_dh_data *) scsi_dh_data->buf; | ||
| 773 | if (h->buff && h->inq != h->buff) | ||
| 774 | kfree(h->buff); | ||
| 775 | kfree(scsi_dh_data); | ||
| 776 | module_put(THIS_MODULE); | ||
| 777 | sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", ALUA_DH_NAME); | ||
| 778 | } | ||
| 779 | |||
| 780 | static int __init alua_init(void) | ||
| 781 | { | ||
| 782 | int r; | ||
| 783 | |||
| 784 | r = scsi_register_device_handler(&alua_dh); | ||
| 785 | if (r != 0) | ||
| 786 | printk(KERN_ERR "%s: Failed to register scsi device handler", | ||
| 787 | ALUA_DH_NAME); | ||
| 788 | return r; | ||
| 789 | } | ||
| 790 | |||
| 791 | static void __exit alua_exit(void) | ||
| 792 | { | ||
| 793 | scsi_unregister_device_handler(&alua_dh); | ||
| 794 | } | ||
| 795 | |||
| 796 | module_init(alua_init); | ||
| 797 | module_exit(alua_exit); | ||
| 798 | |||
| 799 | MODULE_DESCRIPTION("DM Multipath ALUA support"); | ||
| 800 | MODULE_AUTHOR("Hannes Reinecke <hare@suse.de>"); | ||
| 801 | MODULE_LICENSE("GPL"); | ||
| 802 | MODULE_VERSION(ALUA_DH_VER); | ||
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index f2467e936e55..aa46b131b20e 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c | |||
| @@ -25,28 +25,31 @@ | |||
| 25 | #include <scsi/scsi_dh.h> | 25 | #include <scsi/scsi_dh.h> |
| 26 | #include <scsi/scsi_device.h> | 26 | #include <scsi/scsi_device.h> |
| 27 | 27 | ||
| 28 | #define CLARIION_NAME "emc_clariion" | 28 | #define CLARIION_NAME "emc" |
| 29 | 29 | ||
| 30 | #define CLARIION_TRESPASS_PAGE 0x22 | 30 | #define CLARIION_TRESPASS_PAGE 0x22 |
| 31 | #define CLARIION_BUFFER_SIZE 0x80 | 31 | #define CLARIION_BUFFER_SIZE 0xFC |
| 32 | #define CLARIION_TIMEOUT (60 * HZ) | 32 | #define CLARIION_TIMEOUT (60 * HZ) |
| 33 | #define CLARIION_RETRIES 3 | 33 | #define CLARIION_RETRIES 3 |
| 34 | #define CLARIION_UNBOUND_LU -1 | 34 | #define CLARIION_UNBOUND_LU -1 |
| 35 | #define CLARIION_SP_A 0 | ||
| 36 | #define CLARIION_SP_B 1 | ||
| 35 | 37 | ||
| 36 | static unsigned char long_trespass[] = { | 38 | /* Flags */ |
| 37 | 0, 0, 0, 0, | 39 | #define CLARIION_SHORT_TRESPASS 1 |
| 38 | CLARIION_TRESPASS_PAGE, /* Page code */ | 40 | #define CLARIION_HONOR_RESERVATIONS 2 |
| 39 | 0x09, /* Page length - 2 */ | ||
| 40 | 0x81, /* Trespass code + Honor reservation bit */ | ||
| 41 | 0xff, 0xff, /* Trespass target */ | ||
| 42 | 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */ | ||
| 43 | }; | ||
| 44 | 41 | ||
| 45 | static unsigned char long_trespass_hr[] = { | 42 | /* LUN states */ |
| 46 | 0, 0, 0, 0, | 43 | #define CLARIION_LUN_UNINITIALIZED -1 |
| 44 | #define CLARIION_LUN_UNBOUND 0 | ||
| 45 | #define CLARIION_LUN_BOUND 1 | ||
| 46 | #define CLARIION_LUN_OWNED 2 | ||
| 47 | |||
| 48 | static unsigned char long_trespass[] = { | ||
| 49 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 47 | CLARIION_TRESPASS_PAGE, /* Page code */ | 50 | CLARIION_TRESPASS_PAGE, /* Page code */ |
| 48 | 0x09, /* Page length - 2 */ | 51 | 0x09, /* Page length - 2 */ |
| 49 | 0x01, /* Trespass code + Honor reservation bit */ | 52 | 0x01, /* Trespass code */ |
| 50 | 0xff, 0xff, /* Trespass target */ | 53 | 0xff, 0xff, /* Trespass target */ |
| 51 | 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */ | 54 | 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */ |
| 52 | }; | 55 | }; |
| @@ -55,39 +58,56 @@ static unsigned char short_trespass[] = { | |||
| 55 | 0, 0, 0, 0, | 58 | 0, 0, 0, 0, |
| 56 | CLARIION_TRESPASS_PAGE, /* Page code */ | 59 | CLARIION_TRESPASS_PAGE, /* Page code */ |
| 57 | 0x02, /* Page length - 2 */ | 60 | 0x02, /* Page length - 2 */ |
| 58 | 0x81, /* Trespass code + Honor reservation bit */ | 61 | 0x01, /* Trespass code */ |
| 59 | 0xff, /* Trespass target */ | 62 | 0xff, /* Trespass target */ |
| 60 | }; | 63 | }; |
| 61 | 64 | ||
| 62 | static unsigned char short_trespass_hr[] = { | 65 | static const char * lun_state[] = |
| 63 | 0, 0, 0, 0, | 66 | { |
| 64 | CLARIION_TRESPASS_PAGE, /* Page code */ | 67 | "not bound", |
| 65 | 0x02, /* Page length - 2 */ | 68 | "bound", |
| 66 | 0x01, /* Trespass code + Honor reservation bit */ | 69 | "owned", |
| 67 | 0xff, /* Trespass target */ | ||
| 68 | }; | 70 | }; |
| 69 | 71 | ||
| 70 | struct clariion_dh_data { | 72 | struct clariion_dh_data { |
| 71 | /* | 73 | /* |
| 74 | * Flags: | ||
| 75 | * CLARIION_SHORT_TRESPASS | ||
| 72 | * Use short trespass command (FC-series) or the long version | 76 | * Use short trespass command (FC-series) or the long version |
| 73 | * (default for AX/CX CLARiiON arrays). | 77 | * (default for AX/CX CLARiiON arrays). |
| 74 | */ | 78 | * |
| 75 | unsigned short_trespass; | 79 | * CLARIION_HONOR_RESERVATIONS |
| 76 | /* | ||
| 77 | * Whether or not (default) to honor SCSI reservations when | 80 | * Whether or not (default) to honor SCSI reservations when |
| 78 | * initiating a switch-over. | 81 | * initiating a switch-over. |
| 79 | */ | 82 | */ |
| 80 | unsigned hr; | 83 | unsigned flags; |
| 81 | /* I/O buffer for both MODE_SELECT and INQUIRY commands. */ | 84 | /* |
| 85 | * I/O buffer for both MODE_SELECT and INQUIRY commands. | ||
| 86 | */ | ||
| 82 | char buffer[CLARIION_BUFFER_SIZE]; | 87 | char buffer[CLARIION_BUFFER_SIZE]; |
| 83 | /* | 88 | /* |
| 84 | * SCSI sense buffer for commands -- assumes serial issuance | 89 | * SCSI sense buffer for commands -- assumes serial issuance |
| 85 | * and completion sequence of all commands for same multipath. | 90 | * and completion sequence of all commands for same multipath. |
| 86 | */ | 91 | */ |
| 87 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | 92 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; |
| 88 | /* which SP (A=0,B=1,UNBOUND=-1) is dflt SP for path's mapped dev */ | 93 | unsigned int senselen; |
| 94 | /* | ||
| 95 | * LUN state | ||
| 96 | */ | ||
| 97 | int lun_state; | ||
| 98 | /* | ||
| 99 | * SP Port number | ||
| 100 | */ | ||
| 101 | int port; | ||
| 102 | /* | ||
| 103 | * which SP (A=0,B=1,UNBOUND=-1) is the default SP for this | ||
| 104 | * path's mapped LUN | ||
| 105 | */ | ||
| 89 | int default_sp; | 106 | int default_sp; |
| 90 | /* which SP (A=0,B=1,UNBOUND=-1) is active for path's mapped dev */ | 107 | /* |
| 108 | * which SP (A=0,B=1,UNBOUND=-1) is the active SP for this | ||
| 109 | * path's mapped LUN | ||
| 110 | */ | ||
| 91 | int current_sp; | 111 | int current_sp; |
| 92 | }; | 112 | }; |
| 93 | 113 | ||
| @@ -102,19 +122,16 @@ static inline struct clariion_dh_data | |||
| 102 | /* | 122 | /* |
| 103 | * Parse MODE_SELECT cmd reply. | 123 | * Parse MODE_SELECT cmd reply. |
| 104 | */ | 124 | */ |
| 105 | static int trespass_endio(struct scsi_device *sdev, int result) | 125 | static int trespass_endio(struct scsi_device *sdev, char *sense) |
| 106 | { | 126 | { |
| 107 | int err = SCSI_DH_OK; | 127 | int err = SCSI_DH_IO; |
| 108 | struct scsi_sense_hdr sshdr; | 128 | struct scsi_sense_hdr sshdr; |
| 109 | struct clariion_dh_data *csdev = get_clariion_data(sdev); | ||
| 110 | char *sense = csdev->sense; | ||
| 111 | 129 | ||
| 112 | if (status_byte(result) == CHECK_CONDITION && | 130 | if (!scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) { |
| 113 | scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) { | 131 | sdev_printk(KERN_ERR, sdev, "%s: Found valid sense data 0x%2x, " |
| 114 | sdev_printk(KERN_ERR, sdev, "Found valid sense data 0x%2x, " | ||
| 115 | "0x%2x, 0x%2x while sending CLARiiON trespass " | 132 | "0x%2x, 0x%2x while sending CLARiiON trespass " |
| 116 | "command.\n", sshdr.sense_key, sshdr.asc, | 133 | "command.\n", CLARIION_NAME, sshdr.sense_key, |
| 117 | sshdr.ascq); | 134 | sshdr.asc, sshdr.ascq); |
| 118 | 135 | ||
| 119 | if ((sshdr.sense_key == 0x05) && (sshdr.asc == 0x04) && | 136 | if ((sshdr.sense_key == 0x05) && (sshdr.asc == 0x04) && |
| 120 | (sshdr.ascq == 0x00)) { | 137 | (sshdr.ascq == 0x00)) { |
| @@ -122,9 +139,9 @@ static int trespass_endio(struct scsi_device *sdev, int result) | |||
| 122 | * Array based copy in progress -- do not send | 139 | * Array based copy in progress -- do not send |
| 123 | * mode_select or copy will be aborted mid-stream. | 140 | * mode_select or copy will be aborted mid-stream. |
| 124 | */ | 141 | */ |
| 125 | sdev_printk(KERN_INFO, sdev, "Array Based Copy in " | 142 | sdev_printk(KERN_INFO, sdev, "%s: Array Based Copy in " |
| 126 | "progress while sending CLARiiON trespass " | 143 | "progress while sending CLARiiON trespass " |
| 127 | "command.\n"); | 144 | "command.\n", CLARIION_NAME); |
| 128 | err = SCSI_DH_DEV_TEMP_BUSY; | 145 | err = SCSI_DH_DEV_TEMP_BUSY; |
| 129 | } else if ((sshdr.sense_key == 0x02) && (sshdr.asc == 0x04) && | 146 | } else if ((sshdr.sense_key == 0x02) && (sshdr.asc == 0x04) && |
| 130 | (sshdr.ascq == 0x03)) { | 147 | (sshdr.ascq == 0x03)) { |
| @@ -132,160 +149,153 @@ static int trespass_endio(struct scsi_device *sdev, int result) | |||
| 132 | * LUN Not Ready - Manual Intervention Required | 149 | * LUN Not Ready - Manual Intervention Required |
| 133 | * indicates in-progress ucode upgrade (NDU). | 150 | * indicates in-progress ucode upgrade (NDU). |
| 134 | */ | 151 | */ |
| 135 | sdev_printk(KERN_INFO, sdev, "Detected in-progress " | 152 | sdev_printk(KERN_INFO, sdev, "%s: Detected in-progress " |
| 136 | "ucode upgrade NDU operation while sending " | 153 | "ucode upgrade NDU operation while sending " |
| 137 | "CLARiiON trespass command.\n"); | 154 | "CLARiiON trespass command.\n", CLARIION_NAME); |
| 138 | err = SCSI_DH_DEV_TEMP_BUSY; | 155 | err = SCSI_DH_DEV_TEMP_BUSY; |
| 139 | } else | 156 | } else |
| 140 | err = SCSI_DH_DEV_FAILED; | 157 | err = SCSI_DH_DEV_FAILED; |
| 141 | } else if (result) { | 158 | } else { |
| 142 | sdev_printk(KERN_ERR, sdev, "Error 0x%x while sending " | 159 | sdev_printk(KERN_INFO, sdev, |
| 143 | "CLARiiON trespass command.\n", result); | 160 | "%s: failed to send MODE SELECT, no sense available\n", |
| 144 | err = SCSI_DH_IO; | 161 | CLARIION_NAME); |
| 145 | } | 162 | } |
| 146 | |||
| 147 | return err; | 163 | return err; |
| 148 | } | 164 | } |
| 149 | 165 | ||
| 150 | static int parse_sp_info_reply(struct scsi_device *sdev, int result, | 166 | static int parse_sp_info_reply(struct scsi_device *sdev, |
| 151 | int *default_sp, int *current_sp, int *new_current_sp) | 167 | struct clariion_dh_data *csdev) |
| 152 | { | 168 | { |
| 153 | int err = SCSI_DH_OK; | 169 | int err = SCSI_DH_OK; |
| 154 | struct clariion_dh_data *csdev = get_clariion_data(sdev); | ||
| 155 | 170 | ||
| 156 | if (result == 0) { | 171 | /* check for in-progress ucode upgrade (NDU) */ |
| 157 | /* check for in-progress ucode upgrade (NDU) */ | 172 | if (csdev->buffer[48] != 0) { |
| 158 | if (csdev->buffer[48] != 0) { | 173 | sdev_printk(KERN_NOTICE, sdev, "%s: Detected in-progress " |
| 159 | sdev_printk(KERN_NOTICE, sdev, "Detected in-progress " | 174 | "ucode upgrade NDU operation while finding " |
| 160 | "ucode upgrade NDU operation while finding " | 175 | "current active SP.", CLARIION_NAME); |
| 161 | "current active SP."); | 176 | err = SCSI_DH_DEV_TEMP_BUSY; |
| 162 | err = SCSI_DH_DEV_TEMP_BUSY; | 177 | goto out; |
| 163 | } else { | 178 | } |
| 164 | *default_sp = csdev->buffer[5]; | 179 | if (csdev->buffer[4] < 0 || csdev->buffer[4] > 2) { |
| 165 | 180 | /* Invalid buffer format */ | |
| 166 | if (csdev->buffer[4] == 2) | 181 | sdev_printk(KERN_NOTICE, sdev, |
| 167 | /* SP for path is current */ | 182 | "%s: invalid VPD page 0xC0 format\n", |
| 168 | *current_sp = csdev->buffer[8]; | 183 | CLARIION_NAME); |
| 169 | else { | 184 | err = SCSI_DH_NOSYS; |
| 170 | if (csdev->buffer[4] == 1) | 185 | goto out; |
| 171 | /* SP for this path is NOT current */ | 186 | } |
| 172 | if (csdev->buffer[8] == 0) | 187 | switch (csdev->buffer[28] & 0x0f) { |
| 173 | *current_sp = 1; | 188 | case 6: |
| 174 | else | 189 | sdev_printk(KERN_NOTICE, sdev, |
| 175 | *current_sp = 0; | 190 | "%s: ALUA failover mode detected\n", |
| 176 | else | 191 | CLARIION_NAME); |
| 177 | /* unbound LU or LUNZ */ | 192 | break; |
| 178 | *current_sp = CLARIION_UNBOUND_LU; | 193 | case 4: |
| 179 | } | 194 | /* Linux failover */ |
| 180 | *new_current_sp = csdev->buffer[8]; | 195 | break; |
| 181 | } | 196 | default: |
| 182 | } else { | 197 | sdev_printk(KERN_WARNING, sdev, |
| 183 | struct scsi_sense_hdr sshdr; | 198 | "%s: Invalid failover mode %d\n", |
| 184 | 199 | CLARIION_NAME, csdev->buffer[28] & 0x0f); | |
| 185 | err = SCSI_DH_IO; | 200 | err = SCSI_DH_NOSYS; |
| 186 | 201 | goto out; | |
| 187 | if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE, | ||
| 188 | &sshdr)) | ||
| 189 | sdev_printk(KERN_ERR, sdev, "Found valid sense data " | ||
| 190 | "0x%2x, 0x%2x, 0x%2x while finding current " | ||
| 191 | "active SP.", sshdr.sense_key, sshdr.asc, | ||
| 192 | sshdr.ascq); | ||
| 193 | else | ||
| 194 | sdev_printk(KERN_ERR, sdev, "Error 0x%x finding " | ||
| 195 | "current active SP.", result); | ||
| 196 | } | 202 | } |
| 197 | 203 | ||
| 204 | csdev->default_sp = csdev->buffer[5]; | ||
| 205 | csdev->lun_state = csdev->buffer[4]; | ||
| 206 | csdev->current_sp = csdev->buffer[8]; | ||
| 207 | csdev->port = csdev->buffer[7]; | ||
| 208 | |||
| 209 | out: | ||
| 198 | return err; | 210 | return err; |
| 199 | } | 211 | } |
| 200 | 212 | ||
| 201 | static int sp_info_endio(struct scsi_device *sdev, int result, | 213 | #define emc_default_str "FC (Legacy)" |
| 202 | int mode_select_sent, int *done) | 214 | |
| 215 | static char * parse_sp_model(struct scsi_device *sdev, unsigned char *buffer) | ||
| 203 | { | 216 | { |
| 204 | struct clariion_dh_data *csdev = get_clariion_data(sdev); | 217 | unsigned char len = buffer[4] + 5; |
| 205 | int err_flags, default_sp, current_sp, new_current_sp; | 218 | char *sp_model = NULL; |
| 219 | unsigned char sp_len, serial_len; | ||
| 220 | |||
| 221 | if (len < 160) { | ||
| 222 | sdev_printk(KERN_WARNING, sdev, | ||
| 223 | "%s: Invalid information section length %d\n", | ||
| 224 | CLARIION_NAME, len); | ||
| 225 | /* Check for old FC arrays */ | ||
| 226 | if (!strncmp(buffer + 8, "DGC", 3)) { | ||
| 227 | /* Old FC array, not supporting extended information */ | ||
| 228 | sp_model = emc_default_str; | ||
| 229 | } | ||
| 230 | goto out; | ||
| 231 | } | ||
| 206 | 232 | ||
| 207 | err_flags = parse_sp_info_reply(sdev, result, &default_sp, | 233 | /* |
| 208 | ¤t_sp, &new_current_sp); | 234 | * Parse extended information for SP model number |
| 235 | */ | ||
| 236 | serial_len = buffer[160]; | ||
| 237 | if (serial_len == 0 || serial_len + 161 > len) { | ||
| 238 | sdev_printk(KERN_WARNING, sdev, | ||
| 239 | "%s: Invalid array serial number length %d\n", | ||
| 240 | CLARIION_NAME, serial_len); | ||
| 241 | goto out; | ||
| 242 | } | ||
| 243 | sp_len = buffer[99]; | ||
| 244 | if (sp_len == 0 || serial_len + sp_len + 161 > len) { | ||
| 245 | sdev_printk(KERN_WARNING, sdev, | ||
| 246 | "%s: Invalid model number length %d\n", | ||
| 247 | CLARIION_NAME, sp_len); | ||
| 248 | goto out; | ||
| 249 | } | ||
| 250 | sp_model = &buffer[serial_len + 161]; | ||
| 251 | /* Strip whitespace at the end */ | ||
| 252 | while (sp_len > 1 && sp_model[sp_len - 1] == ' ') | ||
| 253 | sp_len--; | ||
| 209 | 254 | ||
| 210 | if (err_flags != SCSI_DH_OK) | 255 | sp_model[sp_len] = '\0'; |
| 211 | goto done; | ||
| 212 | 256 | ||
| 213 | if (mode_select_sent) { | 257 | out: |
| 214 | csdev->default_sp = default_sp; | 258 | return sp_model; |
| 215 | csdev->current_sp = current_sp; | ||
| 216 | } else { | ||
| 217 | /* | ||
| 218 | * Issue the actual module_selec request IFF either | ||
| 219 | * (1) we do not know the identity of the current SP OR | ||
| 220 | * (2) what we think we know is actually correct. | ||
| 221 | */ | ||
| 222 | if ((current_sp != CLARIION_UNBOUND_LU) && | ||
| 223 | (new_current_sp != current_sp)) { | ||
| 224 | |||
| 225 | csdev->default_sp = default_sp; | ||
| 226 | csdev->current_sp = current_sp; | ||
| 227 | |||
| 228 | sdev_printk(KERN_INFO, sdev, "Ignoring path group " | ||
| 229 | "switch-over command for CLARiiON SP%s since " | ||
| 230 | " mapped device is already initialized.", | ||
| 231 | current_sp ? "B" : "A"); | ||
| 232 | if (done) | ||
| 233 | *done = 1; /* as good as doing it */ | ||
| 234 | } | ||
| 235 | } | ||
| 236 | done: | ||
| 237 | return err_flags; | ||
| 238 | } | 259 | } |
| 239 | 260 | ||
| 240 | /* | 261 | /* |
| 241 | * Get block request for REQ_BLOCK_PC command issued to path. Currently | 262 | * Get block request for REQ_BLOCK_PC command issued to path. Currently |
| 242 | * limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands. | 263 | * limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands. |
| 243 | * | 264 | * |
| 244 | * Uses data and sense buffers in hardware handler context structure and | 265 | * Uses data and sense buffers in hardware handler context structure and |
| 245 | * assumes serial servicing of commands, both issuance and completion. | 266 | * assumes serial servicing of commands, both issuance and completion. |
| 246 | */ | 267 | */ |
| 247 | static struct request *get_req(struct scsi_device *sdev, int cmd) | 268 | static struct request *get_req(struct scsi_device *sdev, int cmd, |
| 269 | unsigned char *buffer) | ||
| 248 | { | 270 | { |
| 249 | struct clariion_dh_data *csdev = get_clariion_data(sdev); | ||
| 250 | struct request *rq; | 271 | struct request *rq; |
| 251 | unsigned char *page22; | ||
| 252 | int len = 0; | 272 | int len = 0; |
| 253 | 273 | ||
| 254 | rq = blk_get_request(sdev->request_queue, | 274 | rq = blk_get_request(sdev->request_queue, |
| 255 | (cmd == MODE_SELECT) ? WRITE : READ, GFP_ATOMIC); | 275 | (cmd == MODE_SELECT) ? WRITE : READ, GFP_NOIO); |
| 256 | if (!rq) { | 276 | if (!rq) { |
| 257 | sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed"); | 277 | sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed"); |
| 258 | return NULL; | 278 | return NULL; |
| 259 | } | 279 | } |
| 260 | 280 | ||
| 261 | memset(&rq->cmd, 0, BLK_MAX_CDB); | 281 | memset(rq->cmd, 0, BLK_MAX_CDB); |
| 282 | rq->cmd_len = COMMAND_SIZE(cmd); | ||
| 262 | rq->cmd[0] = cmd; | 283 | rq->cmd[0] = cmd; |
| 263 | rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); | ||
| 264 | 284 | ||
| 265 | switch (cmd) { | 285 | switch (cmd) { |
| 266 | case MODE_SELECT: | 286 | case MODE_SELECT: |
| 267 | if (csdev->short_trespass) { | 287 | len = sizeof(short_trespass); |
| 268 | page22 = csdev->hr ? short_trespass_hr : short_trespass; | 288 | rq->cmd_flags |= REQ_RW; |
| 269 | len = sizeof(short_trespass); | 289 | rq->cmd[1] = 0x10; |
| 270 | } else { | 290 | break; |
| 271 | page22 = csdev->hr ? long_trespass_hr : long_trespass; | 291 | case MODE_SELECT_10: |
| 272 | len = sizeof(long_trespass); | 292 | len = sizeof(long_trespass); |
| 273 | } | ||
| 274 | /* | ||
| 275 | * Can't DMA from kernel BSS -- must copy selected trespass | ||
| 276 | * command mode page contents to context buffer which is | ||
| 277 | * allocated by kmalloc. | ||
| 278 | */ | ||
| 279 | BUG_ON((len > CLARIION_BUFFER_SIZE)); | ||
| 280 | memcpy(csdev->buffer, page22, len); | ||
| 281 | rq->cmd_flags |= REQ_RW; | 293 | rq->cmd_flags |= REQ_RW; |
| 282 | rq->cmd[1] = 0x10; | 294 | rq->cmd[1] = 0x10; |
| 283 | break; | 295 | break; |
| 284 | case INQUIRY: | 296 | case INQUIRY: |
| 285 | rq->cmd[1] = 0x1; | ||
| 286 | rq->cmd[2] = 0xC0; | ||
| 287 | len = CLARIION_BUFFER_SIZE; | 297 | len = CLARIION_BUFFER_SIZE; |
| 288 | memset(csdev->buffer, 0, CLARIION_BUFFER_SIZE); | 298 | memset(buffer, 0, len); |
| 289 | break; | 299 | break; |
| 290 | default: | 300 | default: |
| 291 | BUG_ON(1); | 301 | BUG_ON(1); |
| @@ -298,47 +308,94 @@ static struct request *get_req(struct scsi_device *sdev, int cmd) | |||
| 298 | rq->timeout = CLARIION_TIMEOUT; | 308 | rq->timeout = CLARIION_TIMEOUT; |
| 299 | rq->retries = CLARIION_RETRIES; | 309 | rq->retries = CLARIION_RETRIES; |
| 300 | 310 | ||
| 301 | rq->sense = csdev->sense; | 311 | if (blk_rq_map_kern(rq->q, rq, buffer, len, GFP_NOIO)) { |
| 302 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); | 312 | blk_put_request(rq); |
| 303 | rq->sense_len = 0; | ||
| 304 | |||
| 305 | if (blk_rq_map_kern(sdev->request_queue, rq, csdev->buffer, | ||
| 306 | len, GFP_ATOMIC)) { | ||
| 307 | __blk_put_request(rq->q, rq); | ||
| 308 | return NULL; | 313 | return NULL; |
| 309 | } | 314 | } |
| 310 | 315 | ||
| 311 | return rq; | 316 | return rq; |
| 312 | } | 317 | } |
| 313 | 318 | ||
| 314 | static int send_cmd(struct scsi_device *sdev, int cmd) | 319 | static int send_inquiry_cmd(struct scsi_device *sdev, int page, |
| 320 | struct clariion_dh_data *csdev) | ||
| 315 | { | 321 | { |
| 316 | struct request *rq = get_req(sdev, cmd); | 322 | struct request *rq = get_req(sdev, INQUIRY, csdev->buffer); |
| 323 | int err; | ||
| 317 | 324 | ||
| 318 | if (!rq) | 325 | if (!rq) |
| 319 | return SCSI_DH_RES_TEMP_UNAVAIL; | 326 | return SCSI_DH_RES_TEMP_UNAVAIL; |
| 320 | 327 | ||
| 321 | return blk_execute_rq(sdev->request_queue, NULL, rq, 1); | 328 | rq->sense = csdev->sense; |
| 329 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
| 330 | rq->sense_len = csdev->senselen = 0; | ||
| 331 | |||
| 332 | rq->cmd[0] = INQUIRY; | ||
| 333 | if (page != 0) { | ||
| 334 | rq->cmd[1] = 1; | ||
| 335 | rq->cmd[2] = page; | ||
| 336 | } | ||
| 337 | err = blk_execute_rq(sdev->request_queue, NULL, rq, 1); | ||
| 338 | if (err == -EIO) { | ||
| 339 | sdev_printk(KERN_INFO, sdev, | ||
| 340 | "%s: failed to send %s INQUIRY: %x\n", | ||
| 341 | CLARIION_NAME, page?"EVPD":"standard", | ||
| 342 | rq->errors); | ||
| 343 | csdev->senselen = rq->sense_len; | ||
| 344 | err = SCSI_DH_IO; | ||
| 345 | } | ||
| 346 | |||
| 347 | blk_put_request(rq); | ||
| 348 | |||
| 349 | return err; | ||
| 322 | } | 350 | } |
| 323 | 351 | ||
| 324 | static int clariion_activate(struct scsi_device *sdev) | 352 | static int send_trespass_cmd(struct scsi_device *sdev, |
| 353 | struct clariion_dh_data *csdev) | ||
| 325 | { | 354 | { |
| 326 | int result, done = 0; | 355 | struct request *rq; |
| 356 | unsigned char *page22; | ||
| 357 | int err, len, cmd; | ||
| 358 | |||
| 359 | if (csdev->flags & CLARIION_SHORT_TRESPASS) { | ||
| 360 | page22 = short_trespass; | ||
| 361 | if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS)) | ||
| 362 | /* Set Honor Reservations bit */ | ||
| 363 | page22[6] |= 0x80; | ||
| 364 | len = sizeof(short_trespass); | ||
| 365 | cmd = MODE_SELECT; | ||
| 366 | } else { | ||
| 367 | page22 = long_trespass; | ||
| 368 | if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS)) | ||
| 369 | /* Set Honor Reservations bit */ | ||
| 370 | page22[10] |= 0x80; | ||
| 371 | len = sizeof(long_trespass); | ||
| 372 | cmd = MODE_SELECT_10; | ||
| 373 | } | ||
| 374 | BUG_ON((len > CLARIION_BUFFER_SIZE)); | ||
| 375 | memcpy(csdev->buffer, page22, len); | ||
| 327 | 376 | ||
| 328 | result = send_cmd(sdev, INQUIRY); | 377 | rq = get_req(sdev, cmd, csdev->buffer); |
| 329 | result = sp_info_endio(sdev, result, 0, &done); | 378 | if (!rq) |
| 330 | if (result || done) | 379 | return SCSI_DH_RES_TEMP_UNAVAIL; |
| 331 | goto done; | ||
| 332 | 380 | ||
| 333 | result = send_cmd(sdev, MODE_SELECT); | 381 | rq->sense = csdev->sense; |
| 334 | result = trespass_endio(sdev, result); | 382 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); |
| 335 | if (result) | 383 | rq->sense_len = csdev->senselen = 0; |
| 336 | goto done; | ||
| 337 | 384 | ||
| 338 | result = send_cmd(sdev, INQUIRY); | 385 | err = blk_execute_rq(sdev->request_queue, NULL, rq, 1); |
| 339 | result = sp_info_endio(sdev, result, 1, NULL); | 386 | if (err == -EIO) { |
| 340 | done: | 387 | if (rq->sense_len) { |
| 341 | return result; | 388 | err = trespass_endio(sdev, csdev->sense); |
| 389 | } else { | ||
| 390 | sdev_printk(KERN_INFO, sdev, | ||
| 391 | "%s: failed to send MODE SELECT: %x\n", | ||
| 392 | CLARIION_NAME, rq->errors); | ||
| 393 | } | ||
| 394 | } | ||
| 395 | |||
| 396 | blk_put_request(rq); | ||
| 397 | |||
| 398 | return err; | ||
| 342 | } | 399 | } |
| 343 | 400 | ||
| 344 | static int clariion_check_sense(struct scsi_device *sdev, | 401 | static int clariion_check_sense(struct scsi_device *sdev, |
| @@ -386,99 +443,215 @@ static int clariion_check_sense(struct scsi_device *sdev, | |||
| 386 | break; | 443 | break; |
| 387 | } | 444 | } |
| 388 | 445 | ||
| 389 | /* success just means we do not care what scsi-ml does */ | 446 | return SCSI_RETURN_NOT_HANDLED; |
| 390 | return SUCCESS; | 447 | } |
| 448 | |||
| 449 | static int clariion_prep_fn(struct scsi_device *sdev, struct request *req) | ||
| 450 | { | ||
| 451 | struct clariion_dh_data *h = get_clariion_data(sdev); | ||
| 452 | int ret = BLKPREP_OK; | ||
| 453 | |||
| 454 | if (h->lun_state != CLARIION_LUN_OWNED) { | ||
| 455 | ret = BLKPREP_KILL; | ||
| 456 | req->cmd_flags |= REQ_QUIET; | ||
| 457 | } | ||
| 458 | return ret; | ||
| 459 | |||
| 460 | } | ||
| 461 | |||
| 462 | static int clariion_std_inquiry(struct scsi_device *sdev, | ||
| 463 | struct clariion_dh_data *csdev) | ||
| 464 | { | ||
| 465 | int err; | ||
| 466 | char *sp_model; | ||
| 467 | |||
| 468 | err = send_inquiry_cmd(sdev, 0, csdev); | ||
| 469 | if (err != SCSI_DH_OK && csdev->senselen) { | ||
| 470 | struct scsi_sense_hdr sshdr; | ||
| 471 | |||
| 472 | if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE, | ||
| 473 | &sshdr)) { | ||
| 474 | sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code " | ||
| 475 | "%02x/%02x/%02x\n", CLARIION_NAME, | ||
| 476 | sshdr.sense_key, sshdr.asc, sshdr.ascq); | ||
| 477 | } | ||
| 478 | err = SCSI_DH_IO; | ||
| 479 | goto out; | ||
| 480 | } | ||
| 481 | |||
| 482 | sp_model = parse_sp_model(sdev, csdev->buffer); | ||
| 483 | if (!sp_model) { | ||
| 484 | err = SCSI_DH_DEV_UNSUPP; | ||
| 485 | goto out; | ||
| 486 | } | ||
| 487 | |||
| 488 | /* | ||
| 489 | * FC Series arrays do not support long trespass | ||
| 490 | */ | ||
| 491 | if (!strlen(sp_model) || !strncmp(sp_model, "FC",2)) | ||
| 492 | csdev->flags |= CLARIION_SHORT_TRESPASS; | ||
| 493 | |||
| 494 | sdev_printk(KERN_INFO, sdev, | ||
| 495 | "%s: detected Clariion %s, flags %x\n", | ||
| 496 | CLARIION_NAME, sp_model, csdev->flags); | ||
| 497 | out: | ||
| 498 | return err; | ||
| 391 | } | 499 | } |
| 392 | 500 | ||
| 393 | static const struct { | 501 | static int clariion_send_inquiry(struct scsi_device *sdev, |
| 394 | char *vendor; | 502 | struct clariion_dh_data *csdev) |
| 395 | char *model; | 503 | { |
| 396 | } clariion_dev_list[] = { | 504 | int err, retry = CLARIION_RETRIES; |
| 505 | |||
| 506 | retry: | ||
| 507 | err = send_inquiry_cmd(sdev, 0xC0, csdev); | ||
| 508 | if (err != SCSI_DH_OK && csdev->senselen) { | ||
| 509 | struct scsi_sense_hdr sshdr; | ||
| 510 | |||
| 511 | err = scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE, | ||
| 512 | &sshdr); | ||
| 513 | if (!err) | ||
| 514 | return SCSI_DH_IO; | ||
| 515 | |||
| 516 | err = clariion_check_sense(sdev, &sshdr); | ||
| 517 | if (retry > 0 && err == NEEDS_RETRY) { | ||
| 518 | retry--; | ||
| 519 | goto retry; | ||
| 520 | } | ||
| 521 | sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code " | ||
| 522 | "%02x/%02x/%02x\n", CLARIION_NAME, | ||
| 523 | sshdr.sense_key, sshdr.asc, sshdr.ascq); | ||
| 524 | err = SCSI_DH_IO; | ||
| 525 | } else { | ||
| 526 | err = parse_sp_info_reply(sdev, csdev); | ||
| 527 | } | ||
| 528 | return err; | ||
| 529 | } | ||
| 530 | |||
| 531 | static int clariion_activate(struct scsi_device *sdev) | ||
| 532 | { | ||
| 533 | struct clariion_dh_data *csdev = get_clariion_data(sdev); | ||
| 534 | int result; | ||
| 535 | |||
| 536 | result = clariion_send_inquiry(sdev, csdev); | ||
| 537 | if (result != SCSI_DH_OK) | ||
| 538 | goto done; | ||
| 539 | |||
| 540 | if (csdev->lun_state == CLARIION_LUN_OWNED) | ||
| 541 | goto done; | ||
| 542 | |||
| 543 | result = send_trespass_cmd(sdev, csdev); | ||
| 544 | if (result != SCSI_DH_OK) | ||
| 545 | goto done; | ||
| 546 | sdev_printk(KERN_INFO, sdev,"%s: %s trespass command sent\n", | ||
| 547 | CLARIION_NAME, | ||
| 548 | csdev->flags&CLARIION_SHORT_TRESPASS?"short":"long" ); | ||
| 549 | |||
| 550 | /* Update status */ | ||
| 551 | result = clariion_send_inquiry(sdev, csdev); | ||
| 552 | if (result != SCSI_DH_OK) | ||
| 553 | goto done; | ||
| 554 | |||
| 555 | done: | ||
| 556 | sdev_printk(KERN_INFO, sdev, | ||
| 557 | "%s: at SP %c Port %d (%s, default SP %c)\n", | ||
| 558 | CLARIION_NAME, csdev->current_sp + 'A', | ||
| 559 | csdev->port, lun_state[csdev->lun_state], | ||
| 560 | csdev->default_sp + 'A'); | ||
| 561 | |||
| 562 | return result; | ||
| 563 | } | ||
| 564 | |||
| 565 | const struct scsi_dh_devlist clariion_dev_list[] = { | ||
| 397 | {"DGC", "RAID"}, | 566 | {"DGC", "RAID"}, |
| 398 | {"DGC", "DISK"}, | 567 | {"DGC", "DISK"}, |
| 568 | {"DGC", "VRAID"}, | ||
| 399 | {NULL, NULL}, | 569 | {NULL, NULL}, |
| 400 | }; | 570 | }; |
| 401 | 571 | ||
| 402 | static int clariion_bus_notify(struct notifier_block *, unsigned long, void *); | 572 | static int clariion_bus_attach(struct scsi_device *sdev); |
| 573 | static void clariion_bus_detach(struct scsi_device *sdev); | ||
| 403 | 574 | ||
| 404 | static struct scsi_device_handler clariion_dh = { | 575 | static struct scsi_device_handler clariion_dh = { |
| 405 | .name = CLARIION_NAME, | 576 | .name = CLARIION_NAME, |
| 406 | .module = THIS_MODULE, | 577 | .module = THIS_MODULE, |
| 407 | .nb.notifier_call = clariion_bus_notify, | 578 | .devlist = clariion_dev_list, |
| 579 | .attach = clariion_bus_attach, | ||
| 580 | .detach = clariion_bus_detach, | ||
| 408 | .check_sense = clariion_check_sense, | 581 | .check_sense = clariion_check_sense, |
| 409 | .activate = clariion_activate, | 582 | .activate = clariion_activate, |
| 583 | .prep_fn = clariion_prep_fn, | ||
| 410 | }; | 584 | }; |
| 411 | 585 | ||
| 412 | /* | 586 | /* |
| 413 | * TODO: need some interface so we can set trespass values | 587 | * TODO: need some interface so we can set trespass values |
| 414 | */ | 588 | */ |
| 415 | static int clariion_bus_notify(struct notifier_block *nb, | 589 | static int clariion_bus_attach(struct scsi_device *sdev) |
| 416 | unsigned long action, void *data) | ||
| 417 | { | 590 | { |
| 418 | struct device *dev = data; | ||
| 419 | struct scsi_device *sdev; | ||
| 420 | struct scsi_dh_data *scsi_dh_data; | 591 | struct scsi_dh_data *scsi_dh_data; |
| 421 | struct clariion_dh_data *h; | 592 | struct clariion_dh_data *h; |
| 422 | int i, found = 0; | ||
| 423 | unsigned long flags; | 593 | unsigned long flags; |
| 594 | int err; | ||
| 424 | 595 | ||
| 425 | if (!scsi_is_sdev_device(dev)) | 596 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) |
| 426 | return 0; | 597 | + sizeof(*h) , GFP_KERNEL); |
| 598 | if (!scsi_dh_data) { | ||
| 599 | sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n", | ||
| 600 | CLARIION_NAME); | ||
| 601 | return -ENOMEM; | ||
| 602 | } | ||
| 427 | 603 | ||
| 428 | sdev = to_scsi_device(dev); | 604 | scsi_dh_data->scsi_dh = &clariion_dh; |
| 605 | h = (struct clariion_dh_data *) scsi_dh_data->buf; | ||
| 606 | h->lun_state = CLARIION_LUN_UNINITIALIZED; | ||
| 607 | h->default_sp = CLARIION_UNBOUND_LU; | ||
| 608 | h->current_sp = CLARIION_UNBOUND_LU; | ||
| 429 | 609 | ||
| 430 | if (action == BUS_NOTIFY_ADD_DEVICE) { | 610 | err = clariion_std_inquiry(sdev, h); |
| 431 | for (i = 0; clariion_dev_list[i].vendor; i++) { | 611 | if (err != SCSI_DH_OK) |
| 432 | if (!strncmp(sdev->vendor, clariion_dev_list[i].vendor, | 612 | goto failed; |
| 433 | strlen(clariion_dev_list[i].vendor)) && | ||
| 434 | !strncmp(sdev->model, clariion_dev_list[i].model, | ||
| 435 | strlen(clariion_dev_list[i].model))) { | ||
| 436 | found = 1; | ||
| 437 | break; | ||
| 438 | } | ||
| 439 | } | ||
| 440 | if (!found) | ||
| 441 | goto out; | ||
| 442 | |||
| 443 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) | ||
| 444 | + sizeof(*h) , GFP_KERNEL); | ||
| 445 | if (!scsi_dh_data) { | ||
| 446 | sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n", | ||
| 447 | CLARIION_NAME); | ||
| 448 | goto out; | ||
| 449 | } | ||
| 450 | 613 | ||
| 451 | scsi_dh_data->scsi_dh = &clariion_dh; | 614 | err = clariion_send_inquiry(sdev, h); |
| 452 | h = (struct clariion_dh_data *) scsi_dh_data->buf; | 615 | if (err != SCSI_DH_OK) |
| 453 | h->default_sp = CLARIION_UNBOUND_LU; | 616 | goto failed; |
| 454 | h->current_sp = CLARIION_UNBOUND_LU; | ||
| 455 | 617 | ||
| 456 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | 618 | if (!try_module_get(THIS_MODULE)) |
| 457 | sdev->scsi_dh_data = scsi_dh_data; | 619 | goto failed; |
| 458 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
| 459 | 620 | ||
| 460 | sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", CLARIION_NAME); | 621 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); |
| 461 | try_module_get(THIS_MODULE); | 622 | sdev->scsi_dh_data = scsi_dh_data; |
| 623 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
| 462 | 624 | ||
| 463 | } else if (action == BUS_NOTIFY_DEL_DEVICE) { | 625 | sdev_printk(KERN_INFO, sdev, |
| 464 | if (sdev->scsi_dh_data == NULL || | 626 | "%s: connected to SP %c Port %d (%s, default SP %c)\n", |
| 465 | sdev->scsi_dh_data->scsi_dh != &clariion_dh) | 627 | CLARIION_NAME, h->current_sp + 'A', |
| 466 | goto out; | 628 | h->port, lun_state[h->lun_state], |
| 629 | h->default_sp + 'A'); | ||
| 467 | 630 | ||
| 468 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | 631 | return 0; |
| 469 | scsi_dh_data = sdev->scsi_dh_data; | ||
| 470 | sdev->scsi_dh_data = NULL; | ||
| 471 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
| 472 | 632 | ||
| 473 | sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", | 633 | failed: |
| 474 | CLARIION_NAME); | 634 | kfree(scsi_dh_data); |
| 635 | sdev_printk(KERN_ERR, sdev, "%s: not attached\n", | ||
| 636 | CLARIION_NAME); | ||
| 637 | return -EINVAL; | ||
| 638 | } | ||
| 475 | 639 | ||
| 476 | kfree(scsi_dh_data); | 640 | static void clariion_bus_detach(struct scsi_device *sdev) |
| 477 | module_put(THIS_MODULE); | 641 | { |
| 478 | } | 642 | struct scsi_dh_data *scsi_dh_data; |
| 643 | unsigned long flags; | ||
| 479 | 644 | ||
| 480 | out: | 645 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); |
| 481 | return 0; | 646 | scsi_dh_data = sdev->scsi_dh_data; |
| 647 | sdev->scsi_dh_data = NULL; | ||
| 648 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
| 649 | |||
| 650 | sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", | ||
| 651 | CLARIION_NAME); | ||
| 652 | |||
| 653 | kfree(scsi_dh_data); | ||
| 654 | module_put(THIS_MODULE); | ||
| 482 | } | 655 | } |
| 483 | 656 | ||
| 484 | static int __init clariion_init(void) | 657 | static int __init clariion_init(void) |
| @@ -487,7 +660,8 @@ static int __init clariion_init(void) | |||
| 487 | 660 | ||
| 488 | r = scsi_register_device_handler(&clariion_dh); | 661 | r = scsi_register_device_handler(&clariion_dh); |
| 489 | if (r != 0) | 662 | if (r != 0) |
| 490 | printk(KERN_ERR "Failed to register scsi device handler."); | 663 | printk(KERN_ERR "%s: Failed to register scsi device handler.", |
| 664 | CLARIION_NAME); | ||
| 491 | return r; | 665 | return r; |
| 492 | } | 666 | } |
| 493 | 667 | ||
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c index ae6be87d6a83..9c7a1f8ebb72 100644 --- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | * | 4 | * |
| 5 | * Copyright (C) 2006 Red Hat, Inc. All rights reserved. | 5 | * Copyright (C) 2006 Red Hat, Inc. All rights reserved. |
| 6 | * Copyright (C) 2006 Mike Christie | 6 | * Copyright (C) 2006 Mike Christie |
| 7 | * Copyright (C) 2008 Hannes Reinecke <hare@suse.de> | ||
| 7 | * | 8 | * |
| 8 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
| 9 | * it under the terms of the GNU General Public License as published by | 10 | * it under the terms of the GNU General Public License as published by |
| @@ -25,13 +26,18 @@ | |||
| 25 | #include <scsi/scsi_eh.h> | 26 | #include <scsi/scsi_eh.h> |
| 26 | #include <scsi/scsi_dh.h> | 27 | #include <scsi/scsi_dh.h> |
| 27 | 28 | ||
| 28 | #define HP_SW_NAME "hp_sw" | 29 | #define HP_SW_NAME "hp_sw" |
| 29 | 30 | ||
| 30 | #define HP_SW_TIMEOUT (60 * HZ) | 31 | #define HP_SW_TIMEOUT (60 * HZ) |
| 31 | #define HP_SW_RETRIES 3 | 32 | #define HP_SW_RETRIES 3 |
| 33 | |||
| 34 | #define HP_SW_PATH_UNINITIALIZED -1 | ||
| 35 | #define HP_SW_PATH_ACTIVE 0 | ||
| 36 | #define HP_SW_PATH_PASSIVE 1 | ||
| 32 | 37 | ||
| 33 | struct hp_sw_dh_data { | 38 | struct hp_sw_dh_data { |
| 34 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | 39 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; |
| 40 | int path_state; | ||
| 35 | int retries; | 41 | int retries; |
| 36 | }; | 42 | }; |
| 37 | 43 | ||
| @@ -42,51 +48,161 @@ static inline struct hp_sw_dh_data *get_hp_sw_data(struct scsi_device *sdev) | |||
| 42 | return ((struct hp_sw_dh_data *) scsi_dh_data->buf); | 48 | return ((struct hp_sw_dh_data *) scsi_dh_data->buf); |
| 43 | } | 49 | } |
| 44 | 50 | ||
| 45 | static int hp_sw_done(struct scsi_device *sdev) | 51 | /* |
| 52 | * tur_done - Handle TEST UNIT READY return status | ||
| 53 | * @sdev: sdev the command has been sent to | ||
| 54 | * @errors: blk error code | ||
| 55 | * | ||
| 56 | * Returns SCSI_DH_DEV_OFFLINED if the sdev is on the passive path | ||
| 57 | */ | ||
| 58 | static int tur_done(struct scsi_device *sdev, unsigned char *sense) | ||
| 46 | { | 59 | { |
| 47 | struct hp_sw_dh_data *h = get_hp_sw_data(sdev); | ||
| 48 | struct scsi_sense_hdr sshdr; | 60 | struct scsi_sense_hdr sshdr; |
| 49 | int rc; | 61 | int ret; |
| 50 | |||
| 51 | sdev_printk(KERN_INFO, sdev, "hp_sw_done\n"); | ||
| 52 | 62 | ||
| 53 | rc = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sshdr); | 63 | ret = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr); |
| 54 | if (!rc) | 64 | if (!ret) { |
| 65 | sdev_printk(KERN_WARNING, sdev, | ||
| 66 | "%s: sending tur failed, no sense available\n", | ||
| 67 | HP_SW_NAME); | ||
| 68 | ret = SCSI_DH_IO; | ||
| 55 | goto done; | 69 | goto done; |
| 70 | } | ||
| 56 | switch (sshdr.sense_key) { | 71 | switch (sshdr.sense_key) { |
| 72 | case UNIT_ATTENTION: | ||
| 73 | ret = SCSI_DH_IMM_RETRY; | ||
| 74 | break; | ||
| 57 | case NOT_READY: | 75 | case NOT_READY: |
| 58 | if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) { | 76 | if ((sshdr.asc == 0x04) && (sshdr.ascq == 2)) { |
| 59 | rc = SCSI_DH_RETRY; | 77 | /* |
| 60 | h->retries++; | 78 | * LUN not ready - Initialization command required |
| 79 | * | ||
| 80 | * This is the passive path | ||
| 81 | */ | ||
| 82 | ret = SCSI_DH_DEV_OFFLINED; | ||
| 61 | break; | 83 | break; |
| 62 | } | 84 | } |
| 63 | /* fall through */ | 85 | /* Fallthrough */ |
| 64 | default: | 86 | default: |
| 65 | h->retries++; | 87 | sdev_printk(KERN_WARNING, sdev, |
| 66 | rc = SCSI_DH_IMM_RETRY; | 88 | "%s: sending tur failed, sense %x/%x/%x\n", |
| 89 | HP_SW_NAME, sshdr.sense_key, sshdr.asc, | ||
| 90 | sshdr.ascq); | ||
| 91 | break; | ||
| 67 | } | 92 | } |
| 68 | 93 | ||
| 69 | done: | 94 | done: |
| 70 | if (rc == SCSI_DH_OK || rc == SCSI_DH_IO) | 95 | return ret; |
| 71 | h->retries = 0; | 96 | } |
| 72 | else if (h->retries > HP_SW_RETRIES) { | 97 | |
| 73 | h->retries = 0; | 98 | /* |
| 99 | * hp_sw_tur - Send TEST UNIT READY | ||
| 100 | * @sdev: sdev command should be sent to | ||
| 101 | * | ||
| 102 | * Use the TEST UNIT READY command to determine | ||
| 103 | * the path state. | ||
| 104 | */ | ||
| 105 | static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h) | ||
| 106 | { | ||
| 107 | struct request *req; | ||
| 108 | int ret; | ||
| 109 | |||
| 110 | req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO); | ||
| 111 | if (!req) | ||
| 112 | return SCSI_DH_RES_TEMP_UNAVAIL; | ||
| 113 | |||
| 114 | req->cmd_type = REQ_TYPE_BLOCK_PC; | ||
| 115 | req->cmd_flags |= REQ_FAILFAST; | ||
| 116 | req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY); | ||
| 117 | memset(req->cmd, 0, MAX_COMMAND_SIZE); | ||
| 118 | req->cmd[0] = TEST_UNIT_READY; | ||
| 119 | req->timeout = HP_SW_TIMEOUT; | ||
| 120 | req->sense = h->sense; | ||
| 121 | memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
| 122 | req->sense_len = 0; | ||
| 123 | |||
| 124 | retry: | ||
| 125 | ret = blk_execute_rq(req->q, NULL, req, 1); | ||
| 126 | if (ret == -EIO) { | ||
| 127 | if (req->sense_len > 0) { | ||
| 128 | ret = tur_done(sdev, h->sense); | ||
| 129 | } else { | ||
| 130 | sdev_printk(KERN_WARNING, sdev, | ||
| 131 | "%s: sending tur failed with %x\n", | ||
| 132 | HP_SW_NAME, req->errors); | ||
| 133 | ret = SCSI_DH_IO; | ||
| 134 | } | ||
| 135 | } else { | ||
| 136 | h->path_state = HP_SW_PATH_ACTIVE; | ||
| 137 | ret = SCSI_DH_OK; | ||
| 138 | } | ||
| 139 | if (ret == SCSI_DH_IMM_RETRY) | ||
| 140 | goto retry; | ||
| 141 | if (ret == SCSI_DH_DEV_OFFLINED) { | ||
| 142 | h->path_state = HP_SW_PATH_PASSIVE; | ||
| 143 | ret = SCSI_DH_OK; | ||
| 144 | } | ||
| 145 | |||
| 146 | blk_put_request(req); | ||
| 147 | |||
| 148 | return ret; | ||
| 149 | } | ||
| 150 | |||
| 151 | /* | ||
| 152 | * start_done - Handle START STOP UNIT return status | ||
| 153 | * @sdev: sdev the command has been sent to | ||
| 154 | * @errors: blk error code | ||
| 155 | */ | ||
| 156 | static int start_done(struct scsi_device *sdev, unsigned char *sense) | ||
| 157 | { | ||
| 158 | struct scsi_sense_hdr sshdr; | ||
| 159 | int rc; | ||
| 160 | |||
| 161 | rc = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr); | ||
| 162 | if (!rc) { | ||
| 163 | sdev_printk(KERN_WARNING, sdev, | ||
| 164 | "%s: sending start_stop_unit failed, " | ||
| 165 | "no sense available\n", | ||
| 166 | HP_SW_NAME); | ||
| 167 | return SCSI_DH_IO; | ||
| 168 | } | ||
| 169 | switch (sshdr.sense_key) { | ||
| 170 | case NOT_READY: | ||
| 171 | if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) { | ||
| 172 | /* | ||
| 173 | * LUN not ready - manual intervention required | ||
| 174 | * | ||
| 175 | * Switch-over in progress, retry. | ||
| 176 | */ | ||
| 177 | rc = SCSI_DH_RETRY; | ||
| 178 | break; | ||
| 179 | } | ||
| 180 | /* fall through */ | ||
| 181 | default: | ||
| 182 | sdev_printk(KERN_WARNING, sdev, | ||
| 183 | "%s: sending start_stop_unit failed, sense %x/%x/%x\n", | ||
| 184 | HP_SW_NAME, sshdr.sense_key, sshdr.asc, | ||
| 185 | sshdr.ascq); | ||
| 74 | rc = SCSI_DH_IO; | 186 | rc = SCSI_DH_IO; |
| 75 | } | 187 | } |
| 188 | |||
| 76 | return rc; | 189 | return rc; |
| 77 | } | 190 | } |
| 78 | 191 | ||
| 79 | static int hp_sw_activate(struct scsi_device *sdev) | 192 | /* |
| 193 | * hp_sw_start_stop - Send START STOP UNIT command | ||
| 194 | * @sdev: sdev command should be sent to | ||
| 195 | * | ||
| 196 | * Sending START STOP UNIT activates the SP. | ||
| 197 | */ | ||
| 198 | static int hp_sw_start_stop(struct scsi_device *sdev, struct hp_sw_dh_data *h) | ||
| 80 | { | 199 | { |
| 81 | struct hp_sw_dh_data *h = get_hp_sw_data(sdev); | ||
| 82 | struct request *req; | 200 | struct request *req; |
| 83 | int ret = SCSI_DH_RES_TEMP_UNAVAIL; | 201 | int ret, retry; |
| 84 | 202 | ||
| 85 | req = blk_get_request(sdev->request_queue, WRITE, GFP_ATOMIC); | 203 | req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO); |
| 86 | if (!req) | 204 | if (!req) |
| 87 | goto done; | 205 | return SCSI_DH_RES_TEMP_UNAVAIL; |
| 88 | |||
| 89 | sdev_printk(KERN_INFO, sdev, "sending START_STOP."); | ||
| 90 | 206 | ||
| 91 | req->cmd_type = REQ_TYPE_BLOCK_PC; | 207 | req->cmd_type = REQ_TYPE_BLOCK_PC; |
| 92 | req->cmd_flags |= REQ_FAILFAST; | 208 | req->cmd_flags |= REQ_FAILFAST; |
| @@ -98,95 +214,153 @@ static int hp_sw_activate(struct scsi_device *sdev) | |||
| 98 | req->sense = h->sense; | 214 | req->sense = h->sense; |
| 99 | memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); | 215 | memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); |
| 100 | req->sense_len = 0; | 216 | req->sense_len = 0; |
| 217 | retry = h->retries; | ||
| 101 | 218 | ||
| 219 | retry: | ||
| 102 | ret = blk_execute_rq(req->q, NULL, req, 1); | 220 | ret = blk_execute_rq(req->q, NULL, req, 1); |
| 103 | if (!ret) /* SUCCESS */ | 221 | if (ret == -EIO) { |
| 104 | ret = hp_sw_done(sdev); | 222 | if (req->sense_len > 0) { |
| 105 | else | 223 | ret = start_done(sdev, h->sense); |
| 224 | } else { | ||
| 225 | sdev_printk(KERN_WARNING, sdev, | ||
| 226 | "%s: sending start_stop_unit failed with %x\n", | ||
| 227 | HP_SW_NAME, req->errors); | ||
| 228 | ret = SCSI_DH_IO; | ||
| 229 | } | ||
| 230 | } else | ||
| 231 | ret = SCSI_DH_OK; | ||
| 232 | |||
| 233 | if (ret == SCSI_DH_RETRY) { | ||
| 234 | if (--retry) | ||
| 235 | goto retry; | ||
| 106 | ret = SCSI_DH_IO; | 236 | ret = SCSI_DH_IO; |
| 107 | done: | 237 | } |
| 238 | |||
| 239 | blk_put_request(req); | ||
| 240 | |||
| 241 | return ret; | ||
| 242 | } | ||
| 243 | |||
| 244 | static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req) | ||
| 245 | { | ||
| 246 | struct hp_sw_dh_data *h = get_hp_sw_data(sdev); | ||
| 247 | int ret = BLKPREP_OK; | ||
| 248 | |||
| 249 | if (h->path_state != HP_SW_PATH_ACTIVE) { | ||
| 250 | ret = BLKPREP_KILL; | ||
| 251 | req->cmd_flags |= REQ_QUIET; | ||
| 252 | } | ||
| 253 | return ret; | ||
| 254 | |||
| 255 | } | ||
| 256 | |||
| 257 | /* | ||
| 258 | * hp_sw_activate - Activate a path | ||
| 259 | * @sdev: sdev on the path to be activated | ||
| 260 | * | ||
| 261 | * The HP Active/Passive firmware is pretty simple; | ||
| 262 | * the passive path reports NOT READY with sense codes | ||
| 263 | * 0x04/0x02; a START STOP UNIT command will then | ||
| 264 | * activate the passive path (and deactivate the | ||
| 265 | * previously active one). | ||
| 266 | */ | ||
| 267 | static int hp_sw_activate(struct scsi_device *sdev) | ||
| 268 | { | ||
| 269 | int ret = SCSI_DH_OK; | ||
| 270 | struct hp_sw_dh_data *h = get_hp_sw_data(sdev); | ||
| 271 | |||
| 272 | ret = hp_sw_tur(sdev, h); | ||
| 273 | |||
| 274 | if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE) { | ||
| 275 | ret = hp_sw_start_stop(sdev, h); | ||
| 276 | if (ret == SCSI_DH_OK) | ||
| 277 | sdev_printk(KERN_INFO, sdev, | ||
| 278 | "%s: activated path\n", | ||
| 279 | HP_SW_NAME); | ||
| 280 | } | ||
| 281 | |||
| 108 | return ret; | 282 | return ret; |
| 109 | } | 283 | } |
| 110 | 284 | ||
| 111 | static const struct { | 285 | const struct scsi_dh_devlist hp_sw_dh_data_list[] = { |
| 112 | char *vendor; | 286 | {"COMPAQ", "MSA1000 VOLUME"}, |
| 113 | char *model; | 287 | {"COMPAQ", "HSV110"}, |
| 114 | } hp_sw_dh_data_list[] = { | 288 | {"HP", "HSV100"}, |
| 115 | {"COMPAQ", "MSA"}, | ||
| 116 | {"HP", "HSV"}, | ||
| 117 | {"DEC", "HSG80"}, | 289 | {"DEC", "HSG80"}, |
| 118 | {NULL, NULL}, | 290 | {NULL, NULL}, |
| 119 | }; | 291 | }; |
| 120 | 292 | ||
| 121 | static int hp_sw_bus_notify(struct notifier_block *, unsigned long, void *); | 293 | static int hp_sw_bus_attach(struct scsi_device *sdev); |
| 294 | static void hp_sw_bus_detach(struct scsi_device *sdev); | ||
| 122 | 295 | ||
| 123 | static struct scsi_device_handler hp_sw_dh = { | 296 | static struct scsi_device_handler hp_sw_dh = { |
| 124 | .name = HP_SW_NAME, | 297 | .name = HP_SW_NAME, |
| 125 | .module = THIS_MODULE, | 298 | .module = THIS_MODULE, |
| 126 | .nb.notifier_call = hp_sw_bus_notify, | 299 | .devlist = hp_sw_dh_data_list, |
| 300 | .attach = hp_sw_bus_attach, | ||
| 301 | .detach = hp_sw_bus_detach, | ||
| 127 | .activate = hp_sw_activate, | 302 | .activate = hp_sw_activate, |
| 303 | .prep_fn = hp_sw_prep_fn, | ||
| 128 | }; | 304 | }; |
| 129 | 305 | ||
| 130 | static int hp_sw_bus_notify(struct notifier_block *nb, | 306 | static int hp_sw_bus_attach(struct scsi_device *sdev) |
| 131 | unsigned long action, void *data) | ||
| 132 | { | 307 | { |
| 133 | struct device *dev = data; | ||
| 134 | struct scsi_device *sdev; | ||
| 135 | struct scsi_dh_data *scsi_dh_data; | 308 | struct scsi_dh_data *scsi_dh_data; |
| 136 | int i, found = 0; | 309 | struct hp_sw_dh_data *h; |
| 137 | unsigned long flags; | 310 | unsigned long flags; |
| 311 | int ret; | ||
| 138 | 312 | ||
| 139 | if (!scsi_is_sdev_device(dev)) | 313 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) |
| 314 | + sizeof(struct hp_sw_dh_data) , GFP_KERNEL); | ||
| 315 | if (!scsi_dh_data) { | ||
| 316 | sdev_printk(KERN_ERR, sdev, "%s: Attach Failed\n", | ||
| 317 | HP_SW_NAME); | ||
| 140 | return 0; | 318 | return 0; |
| 319 | } | ||
| 141 | 320 | ||
| 142 | sdev = to_scsi_device(dev); | 321 | scsi_dh_data->scsi_dh = &hp_sw_dh; |
| 143 | 322 | h = (struct hp_sw_dh_data *) scsi_dh_data->buf; | |
| 144 | if (action == BUS_NOTIFY_ADD_DEVICE) { | 323 | h->path_state = HP_SW_PATH_UNINITIALIZED; |
| 145 | for (i = 0; hp_sw_dh_data_list[i].vendor; i++) { | 324 | h->retries = HP_SW_RETRIES; |
| 146 | if (!strncmp(sdev->vendor, hp_sw_dh_data_list[i].vendor, | ||
| 147 | strlen(hp_sw_dh_data_list[i].vendor)) && | ||
| 148 | !strncmp(sdev->model, hp_sw_dh_data_list[i].model, | ||
| 149 | strlen(hp_sw_dh_data_list[i].model))) { | ||
| 150 | found = 1; | ||
| 151 | break; | ||
| 152 | } | ||
| 153 | } | ||
| 154 | if (!found) | ||
| 155 | goto out; | ||
| 156 | 325 | ||
| 157 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) | 326 | ret = hp_sw_tur(sdev, h); |
| 158 | + sizeof(struct hp_sw_dh_data) , GFP_KERNEL); | 327 | if (ret != SCSI_DH_OK || h->path_state == HP_SW_PATH_UNINITIALIZED) |
| 159 | if (!scsi_dh_data) { | 328 | goto failed; |
| 160 | sdev_printk(KERN_ERR, sdev, "Attach Failed %s.\n", | ||
| 161 | HP_SW_NAME); | ||
| 162 | goto out; | ||
| 163 | } | ||
| 164 | 329 | ||
| 165 | scsi_dh_data->scsi_dh = &hp_sw_dh; | 330 | if (!try_module_get(THIS_MODULE)) |
| 166 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | 331 | goto failed; |
| 167 | sdev->scsi_dh_data = scsi_dh_data; | ||
| 168 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
| 169 | try_module_get(THIS_MODULE); | ||
| 170 | 332 | ||
| 171 | sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", HP_SW_NAME); | 333 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); |
| 172 | } else if (action == BUS_NOTIFY_DEL_DEVICE) { | 334 | sdev->scsi_dh_data = scsi_dh_data; |
| 173 | if (sdev->scsi_dh_data == NULL || | 335 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); |
| 174 | sdev->scsi_dh_data->scsi_dh != &hp_sw_dh) | ||
| 175 | goto out; | ||
| 176 | 336 | ||
| 177 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | 337 | sdev_printk(KERN_INFO, sdev, "%s: attached to %s path\n", |
| 178 | scsi_dh_data = sdev->scsi_dh_data; | 338 | HP_SW_NAME, h->path_state == HP_SW_PATH_ACTIVE? |
| 179 | sdev->scsi_dh_data = NULL; | 339 | "active":"passive"); |
| 180 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
| 181 | module_put(THIS_MODULE); | ||
| 182 | 340 | ||
| 183 | sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", HP_SW_NAME); | 341 | return 0; |
| 184 | 342 | ||
| 185 | kfree(scsi_dh_data); | 343 | failed: |
| 186 | } | 344 | kfree(scsi_dh_data); |
| 345 | sdev_printk(KERN_ERR, sdev, "%s: not attached\n", | ||
| 346 | HP_SW_NAME); | ||
| 347 | return -EINVAL; | ||
| 348 | } | ||
| 187 | 349 | ||
| 188 | out: | 350 | static void hp_sw_bus_detach( struct scsi_device *sdev ) |
| 189 | return 0; | 351 | { |
| 352 | struct scsi_dh_data *scsi_dh_data; | ||
| 353 | unsigned long flags; | ||
| 354 | |||
| 355 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
| 356 | scsi_dh_data = sdev->scsi_dh_data; | ||
| 357 | sdev->scsi_dh_data = NULL; | ||
| 358 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
| 359 | module_put(THIS_MODULE); | ||
| 360 | |||
| 361 | sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", HP_SW_NAME); | ||
| 362 | |||
| 363 | kfree(scsi_dh_data); | ||
| 190 | } | 364 | } |
| 191 | 365 | ||
| 192 | static int __init hp_sw_init(void) | 366 | static int __init hp_sw_init(void) |
| @@ -202,6 +376,6 @@ static void __exit hp_sw_exit(void) | |||
| 202 | module_init(hp_sw_init); | 376 | module_init(hp_sw_init); |
| 203 | module_exit(hp_sw_exit); | 377 | module_exit(hp_sw_exit); |
| 204 | 378 | ||
| 205 | MODULE_DESCRIPTION("HP MSA 1000"); | 379 | MODULE_DESCRIPTION("HP Active/Passive driver"); |
| 206 | MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu"); | 380 | MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu"); |
| 207 | MODULE_LICENSE("GPL"); | 381 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index fdf34b0ec6e1..b093a501f8ae 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c | |||
| @@ -173,6 +173,11 @@ struct rdac_dh_data { | |||
| 173 | #define RDAC_STATE_ACTIVE 0 | 173 | #define RDAC_STATE_ACTIVE 0 |
| 174 | #define RDAC_STATE_PASSIVE 1 | 174 | #define RDAC_STATE_PASSIVE 1 |
| 175 | unsigned char state; | 175 | unsigned char state; |
| 176 | |||
| 177 | #define RDAC_LUN_UNOWNED 0 | ||
| 178 | #define RDAC_LUN_OWNED 1 | ||
| 179 | #define RDAC_LUN_AVT 2 | ||
| 180 | char lun_state; | ||
| 176 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | 181 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; |
| 177 | union { | 182 | union { |
| 178 | struct c2_inquiry c2; | 183 | struct c2_inquiry c2; |
| @@ -182,6 +187,13 @@ struct rdac_dh_data { | |||
| 182 | } inq; | 187 | } inq; |
| 183 | }; | 188 | }; |
| 184 | 189 | ||
| 190 | static const char *lun_state[] = | ||
| 191 | { | ||
| 192 | "unowned", | ||
| 193 | "owned", | ||
| 194 | "owned (AVT mode)", | ||
| 195 | }; | ||
| 196 | |||
| 185 | static LIST_HEAD(ctlr_list); | 197 | static LIST_HEAD(ctlr_list); |
| 186 | static DEFINE_SPINLOCK(list_lock); | 198 | static DEFINE_SPINLOCK(list_lock); |
| 187 | 199 | ||
| @@ -197,9 +209,8 @@ static struct request *get_rdac_req(struct scsi_device *sdev, | |||
| 197 | { | 209 | { |
| 198 | struct request *rq; | 210 | struct request *rq; |
| 199 | struct request_queue *q = sdev->request_queue; | 211 | struct request_queue *q = sdev->request_queue; |
| 200 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
| 201 | 212 | ||
| 202 | rq = blk_get_request(q, rw, GFP_KERNEL); | 213 | rq = blk_get_request(q, rw, GFP_NOIO); |
| 203 | 214 | ||
| 204 | if (!rq) { | 215 | if (!rq) { |
| 205 | sdev_printk(KERN_INFO, sdev, | 216 | sdev_printk(KERN_INFO, sdev, |
| @@ -207,17 +218,14 @@ static struct request *get_rdac_req(struct scsi_device *sdev, | |||
| 207 | return NULL; | 218 | return NULL; |
| 208 | } | 219 | } |
| 209 | 220 | ||
| 210 | if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_KERNEL)) { | 221 | if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) { |
| 211 | blk_put_request(rq); | 222 | blk_put_request(rq); |
| 212 | sdev_printk(KERN_INFO, sdev, | 223 | sdev_printk(KERN_INFO, sdev, |
| 213 | "get_rdac_req: blk_rq_map_kern failed.\n"); | 224 | "get_rdac_req: blk_rq_map_kern failed.\n"); |
| 214 | return NULL; | 225 | return NULL; |
| 215 | } | 226 | } |
| 216 | 227 | ||
| 217 | memset(&rq->cmd, 0, BLK_MAX_CDB); | 228 | memset(rq->cmd, 0, BLK_MAX_CDB); |
| 218 | rq->sense = h->sense; | ||
| 219 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
| 220 | rq->sense_len = 0; | ||
| 221 | 229 | ||
| 222 | rq->cmd_type = REQ_TYPE_BLOCK_PC; | 230 | rq->cmd_type = REQ_TYPE_BLOCK_PC; |
| 223 | rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; | 231 | rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; |
| @@ -227,12 +235,12 @@ static struct request *get_rdac_req(struct scsi_device *sdev, | |||
| 227 | return rq; | 235 | return rq; |
| 228 | } | 236 | } |
| 229 | 237 | ||
| 230 | static struct request *rdac_failover_get(struct scsi_device *sdev) | 238 | static struct request *rdac_failover_get(struct scsi_device *sdev, |
| 239 | struct rdac_dh_data *h) | ||
| 231 | { | 240 | { |
| 232 | struct request *rq; | 241 | struct request *rq; |
| 233 | struct rdac_mode_common *common; | 242 | struct rdac_mode_common *common; |
| 234 | unsigned data_size; | 243 | unsigned data_size; |
| 235 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
| 236 | 244 | ||
| 237 | if (h->ctlr->use_ms10) { | 245 | if (h->ctlr->use_ms10) { |
| 238 | struct rdac_pg_expanded *rdac_pg; | 246 | struct rdac_pg_expanded *rdac_pg; |
| @@ -277,6 +285,10 @@ static struct request *rdac_failover_get(struct scsi_device *sdev) | |||
| 277 | } | 285 | } |
| 278 | rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); | 286 | rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); |
| 279 | 287 | ||
| 288 | rq->sense = h->sense; | ||
| 289 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
| 290 | rq->sense_len = 0; | ||
| 291 | |||
| 280 | return rq; | 292 | return rq; |
| 281 | } | 293 | } |
| 282 | 294 | ||
| @@ -321,11 +333,10 @@ done: | |||
| 321 | } | 333 | } |
| 322 | 334 | ||
| 323 | static int submit_inquiry(struct scsi_device *sdev, int page_code, | 335 | static int submit_inquiry(struct scsi_device *sdev, int page_code, |
| 324 | unsigned int len) | 336 | unsigned int len, struct rdac_dh_data *h) |
| 325 | { | 337 | { |
| 326 | struct request *rq; | 338 | struct request *rq; |
| 327 | struct request_queue *q = sdev->request_queue; | 339 | struct request_queue *q = sdev->request_queue; |
| 328 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
| 329 | int err = SCSI_DH_RES_TEMP_UNAVAIL; | 340 | int err = SCSI_DH_RES_TEMP_UNAVAIL; |
| 330 | 341 | ||
| 331 | rq = get_rdac_req(sdev, &h->inq, len, READ); | 342 | rq = get_rdac_req(sdev, &h->inq, len, READ); |
| @@ -338,59 +349,68 @@ static int submit_inquiry(struct scsi_device *sdev, int page_code, | |||
| 338 | rq->cmd[2] = page_code; | 349 | rq->cmd[2] = page_code; |
| 339 | rq->cmd[4] = len; | 350 | rq->cmd[4] = len; |
| 340 | rq->cmd_len = COMMAND_SIZE(INQUIRY); | 351 | rq->cmd_len = COMMAND_SIZE(INQUIRY); |
| 352 | |||
| 353 | rq->sense = h->sense; | ||
| 354 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
| 355 | rq->sense_len = 0; | ||
| 356 | |||
| 341 | err = blk_execute_rq(q, NULL, rq, 1); | 357 | err = blk_execute_rq(q, NULL, rq, 1); |
| 342 | if (err == -EIO) | 358 | if (err == -EIO) |
| 343 | err = SCSI_DH_IO; | 359 | err = SCSI_DH_IO; |
| 360 | |||
| 361 | blk_put_request(rq); | ||
| 344 | done: | 362 | done: |
| 345 | return err; | 363 | return err; |
| 346 | } | 364 | } |
| 347 | 365 | ||
| 348 | static int get_lun(struct scsi_device *sdev) | 366 | static int get_lun(struct scsi_device *sdev, struct rdac_dh_data *h) |
| 349 | { | 367 | { |
| 350 | int err; | 368 | int err; |
| 351 | struct c8_inquiry *inqp; | 369 | struct c8_inquiry *inqp; |
| 352 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
| 353 | 370 | ||
| 354 | err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry)); | 371 | err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry), h); |
| 355 | if (err == SCSI_DH_OK) { | 372 | if (err == SCSI_DH_OK) { |
| 356 | inqp = &h->inq.c8; | 373 | inqp = &h->inq.c8; |
| 357 | h->lun = inqp->lun[7]; /* currently it uses only one byte */ | 374 | if (inqp->page_code != 0xc8) |
| 375 | return SCSI_DH_NOSYS; | ||
| 376 | if (inqp->page_id[0] != 'e' || inqp->page_id[1] != 'd' || | ||
| 377 | inqp->page_id[2] != 'i' || inqp->page_id[3] != 'd') | ||
| 378 | return SCSI_DH_NOSYS; | ||
| 379 | h->lun = scsilun_to_int((struct scsi_lun *)inqp->lun); | ||
| 358 | } | 380 | } |
| 359 | return err; | 381 | return err; |
| 360 | } | 382 | } |
| 361 | 383 | ||
| 362 | #define RDAC_OWNED 0 | 384 | static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h) |
| 363 | #define RDAC_UNOWNED 1 | ||
| 364 | #define RDAC_FAILED 2 | ||
| 365 | static int check_ownership(struct scsi_device *sdev) | ||
| 366 | { | 385 | { |
| 367 | int err; | 386 | int err; |
| 368 | struct c9_inquiry *inqp; | 387 | struct c9_inquiry *inqp; |
| 369 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
| 370 | 388 | ||
| 371 | err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry)); | 389 | err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry), h); |
| 372 | if (err == SCSI_DH_OK) { | 390 | if (err == SCSI_DH_OK) { |
| 373 | err = RDAC_UNOWNED; | ||
| 374 | inqp = &h->inq.c9; | 391 | inqp = &h->inq.c9; |
| 375 | /* | 392 | if ((inqp->avte_cvp >> 7) == 0x1) { |
| 376 | * If in AVT mode or if the path already owns the LUN, | 393 | /* LUN in AVT mode */ |
| 377 | * return RDAC_OWNED; | 394 | sdev_printk(KERN_NOTICE, sdev, |
| 378 | */ | 395 | "%s: AVT mode detected\n", |
| 379 | if (((inqp->avte_cvp >> 7) == 0x1) || | 396 | RDAC_NAME); |
| 380 | ((inqp->avte_cvp & 0x1) != 0)) | 397 | h->lun_state = RDAC_LUN_AVT; |
| 381 | err = RDAC_OWNED; | 398 | } else if ((inqp->avte_cvp & 0x1) != 0) { |
| 382 | } else | 399 | /* LUN was owned by the controller */ |
| 383 | err = RDAC_FAILED; | 400 | h->lun_state = RDAC_LUN_OWNED; |
| 401 | } | ||
| 402 | } | ||
| 403 | |||
| 384 | return err; | 404 | return err; |
| 385 | } | 405 | } |
| 386 | 406 | ||
| 387 | static int initialize_controller(struct scsi_device *sdev) | 407 | static int initialize_controller(struct scsi_device *sdev, |
| 408 | struct rdac_dh_data *h) | ||
| 388 | { | 409 | { |
| 389 | int err; | 410 | int err; |
| 390 | struct c4_inquiry *inqp; | 411 | struct c4_inquiry *inqp; |
| 391 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
| 392 | 412 | ||
| 393 | err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry)); | 413 | err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry), h); |
| 394 | if (err == SCSI_DH_OK) { | 414 | if (err == SCSI_DH_OK) { |
| 395 | inqp = &h->inq.c4; | 415 | inqp = &h->inq.c4; |
| 396 | h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id); | 416 | h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id); |
| @@ -400,13 +420,12 @@ static int initialize_controller(struct scsi_device *sdev) | |||
| 400 | return err; | 420 | return err; |
| 401 | } | 421 | } |
| 402 | 422 | ||
| 403 | static int set_mode_select(struct scsi_device *sdev) | 423 | static int set_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h) |
| 404 | { | 424 | { |
| 405 | int err; | 425 | int err; |
| 406 | struct c2_inquiry *inqp; | 426 | struct c2_inquiry *inqp; |
| 407 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
| 408 | 427 | ||
| 409 | err = submit_inquiry(sdev, 0xC2, sizeof(struct c2_inquiry)); | 428 | err = submit_inquiry(sdev, 0xC2, sizeof(struct c2_inquiry), h); |
| 410 | if (err == SCSI_DH_OK) { | 429 | if (err == SCSI_DH_OK) { |
| 411 | inqp = &h->inq.c2; | 430 | inqp = &h->inq.c2; |
| 412 | /* | 431 | /* |
| @@ -421,13 +440,13 @@ static int set_mode_select(struct scsi_device *sdev) | |||
| 421 | return err; | 440 | return err; |
| 422 | } | 441 | } |
| 423 | 442 | ||
| 424 | static int mode_select_handle_sense(struct scsi_device *sdev) | 443 | static int mode_select_handle_sense(struct scsi_device *sdev, |
| 444 | unsigned char *sensebuf) | ||
| 425 | { | 445 | { |
| 426 | struct scsi_sense_hdr sense_hdr; | 446 | struct scsi_sense_hdr sense_hdr; |
| 427 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
| 428 | int sense, err = SCSI_DH_IO, ret; | 447 | int sense, err = SCSI_DH_IO, ret; |
| 429 | 448 | ||
| 430 | ret = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sense_hdr); | 449 | ret = scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE, &sense_hdr); |
| 431 | if (!ret) | 450 | if (!ret) |
| 432 | goto done; | 451 | goto done; |
| 433 | 452 | ||
| @@ -451,14 +470,13 @@ done: | |||
| 451 | return err; | 470 | return err; |
| 452 | } | 471 | } |
| 453 | 472 | ||
| 454 | static int send_mode_select(struct scsi_device *sdev) | 473 | static int send_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h) |
| 455 | { | 474 | { |
| 456 | struct request *rq; | 475 | struct request *rq; |
| 457 | struct request_queue *q = sdev->request_queue; | 476 | struct request_queue *q = sdev->request_queue; |
| 458 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
| 459 | int err = SCSI_DH_RES_TEMP_UNAVAIL; | 477 | int err = SCSI_DH_RES_TEMP_UNAVAIL; |
| 460 | 478 | ||
| 461 | rq = rdac_failover_get(sdev); | 479 | rq = rdac_failover_get(sdev, h); |
| 462 | if (!rq) | 480 | if (!rq) |
| 463 | goto done; | 481 | goto done; |
| 464 | 482 | ||
| @@ -466,9 +484,11 @@ static int send_mode_select(struct scsi_device *sdev) | |||
| 466 | 484 | ||
| 467 | err = blk_execute_rq(q, NULL, rq, 1); | 485 | err = blk_execute_rq(q, NULL, rq, 1); |
| 468 | if (err != SCSI_DH_OK) | 486 | if (err != SCSI_DH_OK) |
| 469 | err = mode_select_handle_sense(sdev); | 487 | err = mode_select_handle_sense(sdev, h->sense); |
| 470 | if (err == SCSI_DH_OK) | 488 | if (err == SCSI_DH_OK) |
| 471 | h->state = RDAC_STATE_ACTIVE; | 489 | h->state = RDAC_STATE_ACTIVE; |
| 490 | |||
| 491 | blk_put_request(rq); | ||
| 472 | done: | 492 | done: |
| 473 | return err; | 493 | return err; |
| 474 | } | 494 | } |
| @@ -478,38 +498,23 @@ static int rdac_activate(struct scsi_device *sdev) | |||
| 478 | struct rdac_dh_data *h = get_rdac_data(sdev); | 498 | struct rdac_dh_data *h = get_rdac_data(sdev); |
| 479 | int err = SCSI_DH_OK; | 499 | int err = SCSI_DH_OK; |
| 480 | 500 | ||
| 481 | if (h->lun == UNINITIALIZED_LUN) { | 501 | err = check_ownership(sdev, h); |
| 482 | err = get_lun(sdev); | 502 | if (err != SCSI_DH_OK) |
| 483 | if (err != SCSI_DH_OK) | ||
| 484 | goto done; | ||
| 485 | } | ||
| 486 | |||
| 487 | err = check_ownership(sdev); | ||
| 488 | switch (err) { | ||
| 489 | case RDAC_UNOWNED: | ||
| 490 | break; | ||
| 491 | case RDAC_OWNED: | ||
| 492 | err = SCSI_DH_OK; | ||
| 493 | goto done; | ||
| 494 | case RDAC_FAILED: | ||
| 495 | default: | ||
| 496 | err = SCSI_DH_IO; | ||
| 497 | goto done; | 503 | goto done; |
| 498 | } | ||
| 499 | 504 | ||
| 500 | if (!h->ctlr) { | 505 | if (!h->ctlr) { |
| 501 | err = initialize_controller(sdev); | 506 | err = initialize_controller(sdev, h); |
| 502 | if (err != SCSI_DH_OK) | 507 | if (err != SCSI_DH_OK) |
| 503 | goto done; | 508 | goto done; |
| 504 | } | 509 | } |
| 505 | 510 | ||
| 506 | if (h->ctlr->use_ms10 == -1) { | 511 | if (h->ctlr->use_ms10 == -1) { |
| 507 | err = set_mode_select(sdev); | 512 | err = set_mode_select(sdev, h); |
| 508 | if (err != SCSI_DH_OK) | 513 | if (err != SCSI_DH_OK) |
| 509 | goto done; | 514 | goto done; |
| 510 | } | 515 | } |
| 511 | 516 | if (h->lun_state == RDAC_LUN_UNOWNED) | |
| 512 | err = send_mode_select(sdev); | 517 | err = send_mode_select(sdev, h); |
| 513 | done: | 518 | done: |
| 514 | return err; | 519 | return err; |
| 515 | } | 520 | } |
| @@ -569,10 +574,7 @@ static int rdac_check_sense(struct scsi_device *sdev, | |||
| 569 | return SCSI_RETURN_NOT_HANDLED; | 574 | return SCSI_RETURN_NOT_HANDLED; |
| 570 | } | 575 | } |
| 571 | 576 | ||
| 572 | static const struct { | 577 | const struct scsi_dh_devlist rdac_dev_list[] = { |
| 573 | char *vendor; | ||
| 574 | char *model; | ||
| 575 | } rdac_dev_list[] = { | ||
| 576 | {"IBM", "1722"}, | 578 | {"IBM", "1722"}, |
| 577 | {"IBM", "1724"}, | 579 | {"IBM", "1724"}, |
| 578 | {"IBM", "1726"}, | 580 | {"IBM", "1726"}, |
| @@ -590,89 +592,89 @@ static const struct { | |||
| 590 | {NULL, NULL}, | 592 | {NULL, NULL}, |
| 591 | }; | 593 | }; |
| 592 | 594 | ||
| 593 | static int rdac_bus_notify(struct notifier_block *, unsigned long, void *); | 595 | static int rdac_bus_attach(struct scsi_device *sdev); |
| 596 | static void rdac_bus_detach(struct scsi_device *sdev); | ||
| 594 | 597 | ||
| 595 | static struct scsi_device_handler rdac_dh = { | 598 | static struct scsi_device_handler rdac_dh = { |
| 596 | .name = RDAC_NAME, | 599 | .name = RDAC_NAME, |
| 597 | .module = THIS_MODULE, | 600 | .module = THIS_MODULE, |
| 598 | .nb.notifier_call = rdac_bus_notify, | 601 | .devlist = rdac_dev_list, |
| 599 | .prep_fn = rdac_prep_fn, | 602 | .prep_fn = rdac_prep_fn, |
| 600 | .check_sense = rdac_check_sense, | 603 | .check_sense = rdac_check_sense, |
| 604 | .attach = rdac_bus_attach, | ||
| 605 | .detach = rdac_bus_detach, | ||
| 601 | .activate = rdac_activate, | 606 | .activate = rdac_activate, |
| 602 | }; | 607 | }; |
| 603 | 608 | ||
| 604 | /* | 609 | static int rdac_bus_attach(struct scsi_device *sdev) |
| 605 | * TODO: need some interface so we can set trespass values | ||
| 606 | */ | ||
| 607 | static int rdac_bus_notify(struct notifier_block *nb, | ||
| 608 | unsigned long action, void *data) | ||
| 609 | { | 610 | { |
| 610 | struct device *dev = data; | ||
| 611 | struct scsi_device *sdev; | ||
| 612 | struct scsi_dh_data *scsi_dh_data; | 611 | struct scsi_dh_data *scsi_dh_data; |
| 613 | struct rdac_dh_data *h; | 612 | struct rdac_dh_data *h; |
| 614 | int i, found = 0; | ||
| 615 | unsigned long flags; | 613 | unsigned long flags; |
| 614 | int err; | ||
| 616 | 615 | ||
| 617 | if (!scsi_is_sdev_device(dev)) | 616 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) |
| 617 | + sizeof(*h) , GFP_KERNEL); | ||
| 618 | if (!scsi_dh_data) { | ||
| 619 | sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n", | ||
| 620 | RDAC_NAME); | ||
| 618 | return 0; | 621 | return 0; |
| 622 | } | ||
| 619 | 623 | ||
| 620 | sdev = to_scsi_device(dev); | 624 | scsi_dh_data->scsi_dh = &rdac_dh; |
| 621 | 625 | h = (struct rdac_dh_data *) scsi_dh_data->buf; | |
| 622 | if (action == BUS_NOTIFY_ADD_DEVICE) { | 626 | h->lun = UNINITIALIZED_LUN; |
| 623 | for (i = 0; rdac_dev_list[i].vendor; i++) { | 627 | h->state = RDAC_STATE_ACTIVE; |
| 624 | if (!strncmp(sdev->vendor, rdac_dev_list[i].vendor, | ||
| 625 | strlen(rdac_dev_list[i].vendor)) && | ||
| 626 | !strncmp(sdev->model, rdac_dev_list[i].model, | ||
| 627 | strlen(rdac_dev_list[i].model))) { | ||
| 628 | found = 1; | ||
| 629 | break; | ||
| 630 | } | ||
| 631 | } | ||
| 632 | if (!found) | ||
| 633 | goto out; | ||
| 634 | 628 | ||
| 635 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) | 629 | err = get_lun(sdev, h); |
| 636 | + sizeof(*h) , GFP_KERNEL); | 630 | if (err != SCSI_DH_OK) |
| 637 | if (!scsi_dh_data) { | 631 | goto failed; |
| 638 | sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n", | ||
| 639 | RDAC_NAME); | ||
| 640 | goto out; | ||
| 641 | } | ||
| 642 | 632 | ||
| 643 | scsi_dh_data->scsi_dh = &rdac_dh; | 633 | err = check_ownership(sdev, h); |
| 644 | h = (struct rdac_dh_data *) scsi_dh_data->buf; | 634 | if (err != SCSI_DH_OK) |
| 645 | h->lun = UNINITIALIZED_LUN; | 635 | goto failed; |
| 646 | h->state = RDAC_STATE_ACTIVE; | 636 | |
| 647 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | 637 | if (!try_module_get(THIS_MODULE)) |
| 648 | sdev->scsi_dh_data = scsi_dh_data; | 638 | goto failed; |
| 649 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | 639 | |
| 650 | try_module_get(THIS_MODULE); | 640 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); |
| 651 | 641 | sdev->scsi_dh_data = scsi_dh_data; | |
| 652 | sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", RDAC_NAME); | 642 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); |
| 653 | 643 | ||
| 654 | } else if (action == BUS_NOTIFY_DEL_DEVICE) { | 644 | sdev_printk(KERN_NOTICE, sdev, |
| 655 | if (sdev->scsi_dh_data == NULL || | 645 | "%s: LUN %d (%s)\n", |
| 656 | sdev->scsi_dh_data->scsi_dh != &rdac_dh) | 646 | RDAC_NAME, h->lun, lun_state[(int)h->lun_state]); |
| 657 | goto out; | ||
| 658 | |||
| 659 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
| 660 | scsi_dh_data = sdev->scsi_dh_data; | ||
| 661 | sdev->scsi_dh_data = NULL; | ||
| 662 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
| 663 | |||
| 664 | h = (struct rdac_dh_data *) scsi_dh_data->buf; | ||
| 665 | if (h->ctlr) | ||
| 666 | kref_put(&h->ctlr->kref, release_controller); | ||
| 667 | kfree(scsi_dh_data); | ||
| 668 | module_put(THIS_MODULE); | ||
| 669 | sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", RDAC_NAME); | ||
| 670 | } | ||
| 671 | 647 | ||
| 672 | out: | ||
| 673 | return 0; | 648 | return 0; |
| 649 | |||
| 650 | failed: | ||
| 651 | kfree(scsi_dh_data); | ||
| 652 | sdev_printk(KERN_ERR, sdev, "%s: not attached\n", | ||
| 653 | RDAC_NAME); | ||
| 654 | return -EINVAL; | ||
| 655 | } | ||
| 656 | |||
| 657 | static void rdac_bus_detach( struct scsi_device *sdev ) | ||
| 658 | { | ||
| 659 | struct scsi_dh_data *scsi_dh_data; | ||
| 660 | struct rdac_dh_data *h; | ||
| 661 | unsigned long flags; | ||
| 662 | |||
| 663 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
| 664 | scsi_dh_data = sdev->scsi_dh_data; | ||
| 665 | sdev->scsi_dh_data = NULL; | ||
| 666 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
| 667 | |||
| 668 | h = (struct rdac_dh_data *) scsi_dh_data->buf; | ||
| 669 | if (h->ctlr) | ||
| 670 | kref_put(&h->ctlr->kref, release_controller); | ||
| 671 | kfree(scsi_dh_data); | ||
| 672 | module_put(THIS_MODULE); | ||
| 673 | sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", RDAC_NAME); | ||
| 674 | } | 674 | } |
| 675 | 675 | ||
| 676 | |||
| 677 | |||
| 676 | static int __init rdac_init(void) | 678 | static int __init rdac_init(void) |
| 677 | { | 679 | { |
| 678 | int r; | 680 | int r; |
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index c4a7c06793c5..ae560bc04f9d 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c | |||
| @@ -521,9 +521,10 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost, | |||
| 521 | static void ibmvfc_reinit_host(struct ibmvfc_host *vhost) | 521 | static void ibmvfc_reinit_host(struct ibmvfc_host *vhost) |
| 522 | { | 522 | { |
| 523 | if (vhost->action == IBMVFC_HOST_ACTION_NONE) { | 523 | if (vhost->action == IBMVFC_HOST_ACTION_NONE) { |
| 524 | scsi_block_requests(vhost->host); | 524 | if (!ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) { |
| 525 | ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING); | 525 | scsi_block_requests(vhost->host); |
| 526 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); | 526 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); |
| 527 | } | ||
| 527 | } else | 528 | } else |
| 528 | vhost->reinit = 1; | 529 | vhost->reinit = 1; |
| 529 | 530 | ||
| @@ -854,39 +855,41 @@ static void ibmvfc_retry_host_init(struct ibmvfc_host *vhost) | |||
| 854 | } | 855 | } |
| 855 | 856 | ||
| 856 | /** | 857 | /** |
| 857 | * __ibmvfc_find_target - Find the specified scsi_target (no locking) | 858 | * __ibmvfc_get_target - Find the specified scsi_target (no locking) |
| 858 | * @starget: scsi target struct | 859 | * @starget: scsi target struct |
| 859 | * | 860 | * |
| 860 | * Return value: | 861 | * Return value: |
| 861 | * ibmvfc_target struct / NULL if not found | 862 | * ibmvfc_target struct / NULL if not found |
| 862 | **/ | 863 | **/ |
| 863 | static struct ibmvfc_target *__ibmvfc_find_target(struct scsi_target *starget) | 864 | static struct ibmvfc_target *__ibmvfc_get_target(struct scsi_target *starget) |
| 864 | { | 865 | { |
| 865 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | 866 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); |
| 866 | struct ibmvfc_host *vhost = shost_priv(shost); | 867 | struct ibmvfc_host *vhost = shost_priv(shost); |
| 867 | struct ibmvfc_target *tgt; | 868 | struct ibmvfc_target *tgt; |
| 868 | 869 | ||
| 869 | list_for_each_entry(tgt, &vhost->targets, queue) | 870 | list_for_each_entry(tgt, &vhost->targets, queue) |
| 870 | if (tgt->target_id == starget->id) | 871 | if (tgt->target_id == starget->id) { |
| 872 | kref_get(&tgt->kref); | ||
| 871 | return tgt; | 873 | return tgt; |
| 874 | } | ||
| 872 | return NULL; | 875 | return NULL; |
| 873 | } | 876 | } |
| 874 | 877 | ||
| 875 | /** | 878 | /** |
| 876 | * ibmvfc_find_target - Find the specified scsi_target | 879 | * ibmvfc_get_target - Find the specified scsi_target |
| 877 | * @starget: scsi target struct | 880 | * @starget: scsi target struct |
| 878 | * | 881 | * |
| 879 | * Return value: | 882 | * Return value: |
| 880 | * ibmvfc_target struct / NULL if not found | 883 | * ibmvfc_target struct / NULL if not found |
| 881 | **/ | 884 | **/ |
| 882 | static struct ibmvfc_target *ibmvfc_find_target(struct scsi_target *starget) | 885 | static struct ibmvfc_target *ibmvfc_get_target(struct scsi_target *starget) |
| 883 | { | 886 | { |
| 884 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | 887 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); |
| 885 | struct ibmvfc_target *tgt; | 888 | struct ibmvfc_target *tgt; |
| 886 | unsigned long flags; | 889 | unsigned long flags; |
| 887 | 890 | ||
| 888 | spin_lock_irqsave(shost->host_lock, flags); | 891 | spin_lock_irqsave(shost->host_lock, flags); |
| 889 | tgt = __ibmvfc_find_target(starget); | 892 | tgt = __ibmvfc_get_target(starget); |
| 890 | spin_unlock_irqrestore(shost->host_lock, flags); | 893 | spin_unlock_irqrestore(shost->host_lock, flags); |
| 891 | return tgt; | 894 | return tgt; |
| 892 | } | 895 | } |
| @@ -963,6 +966,9 @@ static void ibmvfc_get_host_port_state(struct Scsi_Host *shost) | |||
| 963 | case IBMVFC_HALTED: | 966 | case IBMVFC_HALTED: |
| 964 | fc_host_port_state(shost) = FC_PORTSTATE_BLOCKED; | 967 | fc_host_port_state(shost) = FC_PORTSTATE_BLOCKED; |
| 965 | break; | 968 | break; |
| 969 | case IBMVFC_NO_CRQ: | ||
| 970 | fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; | ||
| 971 | break; | ||
| 966 | default: | 972 | default: |
| 967 | ibmvfc_log(vhost, 3, "Unknown port state: %d\n", vhost->state); | 973 | ibmvfc_log(vhost, 3, "Unknown port state: %d\n", vhost->state); |
| 968 | fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; | 974 | fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; |
| @@ -988,6 +994,17 @@ static void ibmvfc_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) | |||
| 988 | } | 994 | } |
| 989 | 995 | ||
| 990 | /** | 996 | /** |
| 997 | * ibmvfc_release_tgt - Free memory allocated for a target | ||
| 998 | * @kref: kref struct | ||
| 999 | * | ||
| 1000 | **/ | ||
| 1001 | static void ibmvfc_release_tgt(struct kref *kref) | ||
| 1002 | { | ||
| 1003 | struct ibmvfc_target *tgt = container_of(kref, struct ibmvfc_target, kref); | ||
| 1004 | kfree(tgt); | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | /** | ||
| 991 | * ibmvfc_get_starget_node_name - Get SCSI target's node name | 1008 | * ibmvfc_get_starget_node_name - Get SCSI target's node name |
| 992 | * @starget: scsi target struct | 1009 | * @starget: scsi target struct |
| 993 | * | 1010 | * |
| @@ -996,8 +1013,10 @@ static void ibmvfc_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) | |||
| 996 | **/ | 1013 | **/ |
| 997 | static void ibmvfc_get_starget_node_name(struct scsi_target *starget) | 1014 | static void ibmvfc_get_starget_node_name(struct scsi_target *starget) |
| 998 | { | 1015 | { |
| 999 | struct ibmvfc_target *tgt = ibmvfc_find_target(starget); | 1016 | struct ibmvfc_target *tgt = ibmvfc_get_target(starget); |
| 1000 | fc_starget_port_name(starget) = tgt ? tgt->ids.node_name : 0; | 1017 | fc_starget_port_name(starget) = tgt ? tgt->ids.node_name : 0; |
| 1018 | if (tgt) | ||
| 1019 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
| 1001 | } | 1020 | } |
| 1002 | 1021 | ||
| 1003 | /** | 1022 | /** |
| @@ -1009,8 +1028,10 @@ static void ibmvfc_get_starget_node_name(struct scsi_target *starget) | |||
| 1009 | **/ | 1028 | **/ |
| 1010 | static void ibmvfc_get_starget_port_name(struct scsi_target *starget) | 1029 | static void ibmvfc_get_starget_port_name(struct scsi_target *starget) |
| 1011 | { | 1030 | { |
| 1012 | struct ibmvfc_target *tgt = ibmvfc_find_target(starget); | 1031 | struct ibmvfc_target *tgt = ibmvfc_get_target(starget); |
| 1013 | fc_starget_port_name(starget) = tgt ? tgt->ids.port_name : 0; | 1032 | fc_starget_port_name(starget) = tgt ? tgt->ids.port_name : 0; |
| 1033 | if (tgt) | ||
| 1034 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
| 1014 | } | 1035 | } |
| 1015 | 1036 | ||
| 1016 | /** | 1037 | /** |
| @@ -1022,8 +1043,10 @@ static void ibmvfc_get_starget_port_name(struct scsi_target *starget) | |||
| 1022 | **/ | 1043 | **/ |
| 1023 | static void ibmvfc_get_starget_port_id(struct scsi_target *starget) | 1044 | static void ibmvfc_get_starget_port_id(struct scsi_target *starget) |
| 1024 | { | 1045 | { |
| 1025 | struct ibmvfc_target *tgt = ibmvfc_find_target(starget); | 1046 | struct ibmvfc_target *tgt = ibmvfc_get_target(starget); |
| 1026 | fc_starget_port_id(starget) = tgt ? tgt->scsi_id : -1; | 1047 | fc_starget_port_id(starget) = tgt ? tgt->scsi_id : -1; |
| 1048 | if (tgt) | ||
| 1049 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
| 1027 | } | 1050 | } |
| 1028 | 1051 | ||
| 1029 | /** | 1052 | /** |
| @@ -1113,7 +1136,7 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost) | |||
| 1113 | login_info->max_cmds = max_requests + IBMVFC_NUM_INTERNAL_REQ; | 1136 | login_info->max_cmds = max_requests + IBMVFC_NUM_INTERNAL_REQ; |
| 1114 | login_info->capabilities = IBMVFC_CAN_MIGRATE; | 1137 | login_info->capabilities = IBMVFC_CAN_MIGRATE; |
| 1115 | login_info->async.va = vhost->async_crq.msg_token; | 1138 | login_info->async.va = vhost->async_crq.msg_token; |
| 1116 | login_info->async.len = vhost->async_crq.size; | 1139 | login_info->async.len = vhost->async_crq.size * sizeof(*vhost->async_crq.msgs); |
| 1117 | strncpy(login_info->partition_name, vhost->partition_name, IBMVFC_MAX_NAME); | 1140 | strncpy(login_info->partition_name, vhost->partition_name, IBMVFC_MAX_NAME); |
| 1118 | strncpy(login_info->device_name, | 1141 | strncpy(login_info->device_name, |
| 1119 | vhost->host->shost_gendev.bus_id, IBMVFC_MAX_NAME); | 1142 | vhost->host->shost_gendev.bus_id, IBMVFC_MAX_NAME); |
| @@ -1404,7 +1427,7 @@ static void ibmvfc_log_error(struct ibmvfc_event *evt) | |||
| 1404 | err = cmd_status[index].name; | 1427 | err = cmd_status[index].name; |
| 1405 | } | 1428 | } |
| 1406 | 1429 | ||
| 1407 | if (!logerr && (vhost->log_level <= IBMVFC_DEFAULT_LOG_LEVEL)) | 1430 | if (!logerr && (vhost->log_level <= (IBMVFC_DEFAULT_LOG_LEVEL + 1))) |
| 1408 | return; | 1431 | return; |
| 1409 | 1432 | ||
| 1410 | if (rsp->flags & FCP_RSP_LEN_VALID) | 1433 | if (rsp->flags & FCP_RSP_LEN_VALID) |
| @@ -2054,7 +2077,7 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, | |||
| 2054 | { | 2077 | { |
| 2055 | const char *desc = ibmvfc_get_ae_desc(crq->event); | 2078 | const char *desc = ibmvfc_get_ae_desc(crq->event); |
| 2056 | 2079 | ||
| 2057 | ibmvfc_log(vhost, 2, "%s event received\n", desc); | 2080 | ibmvfc_log(vhost, 3, "%s event received\n", desc); |
| 2058 | 2081 | ||
| 2059 | switch (crq->event) { | 2082 | switch (crq->event) { |
| 2060 | case IBMVFC_AE_LINK_UP: | 2083 | case IBMVFC_AE_LINK_UP: |
| @@ -2648,17 +2671,6 @@ static void ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt, | |||
| 2648 | } | 2671 | } |
| 2649 | 2672 | ||
| 2650 | /** | 2673 | /** |
| 2651 | * ibmvfc_release_tgt - Free memory allocated for a target | ||
| 2652 | * @kref: kref struct | ||
| 2653 | * | ||
| 2654 | **/ | ||
| 2655 | static void ibmvfc_release_tgt(struct kref *kref) | ||
| 2656 | { | ||
| 2657 | struct ibmvfc_target *tgt = container_of(kref, struct ibmvfc_target, kref); | ||
| 2658 | kfree(tgt); | ||
| 2659 | } | ||
| 2660 | |||
| 2661 | /** | ||
| 2662 | * ibmvfc_tgt_prli_done - Completion handler for Process Login | 2674 | * ibmvfc_tgt_prli_done - Completion handler for Process Login |
| 2663 | * @evt: ibmvfc event struct | 2675 | * @evt: ibmvfc event struct |
| 2664 | * | 2676 | * |
| @@ -2902,6 +2914,139 @@ static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt) | |||
| 2902 | } | 2914 | } |
| 2903 | 2915 | ||
| 2904 | /** | 2916 | /** |
| 2917 | * ibmvfc_adisc_needs_plogi - Does device need PLOGI? | ||
| 2918 | * @mad: ibmvfc passthru mad struct | ||
| 2919 | * @tgt: ibmvfc target struct | ||
| 2920 | * | ||
| 2921 | * Returns: | ||
| 2922 | * 1 if PLOGI needed / 0 if PLOGI not needed | ||
| 2923 | **/ | ||
| 2924 | static int ibmvfc_adisc_needs_plogi(struct ibmvfc_passthru_mad *mad, | ||
| 2925 | struct ibmvfc_target *tgt) | ||
| 2926 | { | ||
| 2927 | if (memcmp(&mad->fc_iu.response[2], &tgt->ids.port_name, | ||
| 2928 | sizeof(tgt->ids.port_name))) | ||
| 2929 | return 1; | ||
| 2930 | if (memcmp(&mad->fc_iu.response[4], &tgt->ids.node_name, | ||
| 2931 | sizeof(tgt->ids.node_name))) | ||
| 2932 | return 1; | ||
| 2933 | if (mad->fc_iu.response[6] != tgt->scsi_id) | ||
| 2934 | return 1; | ||
| 2935 | return 0; | ||
| 2936 | } | ||
| 2937 | |||
| 2938 | /** | ||
| 2939 | * ibmvfc_tgt_adisc_done - Completion handler for ADISC | ||
| 2940 | * @evt: ibmvfc event struct | ||
| 2941 | * | ||
| 2942 | **/ | ||
| 2943 | static void ibmvfc_tgt_adisc_done(struct ibmvfc_event *evt) | ||
| 2944 | { | ||
| 2945 | struct ibmvfc_target *tgt = evt->tgt; | ||
| 2946 | struct ibmvfc_host *vhost = evt->vhost; | ||
| 2947 | struct ibmvfc_passthru_mad *mad = &evt->xfer_iu->passthru; | ||
| 2948 | u32 status = mad->common.status; | ||
| 2949 | u8 fc_reason, fc_explain; | ||
| 2950 | |||
| 2951 | vhost->discovery_threads--; | ||
| 2952 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
| 2953 | |||
| 2954 | switch (status) { | ||
| 2955 | case IBMVFC_MAD_SUCCESS: | ||
| 2956 | tgt_dbg(tgt, "ADISC succeeded\n"); | ||
| 2957 | if (ibmvfc_adisc_needs_plogi(mad, tgt)) | ||
| 2958 | tgt->need_login = 1; | ||
| 2959 | break; | ||
| 2960 | case IBMVFC_MAD_DRIVER_FAILED: | ||
| 2961 | break; | ||
| 2962 | case IBMVFC_MAD_FAILED: | ||
| 2963 | default: | ||
| 2964 | tgt->need_login = 1; | ||
| 2965 | fc_reason = (mad->fc_iu.response[1] & 0x00ff0000) >> 16; | ||
| 2966 | fc_explain = (mad->fc_iu.response[1] & 0x0000ff00) >> 8; | ||
| 2967 | tgt_info(tgt, "ADISC failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", | ||
| 2968 | ibmvfc_get_cmd_error(mad->iu.status, mad->iu.error), | ||
| 2969 | mad->iu.status, mad->iu.error, | ||
| 2970 | ibmvfc_get_fc_type(fc_reason), fc_reason, | ||
| 2971 | ibmvfc_get_ls_explain(fc_explain), fc_explain, status); | ||
| 2972 | break; | ||
| 2973 | }; | ||
| 2974 | |||
| 2975 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
| 2976 | ibmvfc_free_event(evt); | ||
| 2977 | wake_up(&vhost->work_wait_q); | ||
| 2978 | } | ||
| 2979 | |||
| 2980 | /** | ||
| 2981 | * ibmvfc_init_passthru - Initialize an event struct for FC passthru | ||
| 2982 | * @evt: ibmvfc event struct | ||
| 2983 | * | ||
| 2984 | **/ | ||
| 2985 | static void ibmvfc_init_passthru(struct ibmvfc_event *evt) | ||
| 2986 | { | ||
| 2987 | struct ibmvfc_passthru_mad *mad = &evt->iu.passthru; | ||
| 2988 | |||
| 2989 | memset(mad, 0, sizeof(*mad)); | ||
| 2990 | mad->common.version = 1; | ||
| 2991 | mad->common.opcode = IBMVFC_PASSTHRU; | ||
| 2992 | mad->common.length = sizeof(*mad) - sizeof(mad->fc_iu) - sizeof(mad->iu); | ||
| 2993 | mad->cmd_ioba.va = (u64)evt->crq.ioba + | ||
| 2994 | offsetof(struct ibmvfc_passthru_mad, iu); | ||
| 2995 | mad->cmd_ioba.len = sizeof(mad->iu); | ||
| 2996 | mad->iu.cmd_len = sizeof(mad->fc_iu.payload); | ||
| 2997 | mad->iu.rsp_len = sizeof(mad->fc_iu.response); | ||
| 2998 | mad->iu.cmd.va = (u64)evt->crq.ioba + | ||
| 2999 | offsetof(struct ibmvfc_passthru_mad, fc_iu) + | ||
| 3000 | offsetof(struct ibmvfc_passthru_fc_iu, payload); | ||
| 3001 | mad->iu.cmd.len = sizeof(mad->fc_iu.payload); | ||
| 3002 | mad->iu.rsp.va = (u64)evt->crq.ioba + | ||
| 3003 | offsetof(struct ibmvfc_passthru_mad, fc_iu) + | ||
| 3004 | offsetof(struct ibmvfc_passthru_fc_iu, response); | ||
| 3005 | mad->iu.rsp.len = sizeof(mad->fc_iu.response); | ||
| 3006 | } | ||
| 3007 | |||
| 3008 | /** | ||
| 3009 | * ibmvfc_tgt_adisc - Initiate an ADISC for specified target | ||
| 3010 | * @tgt: ibmvfc target struct | ||
| 3011 | * | ||
| 3012 | **/ | ||
| 3013 | static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt) | ||
| 3014 | { | ||
| 3015 | struct ibmvfc_passthru_mad *mad; | ||
| 3016 | struct ibmvfc_host *vhost = tgt->vhost; | ||
| 3017 | struct ibmvfc_event *evt; | ||
| 3018 | |||
| 3019 | if (vhost->discovery_threads >= disc_threads) | ||
| 3020 | return; | ||
| 3021 | |||
| 3022 | kref_get(&tgt->kref); | ||
| 3023 | evt = ibmvfc_get_event(vhost); | ||
| 3024 | vhost->discovery_threads++; | ||
| 3025 | ibmvfc_init_event(evt, ibmvfc_tgt_adisc_done, IBMVFC_MAD_FORMAT); | ||
| 3026 | evt->tgt = tgt; | ||
| 3027 | |||
| 3028 | ibmvfc_init_passthru(evt); | ||
| 3029 | mad = &evt->iu.passthru; | ||
| 3030 | mad->iu.flags = IBMVFC_FC_ELS; | ||
| 3031 | mad->iu.scsi_id = tgt->scsi_id; | ||
| 3032 | |||
| 3033 | mad->fc_iu.payload[0] = IBMVFC_ADISC; | ||
| 3034 | memcpy(&mad->fc_iu.payload[2], &vhost->login_buf->resp.port_name, | ||
| 3035 | sizeof(vhost->login_buf->resp.port_name)); | ||
| 3036 | memcpy(&mad->fc_iu.payload[4], &vhost->login_buf->resp.node_name, | ||
| 3037 | sizeof(vhost->login_buf->resp.node_name)); | ||
| 3038 | mad->fc_iu.payload[6] = vhost->login_buf->resp.scsi_id & 0x00ffffff; | ||
| 3039 | |||
| 3040 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); | ||
| 3041 | if (ibmvfc_send_event(evt, vhost, default_timeout)) { | ||
| 3042 | vhost->discovery_threads--; | ||
| 3043 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
| 3044 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
| 3045 | } else | ||
| 3046 | tgt_dbg(tgt, "Sent ADISC\n"); | ||
| 3047 | } | ||
| 3048 | |||
| 3049 | /** | ||
| 2905 | * ibmvfc_tgt_query_target_done - Completion handler for Query Target MAD | 3050 | * ibmvfc_tgt_query_target_done - Completion handler for Query Target MAD |
| 2906 | * @evt: ibmvfc event struct | 3051 | * @evt: ibmvfc event struct |
| 2907 | * | 3052 | * |
| @@ -2921,6 +3066,8 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt) | |||
| 2921 | tgt->new_scsi_id = rsp->scsi_id; | 3066 | tgt->new_scsi_id = rsp->scsi_id; |
| 2922 | if (rsp->scsi_id != tgt->scsi_id) | 3067 | if (rsp->scsi_id != tgt->scsi_id) |
| 2923 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); | 3068 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); |
| 3069 | else | ||
| 3070 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_adisc); | ||
| 2924 | break; | 3071 | break; |
| 2925 | case IBMVFC_MAD_DRIVER_FAILED: | 3072 | case IBMVFC_MAD_DRIVER_FAILED: |
| 2926 | break; | 3073 | break; |
| @@ -3336,6 +3483,7 @@ static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt) | |||
| 3336 | tgt_dbg(tgt, "rport add succeeded\n"); | 3483 | tgt_dbg(tgt, "rport add succeeded\n"); |
| 3337 | rport->maxframe_size = tgt->service_parms.common.bb_rcv_sz & 0x0fff; | 3484 | rport->maxframe_size = tgt->service_parms.common.bb_rcv_sz & 0x0fff; |
| 3338 | rport->supported_classes = 0; | 3485 | rport->supported_classes = 0; |
| 3486 | tgt->target_id = rport->scsi_target_id; | ||
| 3339 | if (tgt->service_parms.class1_parms[0] & 0x80000000) | 3487 | if (tgt->service_parms.class1_parms[0] & 0x80000000) |
| 3340 | rport->supported_classes |= FC_COS_CLASS1; | 3488 | rport->supported_classes |= FC_COS_CLASS1; |
| 3341 | if (tgt->service_parms.class2_parms[0] & 0x80000000) | 3489 | if (tgt->service_parms.class2_parms[0] & 0x80000000) |
| @@ -3525,7 +3673,7 @@ static int ibmvfc_init_crq(struct ibmvfc_host *vhost) | |||
| 3525 | crq->msg_token = dma_map_single(dev, crq->msgs, | 3673 | crq->msg_token = dma_map_single(dev, crq->msgs, |
| 3526 | PAGE_SIZE, DMA_BIDIRECTIONAL); | 3674 | PAGE_SIZE, DMA_BIDIRECTIONAL); |
| 3527 | 3675 | ||
| 3528 | if (dma_mapping_error(crq->msg_token)) | 3676 | if (dma_mapping_error(dev, crq->msg_token)) |
| 3529 | goto map_failed; | 3677 | goto map_failed; |
| 3530 | 3678 | ||
| 3531 | retrc = rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address, | 3679 | retrc = rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address, |
| @@ -3618,7 +3766,7 @@ static int ibmvfc_alloc_mem(struct ibmvfc_host *vhost) | |||
| 3618 | async_q->size * sizeof(*async_q->msgs), | 3766 | async_q->size * sizeof(*async_q->msgs), |
| 3619 | DMA_BIDIRECTIONAL); | 3767 | DMA_BIDIRECTIONAL); |
| 3620 | 3768 | ||
| 3621 | if (dma_mapping_error(async_q->msg_token)) { | 3769 | if (dma_mapping_error(dev, async_q->msg_token)) { |
| 3622 | dev_err(dev, "Failed to map async queue\n"); | 3770 | dev_err(dev, "Failed to map async queue\n"); |
| 3623 | goto free_async_crq; | 3771 | goto free_async_crq; |
| 3624 | } | 3772 | } |
| @@ -3800,10 +3948,12 @@ static int ibmvfc_remove(struct vio_dev *vdev) | |||
| 3800 | 3948 | ||
| 3801 | ENTER; | 3949 | ENTER; |
| 3802 | ibmvfc_remove_trace_file(&vhost->host->shost_dev.kobj, &ibmvfc_trace_attr); | 3950 | ibmvfc_remove_trace_file(&vhost->host->shost_dev.kobj, &ibmvfc_trace_attr); |
| 3951 | ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); | ||
| 3952 | ibmvfc_wait_while_resetting(vhost); | ||
| 3953 | ibmvfc_release_crq_queue(vhost); | ||
| 3803 | kthread_stop(vhost->work_thread); | 3954 | kthread_stop(vhost->work_thread); |
| 3804 | fc_remove_host(vhost->host); | 3955 | fc_remove_host(vhost->host); |
| 3805 | scsi_remove_host(vhost->host); | 3956 | scsi_remove_host(vhost->host); |
| 3806 | ibmvfc_release_crq_queue(vhost); | ||
| 3807 | 3957 | ||
| 3808 | spin_lock_irqsave(vhost->host->host_lock, flags); | 3958 | spin_lock_irqsave(vhost->host->host_lock, flags); |
| 3809 | ibmvfc_purge_requests(vhost, DID_ERROR); | 3959 | ibmvfc_purge_requests(vhost, DID_ERROR); |
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index 057f3c01ed61..4bf6e374f076 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h | |||
| @@ -29,8 +29,8 @@ | |||
| 29 | #include "viosrp.h" | 29 | #include "viosrp.h" |
| 30 | 30 | ||
| 31 | #define IBMVFC_NAME "ibmvfc" | 31 | #define IBMVFC_NAME "ibmvfc" |
| 32 | #define IBMVFC_DRIVER_VERSION "1.0.0" | 32 | #define IBMVFC_DRIVER_VERSION "1.0.1" |
| 33 | #define IBMVFC_DRIVER_DATE "(July 1, 2008)" | 33 | #define IBMVFC_DRIVER_DATE "(July 11, 2008)" |
| 34 | 34 | ||
| 35 | #define IBMVFC_DEFAULT_TIMEOUT 15 | 35 | #define IBMVFC_DEFAULT_TIMEOUT 15 |
| 36 | #define IBMVFC_INIT_TIMEOUT 30 | 36 | #define IBMVFC_INIT_TIMEOUT 30 |
| @@ -119,6 +119,7 @@ enum ibmvfc_mad_types { | |||
| 119 | IBMVFC_PROCESS_LOGIN = 0x0008, | 119 | IBMVFC_PROCESS_LOGIN = 0x0008, |
| 120 | IBMVFC_QUERY_TARGET = 0x0010, | 120 | IBMVFC_QUERY_TARGET = 0x0010, |
| 121 | IBMVFC_IMPLICIT_LOGOUT = 0x0040, | 121 | IBMVFC_IMPLICIT_LOGOUT = 0x0040, |
| 122 | IBMVFC_PASSTHRU = 0x0200, | ||
| 122 | IBMVFC_TMF_MAD = 0x0100, | 123 | IBMVFC_TMF_MAD = 0x0100, |
| 123 | }; | 124 | }; |
| 124 | 125 | ||
| @@ -439,6 +440,37 @@ struct ibmvfc_cmd { | |||
| 439 | struct ibmvfc_fcp_rsp rsp; | 440 | struct ibmvfc_fcp_rsp rsp; |
| 440 | }__attribute__((packed, aligned (8))); | 441 | }__attribute__((packed, aligned (8))); |
| 441 | 442 | ||
| 443 | struct ibmvfc_passthru_fc_iu { | ||
| 444 | u32 payload[7]; | ||
| 445 | #define IBMVFC_ADISC 0x52000000 | ||
| 446 | u32 response[7]; | ||
| 447 | }; | ||
| 448 | |||
| 449 | struct ibmvfc_passthru_iu { | ||
| 450 | u64 task_tag; | ||
| 451 | u32 cmd_len; | ||
| 452 | u32 rsp_len; | ||
| 453 | u16 status; | ||
| 454 | u16 error; | ||
| 455 | u32 flags; | ||
| 456 | #define IBMVFC_FC_ELS 0x01 | ||
| 457 | u32 cancel_key; | ||
| 458 | u32 reserved; | ||
| 459 | struct srp_direct_buf cmd; | ||
| 460 | struct srp_direct_buf rsp; | ||
| 461 | u64 correlation; | ||
| 462 | u64 scsi_id; | ||
| 463 | u64 tag; | ||
| 464 | u64 reserved2[2]; | ||
| 465 | }__attribute__((packed, aligned (8))); | ||
| 466 | |||
| 467 | struct ibmvfc_passthru_mad { | ||
| 468 | struct ibmvfc_mad_common common; | ||
| 469 | struct srp_direct_buf cmd_ioba; | ||
| 470 | struct ibmvfc_passthru_iu iu; | ||
| 471 | struct ibmvfc_passthru_fc_iu fc_iu; | ||
| 472 | }__attribute__((packed, aligned (8))); | ||
| 473 | |||
| 442 | struct ibmvfc_trace_start_entry { | 474 | struct ibmvfc_trace_start_entry { |
| 443 | u32 xfer_len; | 475 | u32 xfer_len; |
| 444 | }__attribute__((packed)); | 476 | }__attribute__((packed)); |
| @@ -531,6 +563,7 @@ union ibmvfc_iu { | |||
| 531 | struct ibmvfc_implicit_logout implicit_logout; | 563 | struct ibmvfc_implicit_logout implicit_logout; |
| 532 | struct ibmvfc_tmf tmf; | 564 | struct ibmvfc_tmf tmf; |
| 533 | struct ibmvfc_cmd cmd; | 565 | struct ibmvfc_cmd cmd; |
| 566 | struct ibmvfc_passthru_mad passthru; | ||
| 534 | }__attribute__((packed, aligned (8))); | 567 | }__attribute__((packed, aligned (8))); |
| 535 | 568 | ||
| 536 | enum ibmvfc_target_action { | 569 | enum ibmvfc_target_action { |
| @@ -656,6 +689,9 @@ struct ibmvfc_host { | |||
| 656 | #define tgt_dbg(t, fmt, ...) \ | 689 | #define tgt_dbg(t, fmt, ...) \ |
| 657 | DBG_CMD(dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__)) | 690 | DBG_CMD(dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__)) |
| 658 | 691 | ||
| 692 | #define tgt_info(t, fmt, ...) \ | ||
| 693 | dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__) | ||
| 694 | |||
| 659 | #define tgt_err(t, fmt, ...) \ | 695 | #define tgt_err(t, fmt, ...) \ |
| 660 | dev_err((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__) | 696 | dev_err((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__) |
| 661 | 697 | ||
| @@ -668,8 +704,8 @@ struct ibmvfc_host { | |||
| 668 | dev_err((vhost)->dev, ##__VA_ARGS__); \ | 704 | dev_err((vhost)->dev, ##__VA_ARGS__); \ |
| 669 | } while (0) | 705 | } while (0) |
| 670 | 706 | ||
| 671 | #define ENTER DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Entering %s\n", __FUNCTION__)) | 707 | #define ENTER DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Entering %s\n", __func__)) |
| 672 | #define LEAVE DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Leaving %s\n", __FUNCTION__)) | 708 | #define LEAVE DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Leaving %s\n", __func__)) |
| 673 | 709 | ||
| 674 | #ifdef CONFIG_SCSI_IBMVFC_TRACE | 710 | #ifdef CONFIG_SCSI_IBMVFC_TRACE |
| 675 | #define ibmvfc_create_trace_file(kobj, attr) sysfs_create_bin_file(kobj, attr) | 711 | #define ibmvfc_create_trace_file(kobj, attr) sysfs_create_bin_file(kobj, attr) |
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 20000ec79b04..6b24b9cdb04c 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c | |||
| @@ -859,7 +859,7 @@ static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata) | |||
| 859 | sizeof(hostdata->madapter_info), | 859 | sizeof(hostdata->madapter_info), |
| 860 | DMA_BIDIRECTIONAL); | 860 | DMA_BIDIRECTIONAL); |
| 861 | 861 | ||
| 862 | if (dma_mapping_error(req->buffer)) { | 862 | if (dma_mapping_error(hostdata->dev, req->buffer)) { |
| 863 | if (!firmware_has_feature(FW_FEATURE_CMO)) | 863 | if (!firmware_has_feature(FW_FEATURE_CMO)) |
| 864 | dev_err(hostdata->dev, | 864 | dev_err(hostdata->dev, |
| 865 | "Unable to map request_buffer for " | 865 | "Unable to map request_buffer for " |
| @@ -1407,7 +1407,7 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata, | |||
| 1407 | length, | 1407 | length, |
| 1408 | DMA_BIDIRECTIONAL); | 1408 | DMA_BIDIRECTIONAL); |
| 1409 | 1409 | ||
| 1410 | if (dma_mapping_error(host_config->buffer)) { | 1410 | if (dma_mapping_error(hostdata->dev, host_config->buffer)) { |
| 1411 | if (!firmware_has_feature(FW_FEATURE_CMO)) | 1411 | if (!firmware_has_feature(FW_FEATURE_CMO)) |
| 1412 | dev_err(hostdata->dev, | 1412 | dev_err(hostdata->dev, |
| 1413 | "dma_mapping error getting host config\n"); | 1413 | "dma_mapping error getting host config\n"); |
diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c index 3b9514c8f1f1..2a5b29d12172 100644 --- a/drivers/scsi/ibmvscsi/ibmvstgt.c +++ b/drivers/scsi/ibmvscsi/ibmvstgt.c | |||
| @@ -55,7 +55,7 @@ | |||
| 55 | /* tmp - will replace with SCSI logging stuff */ | 55 | /* tmp - will replace with SCSI logging stuff */ |
| 56 | #define eprintk(fmt, args...) \ | 56 | #define eprintk(fmt, args...) \ |
| 57 | do { \ | 57 | do { \ |
| 58 | printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args); \ | 58 | printk("%s(%d) " fmt, __func__, __LINE__, ##args); \ |
| 59 | } while (0) | 59 | } while (0) |
| 60 | /* #define dprintk eprintk */ | 60 | /* #define dprintk eprintk */ |
| 61 | #define dprintk(fmt, args...) | 61 | #define dprintk(fmt, args...) |
| @@ -564,7 +564,7 @@ static int crq_queue_create(struct crq_queue *queue, struct srp_target *target) | |||
| 564 | queue->size * sizeof(*queue->msgs), | 564 | queue->size * sizeof(*queue->msgs), |
| 565 | DMA_BIDIRECTIONAL); | 565 | DMA_BIDIRECTIONAL); |
| 566 | 566 | ||
| 567 | if (dma_mapping_error(queue->msg_token)) | 567 | if (dma_mapping_error(target->dev, queue->msg_token)) |
| 568 | goto map_failed; | 568 | goto map_failed; |
| 569 | 569 | ||
| 570 | err = h_reg_crq(vport->dma_dev->unit_address, queue->msg_token, | 570 | err = h_reg_crq(vport->dma_dev->unit_address, queue->msg_token, |
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c index 182146100dc1..462a8574dad9 100644 --- a/drivers/scsi/ibmvscsi/rpa_vscsi.c +++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c | |||
| @@ -253,7 +253,7 @@ static int rpavscsi_init_crq_queue(struct crq_queue *queue, | |||
| 253 | queue->size * sizeof(*queue->msgs), | 253 | queue->size * sizeof(*queue->msgs), |
| 254 | DMA_BIDIRECTIONAL); | 254 | DMA_BIDIRECTIONAL); |
| 255 | 255 | ||
| 256 | if (dma_mapping_error(queue->msg_token)) | 256 | if (dma_mapping_error(hostdata->dev, queue->msg_token)) |
| 257 | goto map_failed; | 257 | goto map_failed; |
| 258 | 258 | ||
| 259 | gather_partition_info(); | 259 | gather_partition_info(); |
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index f97d172844be..c2a9a13d788f 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c | |||
| @@ -163,7 +163,7 @@ static int imm_proc_info(struct Scsi_Host *host, char *buffer, char **start, | |||
| 163 | 163 | ||
| 164 | #if IMM_DEBUG > 0 | 164 | #if IMM_DEBUG > 0 |
| 165 | #define imm_fail(x,y) printk("imm: imm_fail(%i) from %s at line %d\n",\ | 165 | #define imm_fail(x,y) printk("imm: imm_fail(%i) from %s at line %d\n",\ |
| 166 | y, __FUNCTION__, __LINE__); imm_fail_func(x,y); | 166 | y, __func__, __LINE__); imm_fail_func(x,y); |
| 167 | static inline void | 167 | static inline void |
| 168 | imm_fail_func(imm_struct *dev, int error_code) | 168 | imm_fail_func(imm_struct *dev, int error_code) |
| 169 | #else | 169 | #else |
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index d93156671e93..4871dd1f2582 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h | |||
| @@ -1403,10 +1403,10 @@ struct ipr_ucode_image_header { | |||
| 1403 | } | 1403 | } |
| 1404 | 1404 | ||
| 1405 | #define ipr_trace ipr_dbg("%s: %s: Line: %d\n",\ | 1405 | #define ipr_trace ipr_dbg("%s: %s: Line: %d\n",\ |
| 1406 | __FILE__, __FUNCTION__, __LINE__) | 1406 | __FILE__, __func__, __LINE__) |
| 1407 | 1407 | ||
| 1408 | #define ENTER IPR_DBG_CMD(printk(KERN_INFO IPR_NAME": Entering %s\n", __FUNCTION__)) | 1408 | #define ENTER IPR_DBG_CMD(printk(KERN_INFO IPR_NAME": Entering %s\n", __func__)) |
| 1409 | #define LEAVE IPR_DBG_CMD(printk(KERN_INFO IPR_NAME": Leaving %s\n", __FUNCTION__)) | 1409 | #define LEAVE IPR_DBG_CMD(printk(KERN_INFO IPR_NAME": Leaving %s\n", __func__)) |
| 1410 | 1410 | ||
| 1411 | #define ipr_err_separator \ | 1411 | #define ipr_err_separator \ |
| 1412 | ipr_err("----------------------------------------------------------\n") | 1412 | ipr_err("----------------------------------------------------------\n") |
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 744f06d04a36..48ee8c7f5bdd 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c | |||
| @@ -74,7 +74,7 @@ static enum ata_completion_errors sas_to_ata_err(struct task_status_struct *ts) | |||
| 74 | case SAS_OPEN_TO: | 74 | case SAS_OPEN_TO: |
| 75 | case SAS_OPEN_REJECT: | 75 | case SAS_OPEN_REJECT: |
| 76 | SAS_DPRINTK("%s: Saw error %d. What to do?\n", | 76 | SAS_DPRINTK("%s: Saw error %d. What to do?\n", |
| 77 | __FUNCTION__, ts->stat); | 77 | __func__, ts->stat); |
| 78 | return AC_ERR_OTHER; | 78 | return AC_ERR_OTHER; |
| 79 | 79 | ||
| 80 | case SAS_ABORTED_TASK: | 80 | case SAS_ABORTED_TASK: |
| @@ -115,7 +115,7 @@ static void sas_ata_task_done(struct sas_task *task) | |||
| 115 | } else if (stat->stat != SAM_STAT_GOOD) { | 115 | } else if (stat->stat != SAM_STAT_GOOD) { |
| 116 | ac = sas_to_ata_err(stat); | 116 | ac = sas_to_ata_err(stat); |
| 117 | if (ac) { | 117 | if (ac) { |
| 118 | SAS_DPRINTK("%s: SAS error %x\n", __FUNCTION__, | 118 | SAS_DPRINTK("%s: SAS error %x\n", __func__, |
| 119 | stat->stat); | 119 | stat->stat); |
| 120 | /* We saw a SAS error. Send a vague error. */ | 120 | /* We saw a SAS error. Send a vague error. */ |
| 121 | qc->err_mask = ac; | 121 | qc->err_mask = ac; |
| @@ -244,20 +244,20 @@ static void sas_ata_phy_reset(struct ata_port *ap) | |||
| 244 | res = i->dft->lldd_I_T_nexus_reset(dev); | 244 | res = i->dft->lldd_I_T_nexus_reset(dev); |
| 245 | 245 | ||
| 246 | if (res != TMF_RESP_FUNC_COMPLETE) | 246 | if (res != TMF_RESP_FUNC_COMPLETE) |
| 247 | SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __FUNCTION__); | 247 | SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __func__); |
| 248 | 248 | ||
| 249 | switch (dev->sata_dev.command_set) { | 249 | switch (dev->sata_dev.command_set) { |
| 250 | case ATA_COMMAND_SET: | 250 | case ATA_COMMAND_SET: |
| 251 | SAS_DPRINTK("%s: Found ATA device.\n", __FUNCTION__); | 251 | SAS_DPRINTK("%s: Found ATA device.\n", __func__); |
| 252 | ap->link.device[0].class = ATA_DEV_ATA; | 252 | ap->link.device[0].class = ATA_DEV_ATA; |
| 253 | break; | 253 | break; |
| 254 | case ATAPI_COMMAND_SET: | 254 | case ATAPI_COMMAND_SET: |
| 255 | SAS_DPRINTK("%s: Found ATAPI device.\n", __FUNCTION__); | 255 | SAS_DPRINTK("%s: Found ATAPI device.\n", __func__); |
| 256 | ap->link.device[0].class = ATA_DEV_ATAPI; | 256 | ap->link.device[0].class = ATA_DEV_ATAPI; |
| 257 | break; | 257 | break; |
| 258 | default: | 258 | default: |
| 259 | SAS_DPRINTK("%s: Unknown SATA command set: %d.\n", | 259 | SAS_DPRINTK("%s: Unknown SATA command set: %d.\n", |
| 260 | __FUNCTION__, | 260 | __func__, |
| 261 | dev->sata_dev.command_set); | 261 | dev->sata_dev.command_set); |
| 262 | ap->link.device[0].class = ATA_DEV_UNKNOWN; | 262 | ap->link.device[0].class = ATA_DEV_UNKNOWN; |
| 263 | break; | 263 | break; |
| @@ -299,7 +299,7 @@ static int sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in, | |||
| 299 | { | 299 | { |
| 300 | struct domain_device *dev = ap->private_data; | 300 | struct domain_device *dev = ap->private_data; |
| 301 | 301 | ||
| 302 | SAS_DPRINTK("STUB %s\n", __FUNCTION__); | 302 | SAS_DPRINTK("STUB %s\n", __func__); |
| 303 | switch (sc_reg_in) { | 303 | switch (sc_reg_in) { |
| 304 | case SCR_STATUS: | 304 | case SCR_STATUS: |
| 305 | dev->sata_dev.sstatus = val; | 305 | dev->sata_dev.sstatus = val; |
| @@ -324,7 +324,7 @@ static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in, | |||
| 324 | { | 324 | { |
| 325 | struct domain_device *dev = ap->private_data; | 325 | struct domain_device *dev = ap->private_data; |
| 326 | 326 | ||
| 327 | SAS_DPRINTK("STUB %s\n", __FUNCTION__); | 327 | SAS_DPRINTK("STUB %s\n", __func__); |
| 328 | switch (sc_reg_in) { | 328 | switch (sc_reg_in) { |
| 329 | case SCR_STATUS: | 329 | case SCR_STATUS: |
| 330 | *val = dev->sata_dev.sstatus; | 330 | *val = dev->sata_dev.sstatus; |
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index aefd865a5788..3da02e436788 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c | |||
| @@ -121,7 +121,7 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size, | |||
| 121 | break; | 121 | break; |
| 122 | } else { | 122 | } else { |
| 123 | SAS_DPRINTK("%s: task to dev %016llx response: 0x%x " | 123 | SAS_DPRINTK("%s: task to dev %016llx response: 0x%x " |
| 124 | "status 0x%x\n", __FUNCTION__, | 124 | "status 0x%x\n", __func__, |
| 125 | SAS_ADDR(dev->sas_addr), | 125 | SAS_ADDR(dev->sas_addr), |
| 126 | task->task_status.resp, | 126 | task->task_status.resp, |
| 127 | task->task_status.stat); | 127 | task->task_status.stat); |
| @@ -1279,7 +1279,7 @@ static int sas_configure_present(struct domain_device *dev, int phy_id, | |||
| 1279 | goto out; | 1279 | goto out; |
| 1280 | } else if (res != SMP_RESP_FUNC_ACC) { | 1280 | } else if (res != SMP_RESP_FUNC_ACC) { |
| 1281 | SAS_DPRINTK("%s: dev %016llx phy 0x%x index 0x%x " | 1281 | SAS_DPRINTK("%s: dev %016llx phy 0x%x index 0x%x " |
| 1282 | "result 0x%x\n", __FUNCTION__, | 1282 | "result 0x%x\n", __func__, |
| 1283 | SAS_ADDR(dev->sas_addr), phy_id, i, res); | 1283 | SAS_ADDR(dev->sas_addr), phy_id, i, res); |
| 1284 | goto out; | 1284 | goto out; |
| 1285 | } | 1285 | } |
| @@ -1901,7 +1901,7 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
| 1901 | 1901 | ||
| 1902 | if (!rsp) { | 1902 | if (!rsp) { |
| 1903 | printk("%s: space for a smp response is missing\n", | 1903 | printk("%s: space for a smp response is missing\n", |
| 1904 | __FUNCTION__); | 1904 | __func__); |
| 1905 | return -EINVAL; | 1905 | return -EINVAL; |
| 1906 | } | 1906 | } |
| 1907 | 1907 | ||
| @@ -1914,20 +1914,20 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
| 1914 | if (type != SAS_EDGE_EXPANDER_DEVICE && | 1914 | if (type != SAS_EDGE_EXPANDER_DEVICE && |
| 1915 | type != SAS_FANOUT_EXPANDER_DEVICE) { | 1915 | type != SAS_FANOUT_EXPANDER_DEVICE) { |
| 1916 | printk("%s: can we send a smp request to a device?\n", | 1916 | printk("%s: can we send a smp request to a device?\n", |
| 1917 | __FUNCTION__); | 1917 | __func__); |
| 1918 | return -EINVAL; | 1918 | return -EINVAL; |
| 1919 | } | 1919 | } |
| 1920 | 1920 | ||
| 1921 | dev = sas_find_dev_by_rphy(rphy); | 1921 | dev = sas_find_dev_by_rphy(rphy); |
| 1922 | if (!dev) { | 1922 | if (!dev) { |
| 1923 | printk("%s: fail to find a domain_device?\n", __FUNCTION__); | 1923 | printk("%s: fail to find a domain_device?\n", __func__); |
| 1924 | return -EINVAL; | 1924 | return -EINVAL; |
| 1925 | } | 1925 | } |
| 1926 | 1926 | ||
| 1927 | /* do we need to support multiple segments? */ | 1927 | /* do we need to support multiple segments? */ |
| 1928 | if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { | 1928 | if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { |
| 1929 | printk("%s: multiple segments req %u %u, rsp %u %u\n", | 1929 | printk("%s: multiple segments req %u %u, rsp %u %u\n", |
| 1930 | __FUNCTION__, req->bio->bi_vcnt, req->data_len, | 1930 | __func__, req->bio->bi_vcnt, req->data_len, |
| 1931 | rsp->bio->bi_vcnt, rsp->data_len); | 1931 | rsp->bio->bi_vcnt, rsp->data_len); |
| 1932 | return -EINVAL; | 1932 | return -EINVAL; |
| 1933 | } | 1933 | } |
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c index 39ae68a3b0ef..139935a121b4 100644 --- a/drivers/scsi/libsas/sas_port.c +++ b/drivers/scsi/libsas/sas_port.c | |||
| @@ -50,7 +50,7 @@ static void sas_form_port(struct asd_sas_phy *phy) | |||
| 50 | sas_deform_port(phy); | 50 | sas_deform_port(phy); |
| 51 | else { | 51 | else { |
| 52 | SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n", | 52 | SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n", |
| 53 | __FUNCTION__, phy->id, phy->port->id, | 53 | __func__, phy->id, phy->port->id, |
| 54 | phy->port->num_phys); | 54 | phy->port->num_phys); |
| 55 | return; | 55 | return; |
| 56 | } | 56 | } |
| @@ -78,7 +78,7 @@ static void sas_form_port(struct asd_sas_phy *phy) | |||
| 78 | 78 | ||
| 79 | if (i >= sas_ha->num_phys) { | 79 | if (i >= sas_ha->num_phys) { |
| 80 | printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n", | 80 | printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n", |
| 81 | __FUNCTION__); | 81 | __func__); |
| 82 | spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); | 82 | spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); |
| 83 | return; | 83 | return; |
| 84 | } | 84 | } |
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 601ec5b6a7f6..a8e3ef309070 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c | |||
| @@ -343,7 +343,7 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task) | |||
| 343 | flags); | 343 | flags); |
| 344 | SAS_DPRINTK("%s: task 0x%p aborted from " | 344 | SAS_DPRINTK("%s: task 0x%p aborted from " |
| 345 | "task_queue\n", | 345 | "task_queue\n", |
| 346 | __FUNCTION__, task); | 346 | __func__, task); |
| 347 | return TASK_IS_ABORTED; | 347 | return TASK_IS_ABORTED; |
| 348 | } | 348 | } |
| 349 | } | 349 | } |
| @@ -351,13 +351,13 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task) | |||
| 351 | } | 351 | } |
| 352 | 352 | ||
| 353 | for (i = 0; i < 5; i++) { | 353 | for (i = 0; i < 5; i++) { |
| 354 | SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task); | 354 | SAS_DPRINTK("%s: aborting task 0x%p\n", __func__, task); |
| 355 | res = si->dft->lldd_abort_task(task); | 355 | res = si->dft->lldd_abort_task(task); |
| 356 | 356 | ||
| 357 | spin_lock_irqsave(&task->task_state_lock, flags); | 357 | spin_lock_irqsave(&task->task_state_lock, flags); |
| 358 | if (task->task_state_flags & SAS_TASK_STATE_DONE) { | 358 | if (task->task_state_flags & SAS_TASK_STATE_DONE) { |
| 359 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 359 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
| 360 | SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__, | 360 | SAS_DPRINTK("%s: task 0x%p is done\n", __func__, |
| 361 | task); | 361 | task); |
| 362 | return TASK_IS_DONE; | 362 | return TASK_IS_DONE; |
| 363 | } | 363 | } |
| @@ -365,24 +365,24 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task) | |||
| 365 | 365 | ||
| 366 | if (res == TMF_RESP_FUNC_COMPLETE) { | 366 | if (res == TMF_RESP_FUNC_COMPLETE) { |
| 367 | SAS_DPRINTK("%s: task 0x%p is aborted\n", | 367 | SAS_DPRINTK("%s: task 0x%p is aborted\n", |
| 368 | __FUNCTION__, task); | 368 | __func__, task); |
| 369 | return TASK_IS_ABORTED; | 369 | return TASK_IS_ABORTED; |
| 370 | } else if (si->dft->lldd_query_task) { | 370 | } else if (si->dft->lldd_query_task) { |
| 371 | SAS_DPRINTK("%s: querying task 0x%p\n", | 371 | SAS_DPRINTK("%s: querying task 0x%p\n", |
| 372 | __FUNCTION__, task); | 372 | __func__, task); |
| 373 | res = si->dft->lldd_query_task(task); | 373 | res = si->dft->lldd_query_task(task); |
| 374 | switch (res) { | 374 | switch (res) { |
| 375 | case TMF_RESP_FUNC_SUCC: | 375 | case TMF_RESP_FUNC_SUCC: |
| 376 | SAS_DPRINTK("%s: task 0x%p at LU\n", | 376 | SAS_DPRINTK("%s: task 0x%p at LU\n", |
| 377 | __FUNCTION__, task); | 377 | __func__, task); |
| 378 | return TASK_IS_AT_LU; | 378 | return TASK_IS_AT_LU; |
| 379 | case TMF_RESP_FUNC_COMPLETE: | 379 | case TMF_RESP_FUNC_COMPLETE: |
| 380 | SAS_DPRINTK("%s: task 0x%p not at LU\n", | 380 | SAS_DPRINTK("%s: task 0x%p not at LU\n", |
| 381 | __FUNCTION__, task); | 381 | __func__, task); |
| 382 | return TASK_IS_NOT_AT_LU; | 382 | return TASK_IS_NOT_AT_LU; |
| 383 | case TMF_RESP_FUNC_FAILED: | 383 | case TMF_RESP_FUNC_FAILED: |
| 384 | SAS_DPRINTK("%s: task 0x%p failed to abort\n", | 384 | SAS_DPRINTK("%s: task 0x%p failed to abort\n", |
| 385 | __FUNCTION__, task); | 385 | __func__, task); |
| 386 | return TASK_ABORT_FAILED; | 386 | return TASK_ABORT_FAILED; |
| 387 | } | 387 | } |
| 388 | 388 | ||
| @@ -545,7 +545,7 @@ Again: | |||
| 545 | 545 | ||
| 546 | if (need_reset) { | 546 | if (need_reset) { |
| 547 | SAS_DPRINTK("%s: task 0x%p requests reset\n", | 547 | SAS_DPRINTK("%s: task 0x%p requests reset\n", |
| 548 | __FUNCTION__, task); | 548 | __func__, task); |
| 549 | goto reset; | 549 | goto reset; |
| 550 | } | 550 | } |
| 551 | 551 | ||
| @@ -556,13 +556,13 @@ Again: | |||
| 556 | 556 | ||
| 557 | switch (res) { | 557 | switch (res) { |
| 558 | case TASK_IS_DONE: | 558 | case TASK_IS_DONE: |
| 559 | SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__, | 559 | SAS_DPRINTK("%s: task 0x%p is done\n", __func__, |
| 560 | task); | 560 | task); |
| 561 | sas_eh_finish_cmd(cmd); | 561 | sas_eh_finish_cmd(cmd); |
| 562 | continue; | 562 | continue; |
| 563 | case TASK_IS_ABORTED: | 563 | case TASK_IS_ABORTED: |
| 564 | SAS_DPRINTK("%s: task 0x%p is aborted\n", | 564 | SAS_DPRINTK("%s: task 0x%p is aborted\n", |
| 565 | __FUNCTION__, task); | 565 | __func__, task); |
| 566 | sas_eh_finish_cmd(cmd); | 566 | sas_eh_finish_cmd(cmd); |
| 567 | continue; | 567 | continue; |
| 568 | case TASK_IS_AT_LU: | 568 | case TASK_IS_AT_LU: |
| @@ -633,7 +633,7 @@ Again: | |||
| 633 | } | 633 | } |
| 634 | return list_empty(work_q); | 634 | return list_empty(work_q); |
| 635 | clear_q: | 635 | clear_q: |
| 636 | SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__); | 636 | SAS_DPRINTK("--- Exit %s -- clear_q\n", __func__); |
| 637 | list_for_each_entry_safe(cmd, n, work_q, eh_entry) | 637 | list_for_each_entry_safe(cmd, n, work_q, eh_entry) |
| 638 | sas_eh_finish_cmd(cmd); | 638 | sas_eh_finish_cmd(cmd); |
| 639 | 639 | ||
| @@ -650,7 +650,7 @@ void sas_scsi_recover_host(struct Scsi_Host *shost) | |||
| 650 | list_splice_init(&shost->eh_cmd_q, &eh_work_q); | 650 | list_splice_init(&shost->eh_cmd_q, &eh_work_q); |
| 651 | spin_unlock_irqrestore(shost->host_lock, flags); | 651 | spin_unlock_irqrestore(shost->host_lock, flags); |
| 652 | 652 | ||
| 653 | SAS_DPRINTK("Enter %s\n", __FUNCTION__); | 653 | SAS_DPRINTK("Enter %s\n", __func__); |
| 654 | /* | 654 | /* |
| 655 | * Deal with commands that still have SAS tasks (i.e. they didn't | 655 | * Deal with commands that still have SAS tasks (i.e. they didn't |
| 656 | * complete via the normal sas_task completion mechanism) | 656 | * complete via the normal sas_task completion mechanism) |
| @@ -669,7 +669,7 @@ void sas_scsi_recover_host(struct Scsi_Host *shost) | |||
| 669 | 669 | ||
| 670 | out: | 670 | out: |
| 671 | scsi_eh_flush_done_q(&ha->eh_done_q); | 671 | scsi_eh_flush_done_q(&ha->eh_done_q); |
| 672 | SAS_DPRINTK("--- Exit %s\n", __FUNCTION__); | 672 | SAS_DPRINTK("--- Exit %s\n", __func__); |
| 673 | return; | 673 | return; |
| 674 | } | 674 | } |
| 675 | 675 | ||
| @@ -990,7 +990,7 @@ int __sas_task_abort(struct sas_task *task) | |||
| 990 | if (task->task_state_flags & SAS_TASK_STATE_ABORTED || | 990 | if (task->task_state_flags & SAS_TASK_STATE_ABORTED || |
| 991 | task->task_state_flags & SAS_TASK_STATE_DONE) { | 991 | task->task_state_flags & SAS_TASK_STATE_DONE) { |
| 992 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 992 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
| 993 | SAS_DPRINTK("%s: Task %p already finished.\n", __FUNCTION__, | 993 | SAS_DPRINTK("%s: Task %p already finished.\n", __func__, |
| 994 | task); | 994 | task); |
| 995 | return 0; | 995 | return 0; |
| 996 | } | 996 | } |
diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c index 6d6a76e65a6c..15e2d132e8b9 100644 --- a/drivers/scsi/libsrp.c +++ b/drivers/scsi/libsrp.c | |||
| @@ -39,7 +39,7 @@ enum srp_task_attributes { | |||
| 39 | /* tmp - will replace with SCSI logging stuff */ | 39 | /* tmp - will replace with SCSI logging stuff */ |
| 40 | #define eprintk(fmt, args...) \ | 40 | #define eprintk(fmt, args...) \ |
| 41 | do { \ | 41 | do { \ |
| 42 | printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args); \ | 42 | printk("%s(%d) " fmt, __func__, __LINE__, ##args); \ |
| 43 | } while (0) | 43 | } while (0) |
| 44 | /* #define dprintk eprintk */ | 44 | /* #define dprintk eprintk */ |
| 45 | #define dprintk(fmt, args...) | 45 | #define dprintk(fmt, args...) |
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 5b6e5395c8eb..d51a2a4b43eb 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
| @@ -2083,7 +2083,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
| 2083 | if (iocbq_entry == NULL) { | 2083 | if (iocbq_entry == NULL) { |
| 2084 | printk(KERN_ERR "%s: only allocated %d iocbs of " | 2084 | printk(KERN_ERR "%s: only allocated %d iocbs of " |
| 2085 | "expected %d count. Unloading driver.\n", | 2085 | "expected %d count. Unloading driver.\n", |
| 2086 | __FUNCTION__, i, LPFC_IOCB_LIST_CNT); | 2086 | __func__, i, LPFC_IOCB_LIST_CNT); |
| 2087 | error = -ENOMEM; | 2087 | error = -ENOMEM; |
| 2088 | goto out_free_iocbq; | 2088 | goto out_free_iocbq; |
| 2089 | } | 2089 | } |
| @@ -2093,7 +2093,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
| 2093 | kfree (iocbq_entry); | 2093 | kfree (iocbq_entry); |
| 2094 | printk(KERN_ERR "%s: failed to allocate IOTAG. " | 2094 | printk(KERN_ERR "%s: failed to allocate IOTAG. " |
| 2095 | "Unloading driver.\n", | 2095 | "Unloading driver.\n", |
| 2096 | __FUNCTION__); | 2096 | __func__); |
| 2097 | error = -ENOMEM; | 2097 | error = -ENOMEM; |
| 2098 | goto out_free_iocbq; | 2098 | goto out_free_iocbq; |
| 2099 | } | 2099 | } |
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index c94da4f2b8a6..1bcebbd3dfac 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c | |||
| @@ -341,7 +341,7 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) | |||
| 341 | if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) { | 341 | if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) { |
| 342 | printk(KERN_ERR "%s: Too many sg segments from " | 342 | printk(KERN_ERR "%s: Too many sg segments from " |
| 343 | "dma_map_sg. Config %d, seg_cnt %d", | 343 | "dma_map_sg. Config %d, seg_cnt %d", |
| 344 | __FUNCTION__, phba->cfg_sg_seg_cnt, | 344 | __func__, phba->cfg_sg_seg_cnt, |
| 345 | lpfc_cmd->seg_cnt); | 345 | lpfc_cmd->seg_cnt); |
| 346 | scsi_dma_unmap(scsi_cmnd); | 346 | scsi_dma_unmap(scsi_cmnd); |
| 347 | return 1; | 347 | return 1; |
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index f40aa7b905f7..50fe07646738 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
| @@ -219,7 +219,7 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd) | |||
| 219 | case CMD_IOCB_LOGENTRY_CN: | 219 | case CMD_IOCB_LOGENTRY_CN: |
| 220 | case CMD_IOCB_LOGENTRY_ASYNC_CN: | 220 | case CMD_IOCB_LOGENTRY_ASYNC_CN: |
| 221 | printk("%s - Unhandled SLI-3 Command x%x\n", | 221 | printk("%s - Unhandled SLI-3 Command x%x\n", |
| 222 | __FUNCTION__, iocb_cmnd); | 222 | __func__, iocb_cmnd); |
| 223 | type = LPFC_UNKNOWN_IOCB; | 223 | type = LPFC_UNKNOWN_IOCB; |
| 224 | break; | 224 | break; |
| 225 | default: | 225 | default: |
| @@ -1715,7 +1715,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba, | |||
| 1715 | rspiocbp = __lpfc_sli_get_iocbq(phba); | 1715 | rspiocbp = __lpfc_sli_get_iocbq(phba); |
| 1716 | if (rspiocbp == NULL) { | 1716 | if (rspiocbp == NULL) { |
| 1717 | printk(KERN_ERR "%s: out of buffers! Failing " | 1717 | printk(KERN_ERR "%s: out of buffers! Failing " |
| 1718 | "completion.\n", __FUNCTION__); | 1718 | "completion.\n", __func__); |
| 1719 | break; | 1719 | break; |
| 1720 | } | 1720 | } |
| 1721 | 1721 | ||
| @@ -3793,7 +3793,7 @@ lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, struct lpfc_vport *vport, | |||
| 3793 | break; | 3793 | break; |
| 3794 | default: | 3794 | default: |
| 3795 | printk(KERN_ERR "%s: Unknown context cmd type, value %d\n", | 3795 | printk(KERN_ERR "%s: Unknown context cmd type, value %d\n", |
| 3796 | __FUNCTION__, ctx_cmd); | 3796 | __func__, ctx_cmd); |
| 3797 | break; | 3797 | break; |
| 3798 | } | 3798 | } |
| 3799 | 3799 | ||
diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h index f62ed468ada0..5ead1283a844 100644 --- a/drivers/scsi/megaraid/mega_common.h +++ b/drivers/scsi/megaraid/mega_common.h | |||
| @@ -265,7 +265,7 @@ typedef struct { | |||
| 265 | #define ASSERT(expression) \ | 265 | #define ASSERT(expression) \ |
| 266 | if (!(expression)) { \ | 266 | if (!(expression)) { \ |
| 267 | ASSERT_ACTION("assertion failed:(%s), file: %s, line: %d:%s\n", \ | 267 | ASSERT_ACTION("assertion failed:(%s), file: %s, line: %d:%s\n", \ |
| 268 | #expression, __FILE__, __LINE__, __FUNCTION__); \ | 268 | #expression, __FILE__, __LINE__, __func__); \ |
| 269 | } | 269 | } |
| 270 | #else | 270 | #else |
| 271 | #define ASSERT(expression) | 271 | #define ASSERT(expression) |
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index 70a0f11f48b2..805bb61dde18 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c | |||
| @@ -458,7 +458,7 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 458 | 458 | ||
| 459 | if (adapter == NULL) { | 459 | if (adapter == NULL) { |
| 460 | con_log(CL_ANN, (KERN_WARNING | 460 | con_log(CL_ANN, (KERN_WARNING |
| 461 | "megaraid: out of memory, %s %d.\n", __FUNCTION__, __LINE__)); | 461 | "megaraid: out of memory, %s %d.\n", __func__, __LINE__)); |
| 462 | 462 | ||
| 463 | goto out_probe_one; | 463 | goto out_probe_one; |
| 464 | } | 464 | } |
| @@ -1002,7 +1002,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter) | |||
| 1002 | 1002 | ||
| 1003 | if (!raid_dev->una_mbox64) { | 1003 | if (!raid_dev->una_mbox64) { |
| 1004 | con_log(CL_ANN, (KERN_WARNING | 1004 | con_log(CL_ANN, (KERN_WARNING |
| 1005 | "megaraid: out of memory, %s %d\n", __FUNCTION__, | 1005 | "megaraid: out of memory, %s %d\n", __func__, |
| 1006 | __LINE__)); | 1006 | __LINE__)); |
| 1007 | return -1; | 1007 | return -1; |
| 1008 | } | 1008 | } |
| @@ -1030,7 +1030,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter) | |||
| 1030 | if (!adapter->ibuf) { | 1030 | if (!adapter->ibuf) { |
| 1031 | 1031 | ||
| 1032 | con_log(CL_ANN, (KERN_WARNING | 1032 | con_log(CL_ANN, (KERN_WARNING |
| 1033 | "megaraid: out of memory, %s %d\n", __FUNCTION__, | 1033 | "megaraid: out of memory, %s %d\n", __func__, |
| 1034 | __LINE__)); | 1034 | __LINE__)); |
| 1035 | 1035 | ||
| 1036 | goto out_free_common_mbox; | 1036 | goto out_free_common_mbox; |
| @@ -1052,7 +1052,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter) | |||
| 1052 | 1052 | ||
| 1053 | if (adapter->kscb_list == NULL) { | 1053 | if (adapter->kscb_list == NULL) { |
| 1054 | con_log(CL_ANN, (KERN_WARNING | 1054 | con_log(CL_ANN, (KERN_WARNING |
| 1055 | "megaraid: out of memory, %s %d\n", __FUNCTION__, | 1055 | "megaraid: out of memory, %s %d\n", __func__, |
| 1056 | __LINE__)); | 1056 | __LINE__)); |
| 1057 | goto out_free_ibuf; | 1057 | goto out_free_ibuf; |
| 1058 | } | 1058 | } |
| @@ -1060,7 +1060,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter) | |||
| 1060 | // memory allocation for our command packets | 1060 | // memory allocation for our command packets |
| 1061 | if (megaraid_mbox_setup_dma_pools(adapter) != 0) { | 1061 | if (megaraid_mbox_setup_dma_pools(adapter) != 0) { |
| 1062 | con_log(CL_ANN, (KERN_WARNING | 1062 | con_log(CL_ANN, (KERN_WARNING |
| 1063 | "megaraid: out of memory, %s %d\n", __FUNCTION__, | 1063 | "megaraid: out of memory, %s %d\n", __func__, |
| 1064 | __LINE__)); | 1064 | __LINE__)); |
| 1065 | goto out_free_scb_list; | 1065 | goto out_free_scb_list; |
| 1066 | } | 1066 | } |
| @@ -2981,7 +2981,7 @@ megaraid_mbox_product_info(adapter_t *adapter) | |||
| 2981 | 2981 | ||
| 2982 | if (pinfo == NULL) { | 2982 | if (pinfo == NULL) { |
| 2983 | con_log(CL_ANN, (KERN_WARNING | 2983 | con_log(CL_ANN, (KERN_WARNING |
| 2984 | "megaraid: out of memory, %s %d\n", __FUNCTION__, | 2984 | "megaraid: out of memory, %s %d\n", __func__, |
| 2985 | __LINE__)); | 2985 | __LINE__)); |
| 2986 | 2986 | ||
| 2987 | return -1; | 2987 | return -1; |
| @@ -3508,7 +3508,7 @@ megaraid_cmm_register(adapter_t *adapter) | |||
| 3508 | 3508 | ||
| 3509 | if (adapter->uscb_list == NULL) { | 3509 | if (adapter->uscb_list == NULL) { |
| 3510 | con_log(CL_ANN, (KERN_WARNING | 3510 | con_log(CL_ANN, (KERN_WARNING |
| 3511 | "megaraid: out of memory, %s %d\n", __FUNCTION__, | 3511 | "megaraid: out of memory, %s %d\n", __func__, |
| 3512 | __LINE__)); | 3512 | __LINE__)); |
| 3513 | return -1; | 3513 | return -1; |
| 3514 | } | 3514 | } |
| @@ -3879,7 +3879,7 @@ megaraid_sysfs_alloc_resources(adapter_t *adapter) | |||
| 3879 | !raid_dev->sysfs_buffer) { | 3879 | !raid_dev->sysfs_buffer) { |
| 3880 | 3880 | ||
| 3881 | con_log(CL_ANN, (KERN_WARNING | 3881 | con_log(CL_ANN, (KERN_WARNING |
| 3882 | "megaraid: out of memory, %s %d\n", __FUNCTION__, | 3882 | "megaraid: out of memory, %s %d\n", __func__, |
| 3883 | __LINE__)); | 3883 | __LINE__)); |
| 3884 | 3884 | ||
| 3885 | rval = -ENOMEM; | 3885 | rval = -ENOMEM; |
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c index ac3b280c2a72..f680561d2c6f 100644 --- a/drivers/scsi/megaraid/megaraid_mm.c +++ b/drivers/scsi/megaraid/megaraid_mm.c | |||
| @@ -929,7 +929,7 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp) | |||
| 929 | !adapter->pthru_dma_pool) { | 929 | !adapter->pthru_dma_pool) { |
| 930 | 930 | ||
| 931 | con_log(CL_ANN, (KERN_WARNING | 931 | con_log(CL_ANN, (KERN_WARNING |
| 932 | "megaraid cmm: out of memory, %s %d\n", __FUNCTION__, | 932 | "megaraid cmm: out of memory, %s %d\n", __func__, |
| 933 | __LINE__)); | 933 | __LINE__)); |
| 934 | 934 | ||
| 935 | rval = (-ENOMEM); | 935 | rval = (-ENOMEM); |
| @@ -957,7 +957,7 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp) | |||
| 957 | 957 | ||
| 958 | con_log(CL_ANN, (KERN_WARNING | 958 | con_log(CL_ANN, (KERN_WARNING |
| 959 | "megaraid cmm: out of memory, %s %d\n", | 959 | "megaraid cmm: out of memory, %s %d\n", |
| 960 | __FUNCTION__, __LINE__)); | 960 | __func__, __LINE__)); |
| 961 | 961 | ||
| 962 | rval = (-ENOMEM); | 962 | rval = (-ENOMEM); |
| 963 | 963 | ||
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index 7fed35372150..edf9fdb3cb3c 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c | |||
| @@ -299,9 +299,9 @@ static struct scsi_host_template nsp32_template = { | |||
| 299 | #else | 299 | #else |
| 300 | # define NSP32_DEBUG_MASK 0xffffff | 300 | # define NSP32_DEBUG_MASK 0xffffff |
| 301 | # define nsp32_msg(type, args...) \ | 301 | # define nsp32_msg(type, args...) \ |
| 302 | nsp32_message (__FUNCTION__, __LINE__, (type), args) | 302 | nsp32_message (__func__, __LINE__, (type), args) |
| 303 | # define nsp32_dbg(mask, args...) \ | 303 | # define nsp32_dbg(mask, args...) \ |
| 304 | nsp32_dmessage(__FUNCTION__, __LINE__, (mask), args) | 304 | nsp32_dmessage(__func__, __LINE__, (mask), args) |
| 305 | #endif | 305 | #endif |
| 306 | 306 | ||
| 307 | #define NSP32_DEBUG_QUEUECOMMAND BIT(0) | 307 | #define NSP32_DEBUG_QUEUECOMMAND BIT(0) |
diff --git a/drivers/scsi/nsp32_debug.c b/drivers/scsi/nsp32_debug.c index ef3c59cbcff6..2fb3fb58858d 100644 --- a/drivers/scsi/nsp32_debug.c +++ b/drivers/scsi/nsp32_debug.c | |||
| @@ -88,7 +88,7 @@ static void print_commandk (unsigned char *command) | |||
| 88 | int i,s; | 88 | int i,s; |
| 89 | // printk(KERN_DEBUG); | 89 | // printk(KERN_DEBUG); |
| 90 | print_opcodek(command[0]); | 90 | print_opcodek(command[0]); |
| 91 | /*printk(KERN_DEBUG "%s ", __FUNCTION__);*/ | 91 | /*printk(KERN_DEBUG "%s ", __func__);*/ |
| 92 | if ((command[0] >> 5) == 6 || | 92 | if ((command[0] >> 5) == 6 || |
| 93 | (command[0] >> 5) == 7 ) { | 93 | (command[0] >> 5) == 7 ) { |
| 94 | s = 12; /* vender specific */ | 94 | s = 12; /* vender specific */ |
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 5082ca3c6876..a221b6ef9fa9 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c | |||
| @@ -107,9 +107,9 @@ static nsp_hw_data nsp_data_base; /* attach <-> detect glue */ | |||
| 107 | #else | 107 | #else |
| 108 | # define NSP_DEBUG_MASK 0xffffff | 108 | # define NSP_DEBUG_MASK 0xffffff |
| 109 | # define nsp_msg(type, args...) \ | 109 | # define nsp_msg(type, args...) \ |
| 110 | nsp_cs_message (__FUNCTION__, __LINE__, (type), args) | 110 | nsp_cs_message (__func__, __LINE__, (type), args) |
| 111 | # define nsp_dbg(mask, args...) \ | 111 | # define nsp_dbg(mask, args...) \ |
| 112 | nsp_cs_dmessage(__FUNCTION__, __LINE__, (mask), args) | 112 | nsp_cs_dmessage(__func__, __LINE__, (mask), args) |
| 113 | #endif | 113 | #endif |
| 114 | 114 | ||
| 115 | #define NSP_DEBUG_QUEUECOMMAND BIT(0) | 115 | #define NSP_DEBUG_QUEUECOMMAND BIT(0) |
diff --git a/drivers/scsi/pcmcia/nsp_debug.c b/drivers/scsi/pcmcia/nsp_debug.c index 2f75fe6e35a7..3c6ef64fcbff 100644 --- a/drivers/scsi/pcmcia/nsp_debug.c +++ b/drivers/scsi/pcmcia/nsp_debug.c | |||
| @@ -90,7 +90,7 @@ static void print_commandk (unsigned char *command) | |||
| 90 | int i, s; | 90 | int i, s; |
| 91 | printk(KERN_DEBUG); | 91 | printk(KERN_DEBUG); |
| 92 | print_opcodek(command[0]); | 92 | print_opcodek(command[0]); |
| 93 | /*printk(KERN_DEBUG "%s ", __FUNCTION__);*/ | 93 | /*printk(KERN_DEBUG "%s ", __func__);*/ |
| 94 | if ((command[0] >> 5) == 6 || | 94 | if ((command[0] >> 5) == 6 || |
| 95 | (command[0] >> 5) == 7 ) { | 95 | (command[0] >> 5) == 7 ) { |
| 96 | s = 12; /* vender specific */ | 96 | s = 12; /* vender specific */ |
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index f655ae320b48..8aa0bd987e29 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c | |||
| @@ -171,7 +171,7 @@ static int device_check(ppa_struct *dev); | |||
| 171 | 171 | ||
| 172 | #if PPA_DEBUG > 0 | 172 | #if PPA_DEBUG > 0 |
| 173 | #define ppa_fail(x,y) printk("ppa: ppa_fail(%i) from %s at line %d\n",\ | 173 | #define ppa_fail(x,y) printk("ppa: ppa_fail(%i) from %s at line %d\n",\ |
| 174 | y, __FUNCTION__, __LINE__); ppa_fail_func(x,y); | 174 | y, __func__, __LINE__); ppa_fail_func(x,y); |
| 175 | static inline void ppa_fail_func(ppa_struct *dev, int error_code) | 175 | static inline void ppa_fail_func(ppa_struct *dev, int error_code) |
| 176 | #else | 176 | #else |
| 177 | static inline void ppa_fail(ppa_struct *dev, int error_code) | 177 | static inline void ppa_fail(ppa_struct *dev, int error_code) |
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 3754ab87f89a..37f9ba0cd798 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c | |||
| @@ -1695,7 +1695,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha) | |||
| 1695 | risc_code_size = *ql1280_board_tbl[ha->devnum].fwlen; | 1695 | risc_code_size = *ql1280_board_tbl[ha->devnum].fwlen; |
| 1696 | 1696 | ||
| 1697 | dprintk(1, "%s: DMA RISC code (%i) words\n", | 1697 | dprintk(1, "%s: DMA RISC code (%i) words\n", |
| 1698 | __FUNCTION__, risc_code_size); | 1698 | __func__, risc_code_size); |
| 1699 | 1699 | ||
| 1700 | num = 0; | 1700 | num = 0; |
| 1701 | while (risc_code_size > 0) { | 1701 | while (risc_code_size > 0) { |
| @@ -1721,7 +1721,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha) | |||
| 1721 | mb[7] = pci_dma_hi32(ha->request_dma) & 0xffff; | 1721 | mb[7] = pci_dma_hi32(ha->request_dma) & 0xffff; |
| 1722 | mb[6] = pci_dma_hi32(ha->request_dma) >> 16; | 1722 | mb[6] = pci_dma_hi32(ha->request_dma) >> 16; |
| 1723 | dprintk(2, "%s: op=%d 0x%p = 0x%4x,0x%4x,0x%4x,0x%4x\n", | 1723 | dprintk(2, "%s: op=%d 0x%p = 0x%4x,0x%4x,0x%4x,0x%4x\n", |
| 1724 | __FUNCTION__, mb[0], | 1724 | __func__, mb[0], |
| 1725 | (void *)(long)ha->request_dma, | 1725 | (void *)(long)ha->request_dma, |
| 1726 | mb[6], mb[7], mb[2], mb[3]); | 1726 | mb[6], mb[7], mb[2], mb[3]); |
| 1727 | err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 | | 1727 | err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 | |
| @@ -1753,10 +1753,10 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha) | |||
| 1753 | if (tbuf[i] != sp[i] && warn++ < 10) { | 1753 | if (tbuf[i] != sp[i] && warn++ < 10) { |
| 1754 | printk(KERN_ERR "%s: FW compare error @ " | 1754 | printk(KERN_ERR "%s: FW compare error @ " |
| 1755 | "byte(0x%x) loop#=%x\n", | 1755 | "byte(0x%x) loop#=%x\n", |
| 1756 | __FUNCTION__, i, num); | 1756 | __func__, i, num); |
| 1757 | printk(KERN_ERR "%s: FWbyte=%x " | 1757 | printk(KERN_ERR "%s: FWbyte=%x " |
| 1758 | "FWfromChip=%x\n", | 1758 | "FWfromChip=%x\n", |
| 1759 | __FUNCTION__, sp[i], tbuf[i]); | 1759 | __func__, sp[i], tbuf[i]); |
| 1760 | /*break; */ | 1760 | /*break; */ |
| 1761 | } | 1761 | } |
| 1762 | } | 1762 | } |
| @@ -1781,7 +1781,7 @@ qla1280_start_firmware(struct scsi_qla_host *ha) | |||
| 1781 | int err; | 1781 | int err; |
| 1782 | 1782 | ||
| 1783 | dprintk(1, "%s: Verifying checksum of loaded RISC code.\n", | 1783 | dprintk(1, "%s: Verifying checksum of loaded RISC code.\n", |
| 1784 | __FUNCTION__); | 1784 | __func__); |
| 1785 | 1785 | ||
| 1786 | /* Verify checksum of loaded RISC code. */ | 1786 | /* Verify checksum of loaded RISC code. */ |
| 1787 | mb[0] = MBC_VERIFY_CHECKSUM; | 1787 | mb[0] = MBC_VERIFY_CHECKSUM; |
| @@ -1794,7 +1794,7 @@ qla1280_start_firmware(struct scsi_qla_host *ha) | |||
| 1794 | } | 1794 | } |
| 1795 | 1795 | ||
| 1796 | /* Start firmware execution. */ | 1796 | /* Start firmware execution. */ |
| 1797 | dprintk(1, "%s: start firmware running.\n", __FUNCTION__); | 1797 | dprintk(1, "%s: start firmware running.\n", __func__); |
| 1798 | mb[0] = MBC_EXECUTE_FIRMWARE; | 1798 | mb[0] = MBC_EXECUTE_FIRMWARE; |
| 1799 | mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; | 1799 | mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; |
| 1800 | err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); | 1800 | err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); |
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 8dd88fc1244a..7a4409ab30ea 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c | |||
| @@ -20,18 +20,12 @@ qla2x00_sysfs_read_fw_dump(struct kobject *kobj, | |||
| 20 | { | 20 | { |
| 21 | struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, | 21 | struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, |
| 22 | struct device, kobj))); | 22 | struct device, kobj))); |
| 23 | char *rbuf = (char *)ha->fw_dump; | ||
| 24 | 23 | ||
| 25 | if (ha->fw_dump_reading == 0) | 24 | if (ha->fw_dump_reading == 0) |
| 26 | return 0; | 25 | return 0; |
| 27 | if (off > ha->fw_dump_len) | ||
| 28 | return 0; | ||
| 29 | if (off + count > ha->fw_dump_len) | ||
| 30 | count = ha->fw_dump_len - off; | ||
| 31 | 26 | ||
| 32 | memcpy(buf, &rbuf[off], count); | 27 | return memory_read_from_buffer(buf, count, &off, ha->fw_dump, |
| 33 | 28 | ha->fw_dump_len); | |
| 34 | return (count); | ||
| 35 | } | 29 | } |
| 36 | 30 | ||
| 37 | static ssize_t | 31 | static ssize_t |
| @@ -94,20 +88,13 @@ qla2x00_sysfs_read_nvram(struct kobject *kobj, | |||
| 94 | { | 88 | { |
| 95 | struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, | 89 | struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, |
| 96 | struct device, kobj))); | 90 | struct device, kobj))); |
| 97 | int size = ha->nvram_size; | ||
| 98 | char *nvram_cache = ha->nvram; | ||
| 99 | 91 | ||
| 100 | if (!capable(CAP_SYS_ADMIN) || off > size || count == 0) | 92 | if (!capable(CAP_SYS_ADMIN)) |
| 101 | return 0; | 93 | return 0; |
| 102 | if (off + count > size) { | ||
| 103 | size -= off; | ||
| 104 | count = size; | ||
| 105 | } | ||
| 106 | 94 | ||
| 107 | /* Read NVRAM data from cache. */ | 95 | /* Read NVRAM data from cache. */ |
| 108 | memcpy(buf, &nvram_cache[off], count); | 96 | return memory_read_from_buffer(buf, count, &off, ha->nvram, |
| 109 | 97 | ha->nvram_size); | |
| 110 | return count; | ||
| 111 | } | 98 | } |
| 112 | 99 | ||
| 113 | static ssize_t | 100 | static ssize_t |
| @@ -175,14 +162,9 @@ qla2x00_sysfs_read_optrom(struct kobject *kobj, | |||
| 175 | 162 | ||
| 176 | if (ha->optrom_state != QLA_SREADING) | 163 | if (ha->optrom_state != QLA_SREADING) |
| 177 | return 0; | 164 | return 0; |
| 178 | if (off > ha->optrom_region_size) | ||
| 179 | return 0; | ||
| 180 | if (off + count > ha->optrom_region_size) | ||
| 181 | count = ha->optrom_region_size - off; | ||
| 182 | |||
| 183 | memcpy(buf, &ha->optrom_buffer[off], count); | ||
| 184 | 165 | ||
| 185 | return count; | 166 | return memory_read_from_buffer(buf, count, &off, ha->optrom_buffer, |
| 167 | ha->optrom_region_size); | ||
| 186 | } | 168 | } |
| 187 | 169 | ||
| 188 | static ssize_t | 170 | static ssize_t |
| @@ -374,20 +356,12 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj, | |||
| 374 | { | 356 | { |
| 375 | struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, | 357 | struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, |
| 376 | struct device, kobj))); | 358 | struct device, kobj))); |
| 377 | int size = ha->vpd_size; | ||
| 378 | char *vpd_cache = ha->vpd; | ||
| 379 | 359 | ||
| 380 | if (!capable(CAP_SYS_ADMIN) || off > size || count == 0) | 360 | if (!capable(CAP_SYS_ADMIN)) |
| 381 | return 0; | 361 | return 0; |
| 382 | if (off + count > size) { | ||
| 383 | size -= off; | ||
| 384 | count = size; | ||
| 385 | } | ||
| 386 | 362 | ||
| 387 | /* Read NVRAM data from cache. */ | 363 | /* Read NVRAM data from cache. */ |
| 388 | memcpy(buf, &vpd_cache[off], count); | 364 | return memory_read_from_buffer(buf, count, &off, ha->vpd, ha->vpd_size); |
| 389 | |||
| 390 | return count; | ||
| 391 | } | 365 | } |
| 392 | 366 | ||
| 393 | static ssize_t | 367 | static ssize_t |
| @@ -557,8 +531,10 @@ qla2x00_serial_num_show(struct device *dev, struct device_attribute *attr, | |||
| 557 | scsi_qla_host_t *ha = shost_priv(class_to_shost(dev)); | 531 | scsi_qla_host_t *ha = shost_priv(class_to_shost(dev)); |
| 558 | uint32_t sn; | 532 | uint32_t sn; |
| 559 | 533 | ||
| 560 | if (IS_FWI2_CAPABLE(ha)) | 534 | if (IS_FWI2_CAPABLE(ha)) { |
| 561 | return snprintf(buf, PAGE_SIZE, "\n"); | 535 | qla2xxx_get_vpd_field(ha, "SN", buf, PAGE_SIZE); |
| 536 | return snprintf(buf, PAGE_SIZE, "%s\n", buf); | ||
| 537 | } | ||
| 562 | 538 | ||
| 563 | sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1; | 539 | sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1; |
| 564 | return snprintf(buf, PAGE_SIZE, "%c%05d\n", 'A' + sn / 100000, | 540 | return snprintf(buf, PAGE_SIZE, "%c%05d\n", 'A' + sn / 100000, |
| @@ -809,6 +785,16 @@ qla2x00_optrom_fw_version_show(struct device *dev, | |||
| 809 | ha->fw_revision[3]); | 785 | ha->fw_revision[3]); |
| 810 | } | 786 | } |
| 811 | 787 | ||
| 788 | static ssize_t | ||
| 789 | qla2x00_total_isp_aborts_show(struct device *dev, | ||
| 790 | struct device_attribute *attr, char *buf) | ||
| 791 | { | ||
| 792 | scsi_qla_host_t *ha = shost_priv(class_to_shost(dev)); | ||
| 793 | |||
| 794 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
| 795 | ha->qla_stats.total_isp_aborts); | ||
| 796 | } | ||
| 797 | |||
| 812 | static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL); | 798 | static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL); |
| 813 | static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); | 799 | static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); |
| 814 | static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL); | 800 | static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL); |
| @@ -831,6 +817,8 @@ static DEVICE_ATTR(optrom_fcode_version, S_IRUGO, | |||
| 831 | qla2x00_optrom_fcode_version_show, NULL); | 817 | qla2x00_optrom_fcode_version_show, NULL); |
| 832 | static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show, | 818 | static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show, |
| 833 | NULL); | 819 | NULL); |
| 820 | static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show, | ||
| 821 | NULL); | ||
| 834 | 822 | ||
| 835 | struct device_attribute *qla2x00_host_attrs[] = { | 823 | struct device_attribute *qla2x00_host_attrs[] = { |
| 836 | &dev_attr_driver_version, | 824 | &dev_attr_driver_version, |
| @@ -849,6 +837,7 @@ struct device_attribute *qla2x00_host_attrs[] = { | |||
| 849 | &dev_attr_optrom_efi_version, | 837 | &dev_attr_optrom_efi_version, |
| 850 | &dev_attr_optrom_fcode_version, | 838 | &dev_attr_optrom_fcode_version, |
| 851 | &dev_attr_optrom_fw_version, | 839 | &dev_attr_optrom_fw_version, |
| 840 | &dev_attr_total_isp_aborts, | ||
| 852 | NULL, | 841 | NULL, |
| 853 | }; | 842 | }; |
| 854 | 843 | ||
| @@ -972,26 +961,39 @@ qla2x00_get_starget_port_id(struct scsi_target *starget) | |||
| 972 | } | 961 | } |
| 973 | 962 | ||
| 974 | static void | 963 | static void |
| 975 | qla2x00_get_rport_loss_tmo(struct fc_rport *rport) | 964 | qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) |
| 976 | { | 965 | { |
| 977 | struct Scsi_Host *host = rport_to_shost(rport); | 966 | if (timeout) |
| 978 | scsi_qla_host_t *ha = shost_priv(host); | 967 | rport->dev_loss_tmo = timeout; |
| 979 | 968 | else | |
| 980 | rport->dev_loss_tmo = ha->port_down_retry_count + 5; | 969 | rport->dev_loss_tmo = 1; |
| 981 | } | 970 | } |
| 982 | 971 | ||
| 983 | static void | 972 | static void |
| 984 | qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) | 973 | qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport) |
| 985 | { | 974 | { |
| 986 | struct Scsi_Host *host = rport_to_shost(rport); | 975 | struct Scsi_Host *host = rport_to_shost(rport); |
| 987 | scsi_qla_host_t *ha = shost_priv(host); | 976 | fc_port_t *fcport = *(fc_port_t **)rport->dd_data; |
| 977 | |||
| 978 | qla2x00_abort_fcport_cmds(fcport); | ||
| 979 | |||
| 980 | /* | ||
| 981 | * Transport has effectively 'deleted' the rport, clear | ||
| 982 | * all local references. | ||
| 983 | */ | ||
| 984 | spin_lock_irq(host->host_lock); | ||
| 985 | fcport->rport = NULL; | ||
| 986 | *((fc_port_t **)rport->dd_data) = NULL; | ||
| 987 | spin_unlock_irq(host->host_lock); | ||
| 988 | } | ||
| 988 | 989 | ||
| 989 | if (timeout) | 990 | static void |
| 990 | ha->port_down_retry_count = timeout; | 991 | qla2x00_terminate_rport_io(struct fc_rport *rport) |
| 991 | else | 992 | { |
| 992 | ha->port_down_retry_count = 1; | 993 | fc_port_t *fcport = *(fc_port_t **)rport->dd_data; |
| 993 | 994 | ||
| 994 | rport->dev_loss_tmo = ha->port_down_retry_count + 5; | 995 | qla2x00_abort_fcport_cmds(fcport); |
| 996 | scsi_target_unblock(&rport->dev); | ||
| 995 | } | 997 | } |
| 996 | 998 | ||
| 997 | static int | 999 | static int |
| @@ -1045,6 +1047,7 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost) | |||
| 1045 | pfc_host_stat->invalid_tx_word_count = stats->inval_xmit_word_cnt; | 1047 | pfc_host_stat->invalid_tx_word_count = stats->inval_xmit_word_cnt; |
| 1046 | pfc_host_stat->invalid_crc_count = stats->inval_crc_cnt; | 1048 | pfc_host_stat->invalid_crc_count = stats->inval_crc_cnt; |
| 1047 | if (IS_FWI2_CAPABLE(ha)) { | 1049 | if (IS_FWI2_CAPABLE(ha)) { |
| 1050 | pfc_host_stat->lip_count = stats->lip_cnt; | ||
| 1048 | pfc_host_stat->tx_frames = stats->tx_frames; | 1051 | pfc_host_stat->tx_frames = stats->tx_frames; |
| 1049 | pfc_host_stat->rx_frames = stats->rx_frames; | 1052 | pfc_host_stat->rx_frames = stats->rx_frames; |
| 1050 | pfc_host_stat->dumped_frames = stats->dumped_frames; | 1053 | pfc_host_stat->dumped_frames = stats->dumped_frames; |
| @@ -1173,17 +1176,16 @@ vport_create_failed_2: | |||
| 1173 | static int | 1176 | static int |
| 1174 | qla24xx_vport_delete(struct fc_vport *fc_vport) | 1177 | qla24xx_vport_delete(struct fc_vport *fc_vport) |
| 1175 | { | 1178 | { |
| 1176 | scsi_qla_host_t *ha = shost_priv(fc_vport->shost); | ||
| 1177 | scsi_qla_host_t *vha = fc_vport->dd_data; | 1179 | scsi_qla_host_t *vha = fc_vport->dd_data; |
| 1180 | scsi_qla_host_t *pha = to_qla_parent(vha); | ||
| 1181 | |||
| 1182 | while (test_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags) || | ||
| 1183 | test_bit(FCPORT_UPDATE_NEEDED, &pha->dpc_flags)) | ||
| 1184 | msleep(1000); | ||
| 1178 | 1185 | ||
| 1179 | qla24xx_disable_vp(vha); | 1186 | qla24xx_disable_vp(vha); |
| 1180 | qla24xx_deallocate_vp_id(vha); | 1187 | qla24xx_deallocate_vp_id(vha); |
| 1181 | 1188 | ||
| 1182 | mutex_lock(&ha->vport_lock); | ||
| 1183 | ha->cur_vport_count--; | ||
| 1184 | clear_bit(vha->vp_idx, ha->vp_idx_map); | ||
| 1185 | mutex_unlock(&ha->vport_lock); | ||
| 1186 | |||
| 1187 | kfree(vha->node_name); | 1189 | kfree(vha->node_name); |
| 1188 | kfree(vha->port_name); | 1190 | kfree(vha->port_name); |
| 1189 | 1191 | ||
| @@ -1248,11 +1250,12 @@ struct fc_function_template qla2xxx_transport_functions = { | |||
| 1248 | .get_starget_port_id = qla2x00_get_starget_port_id, | 1250 | .get_starget_port_id = qla2x00_get_starget_port_id, |
| 1249 | .show_starget_port_id = 1, | 1251 | .show_starget_port_id = 1, |
| 1250 | 1252 | ||
| 1251 | .get_rport_dev_loss_tmo = qla2x00_get_rport_loss_tmo, | ||
| 1252 | .set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo, | 1253 | .set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo, |
| 1253 | .show_rport_dev_loss_tmo = 1, | 1254 | .show_rport_dev_loss_tmo = 1, |
| 1254 | 1255 | ||
| 1255 | .issue_fc_host_lip = qla2x00_issue_lip, | 1256 | .issue_fc_host_lip = qla2x00_issue_lip, |
| 1257 | .dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk, | ||
| 1258 | .terminate_rport_io = qla2x00_terminate_rport_io, | ||
| 1256 | .get_fc_host_stats = qla2x00_get_fc_host_stats, | 1259 | .get_fc_host_stats = qla2x00_get_fc_host_stats, |
| 1257 | 1260 | ||
| 1258 | .vport_create = qla24xx_vport_create, | 1261 | .vport_create = qla24xx_vport_create, |
| @@ -1291,11 +1294,12 @@ struct fc_function_template qla2xxx_transport_vport_functions = { | |||
| 1291 | .get_starget_port_id = qla2x00_get_starget_port_id, | 1294 | .get_starget_port_id = qla2x00_get_starget_port_id, |
| 1292 | .show_starget_port_id = 1, | 1295 | .show_starget_port_id = 1, |
| 1293 | 1296 | ||
| 1294 | .get_rport_dev_loss_tmo = qla2x00_get_rport_loss_tmo, | ||
| 1295 | .set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo, | 1297 | .set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo, |
| 1296 | .show_rport_dev_loss_tmo = 1, | 1298 | .show_rport_dev_loss_tmo = 1, |
| 1297 | 1299 | ||
| 1298 | .issue_fc_host_lip = qla2x00_issue_lip, | 1300 | .issue_fc_host_lip = qla2x00_issue_lip, |
| 1301 | .dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk, | ||
| 1302 | .terminate_rport_io = qla2x00_terminate_rport_io, | ||
| 1299 | .get_fc_host_stats = qla2x00_get_fc_host_stats, | 1303 | .get_fc_host_stats = qla2x00_get_fc_host_stats, |
| 1300 | }; | 1304 | }; |
| 1301 | 1305 | ||
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index cbef785765cf..510ba64bc286 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c | |||
| @@ -216,7 +216,7 @@ qla24xx_soft_reset(scsi_qla_host_t *ha) | |||
| 216 | 216 | ||
| 217 | static int | 217 | static int |
| 218 | qla2xxx_dump_ram(scsi_qla_host_t *ha, uint32_t addr, uint16_t *ram, | 218 | qla2xxx_dump_ram(scsi_qla_host_t *ha, uint32_t addr, uint16_t *ram, |
| 219 | uint16_t ram_words, void **nxt) | 219 | uint32_t ram_words, void **nxt) |
| 220 | { | 220 | { |
| 221 | int rval; | 221 | int rval; |
| 222 | uint32_t cnt, stat, timer, words, idx; | 222 | uint32_t cnt, stat, timer, words, idx; |
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 8dd600013bd1..6da31ba94404 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h | |||
| @@ -864,7 +864,8 @@ struct link_statistics { | |||
| 864 | uint32_t prim_seq_err_cnt; | 864 | uint32_t prim_seq_err_cnt; |
| 865 | uint32_t inval_xmit_word_cnt; | 865 | uint32_t inval_xmit_word_cnt; |
| 866 | uint32_t inval_crc_cnt; | 866 | uint32_t inval_crc_cnt; |
| 867 | uint32_t unused1[0x1b]; | 867 | uint32_t lip_cnt; |
| 868 | uint32_t unused1[0x1a]; | ||
| 868 | uint32_t tx_frames; | 869 | uint32_t tx_frames; |
| 869 | uint32_t rx_frames; | 870 | uint32_t rx_frames; |
| 870 | uint32_t dumped_frames; | 871 | uint32_t dumped_frames; |
| @@ -1544,7 +1545,6 @@ typedef struct fc_port { | |||
| 1544 | int login_retry; | 1545 | int login_retry; |
| 1545 | atomic_t port_down_timer; | 1546 | atomic_t port_down_timer; |
| 1546 | 1547 | ||
| 1547 | spinlock_t rport_lock; | ||
| 1548 | struct fc_rport *rport, *drport; | 1548 | struct fc_rport *rport, *drport; |
| 1549 | u32 supported_classes; | 1549 | u32 supported_classes; |
| 1550 | 1550 | ||
| @@ -2155,6 +2155,10 @@ struct qla_chip_state_84xx { | |||
| 2155 | uint32_t gold_fw_version; | 2155 | uint32_t gold_fw_version; |
| 2156 | }; | 2156 | }; |
| 2157 | 2157 | ||
| 2158 | struct qla_statistics { | ||
| 2159 | uint32_t total_isp_aborts; | ||
| 2160 | }; | ||
| 2161 | |||
| 2158 | /* | 2162 | /* |
| 2159 | * Linux Host Adapter structure | 2163 | * Linux Host Adapter structure |
| 2160 | */ | 2164 | */ |
| @@ -2166,7 +2170,6 @@ typedef struct scsi_qla_host { | |||
| 2166 | struct pci_dev *pdev; | 2170 | struct pci_dev *pdev; |
| 2167 | 2171 | ||
| 2168 | unsigned long host_no; | 2172 | unsigned long host_no; |
| 2169 | unsigned long instance; | ||
| 2170 | 2173 | ||
| 2171 | volatile struct { | 2174 | volatile struct { |
| 2172 | uint32_t init_done :1; | 2175 | uint32_t init_done :1; |
| @@ -2515,7 +2518,7 @@ typedef struct scsi_qla_host { | |||
| 2515 | 2518 | ||
| 2516 | uint8_t model_number[16+1]; | 2519 | uint8_t model_number[16+1]; |
| 2517 | #define BINZERO "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" | 2520 | #define BINZERO "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" |
| 2518 | char *model_desc; | 2521 | char model_desc[80]; |
| 2519 | uint8_t adapter_id[16+1]; | 2522 | uint8_t adapter_id[16+1]; |
| 2520 | 2523 | ||
| 2521 | uint8_t *node_name; | 2524 | uint8_t *node_name; |
| @@ -2596,6 +2599,7 @@ typedef struct scsi_qla_host { | |||
| 2596 | int cur_vport_count; | 2599 | int cur_vport_count; |
| 2597 | 2600 | ||
| 2598 | struct qla_chip_state_84xx *cs84xx; | 2601 | struct qla_chip_state_84xx *cs84xx; |
| 2602 | struct qla_statistics qla_stats; | ||
| 2599 | } scsi_qla_host_t; | 2603 | } scsi_qla_host_t; |
| 2600 | 2604 | ||
| 2601 | 2605 | ||
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 9b4bebee6879..0b156735e9a6 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h | |||
| @@ -62,7 +62,7 @@ extern int ql2xfdmienable; | |||
| 62 | extern int ql2xallocfwdump; | 62 | extern int ql2xallocfwdump; |
| 63 | extern int ql2xextended_error_logging; | 63 | extern int ql2xextended_error_logging; |
| 64 | extern int ql2xqfullrampup; | 64 | extern int ql2xqfullrampup; |
| 65 | extern int num_hosts; | 65 | extern int ql2xiidmaenable; |
| 66 | 66 | ||
| 67 | extern int qla2x00_loop_reset(scsi_qla_host_t *); | 67 | extern int qla2x00_loop_reset(scsi_qla_host_t *); |
| 68 | extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); | 68 | extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); |
| @@ -71,6 +71,8 @@ extern int qla2x00_post_aen_work(struct scsi_qla_host *, enum | |||
| 71 | extern int qla2x00_post_hwe_work(struct scsi_qla_host *, uint16_t , uint16_t, | 71 | extern int qla2x00_post_hwe_work(struct scsi_qla_host *, uint16_t , uint16_t, |
| 72 | uint16_t, uint16_t); | 72 | uint16_t, uint16_t); |
| 73 | 73 | ||
| 74 | extern void qla2x00_abort_fcport_cmds(fc_port_t *); | ||
| 75 | |||
| 74 | /* | 76 | /* |
| 75 | * Global Functions in qla_mid.c source file. | 77 | * Global Functions in qla_mid.c source file. |
| 76 | */ | 78 | */ |
| @@ -312,6 +314,7 @@ extern int qla2xxx_hw_event_log(scsi_qla_host_t *, uint16_t , uint16_t, | |||
| 312 | uint16_t, uint16_t); | 314 | uint16_t, uint16_t); |
| 313 | 315 | ||
| 314 | extern void qla2xxx_get_flash_info(scsi_qla_host_t *); | 316 | extern void qla2xxx_get_flash_info(scsi_qla_host_t *); |
| 317 | extern int qla2xxx_get_vpd_field(scsi_qla_host_t *, char *, char *, size_t); | ||
| 315 | 318 | ||
| 316 | /* | 319 | /* |
| 317 | * Global Function Prototypes in qla_dbg.c source file. | 320 | * Global Function Prototypes in qla_dbg.c source file. |
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 4cb80b476c85..c2a4bfbcb05b 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c | |||
| @@ -1661,6 +1661,12 @@ qla2x00_fdmi_register(scsi_qla_host_t *ha) | |||
| 1661 | { | 1661 | { |
| 1662 | int rval; | 1662 | int rval; |
| 1663 | 1663 | ||
| 1664 | if (IS_QLA2100(ha) || IS_QLA2200(ha)) { | ||
| 1665 | DEBUG2(printk("scsi(%ld): FDMI unsupported on " | ||
| 1666 | "ISP2100/ISP2200.\n", ha->host_no)); | ||
| 1667 | return QLA_SUCCESS; | ||
| 1668 | } | ||
| 1669 | |||
| 1664 | rval = qla2x00_mgmt_svr_login(ha); | 1670 | rval = qla2x00_mgmt_svr_login(ha); |
| 1665 | if (rval) | 1671 | if (rval) |
| 1666 | return rval; | 1672 | return rval; |
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index bbbc5a632a1d..601a6b29750c 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c | |||
| @@ -334,6 +334,8 @@ static int | |||
| 334 | qla2x00_isp_firmware(scsi_qla_host_t *ha) | 334 | qla2x00_isp_firmware(scsi_qla_host_t *ha) |
| 335 | { | 335 | { |
| 336 | int rval; | 336 | int rval; |
| 337 | uint16_t loop_id, topo, sw_cap; | ||
| 338 | uint8_t domain, area, al_pa; | ||
| 337 | 339 | ||
| 338 | /* Assume loading risc code */ | 340 | /* Assume loading risc code */ |
| 339 | rval = QLA_FUNCTION_FAILED; | 341 | rval = QLA_FUNCTION_FAILED; |
| @@ -345,6 +347,11 @@ qla2x00_isp_firmware(scsi_qla_host_t *ha) | |||
| 345 | 347 | ||
| 346 | /* Verify checksum of loaded RISC code. */ | 348 | /* Verify checksum of loaded RISC code. */ |
| 347 | rval = qla2x00_verify_checksum(ha, ha->fw_srisc_address); | 349 | rval = qla2x00_verify_checksum(ha, ha->fw_srisc_address); |
| 350 | if (rval == QLA_SUCCESS) { | ||
| 351 | /* And, verify we are not in ROM code. */ | ||
| 352 | rval = qla2x00_get_adapter_id(ha, &loop_id, &al_pa, | ||
| 353 | &area, &domain, &topo, &sw_cap); | ||
| 354 | } | ||
| 348 | } | 355 | } |
| 349 | 356 | ||
| 350 | if (rval) { | 357 | if (rval) { |
| @@ -722,7 +729,7 @@ qla24xx_chip_diag(scsi_qla_host_t *ha) | |||
| 722 | /* Perform RISC reset. */ | 729 | /* Perform RISC reset. */ |
| 723 | qla24xx_reset_risc(ha); | 730 | qla24xx_reset_risc(ha); |
| 724 | 731 | ||
| 725 | ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024; | 732 | ha->fw_transfer_size = REQUEST_ENTRY_SIZE * ha->request_q_length; |
| 726 | 733 | ||
| 727 | rval = qla2x00_mbx_reg_test(ha); | 734 | rval = qla2x00_mbx_reg_test(ha); |
| 728 | if (rval) { | 735 | if (rval) { |
| @@ -768,42 +775,16 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha) | |||
| 768 | mem_size = (ha->fw_memory_size - 0x100000 + 1) * | 775 | mem_size = (ha->fw_memory_size - 0x100000 + 1) * |
| 769 | sizeof(uint32_t); | 776 | sizeof(uint32_t); |
| 770 | 777 | ||
| 771 | /* Allocate memory for Extended Trace Buffer. */ | ||
| 772 | tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma, | ||
| 773 | GFP_KERNEL); | ||
| 774 | if (!tc) { | ||
| 775 | qla_printk(KERN_WARNING, ha, "Unable to allocate " | ||
| 776 | "(%d KB) for EFT.\n", EFT_SIZE / 1024); | ||
| 777 | goto cont_alloc; | ||
| 778 | } | ||
| 779 | |||
| 780 | memset(tc, 0, EFT_SIZE); | ||
| 781 | rval = qla2x00_enable_eft_trace(ha, tc_dma, EFT_NUM_BUFFERS); | ||
| 782 | if (rval) { | ||
| 783 | qla_printk(KERN_WARNING, ha, "Unable to initialize " | ||
| 784 | "EFT (%d).\n", rval); | ||
| 785 | dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc, | ||
| 786 | tc_dma); | ||
| 787 | goto cont_alloc; | ||
| 788 | } | ||
| 789 | |||
| 790 | qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n", | ||
| 791 | EFT_SIZE / 1024); | ||
| 792 | |||
| 793 | eft_size = EFT_SIZE; | ||
| 794 | ha->eft_dma = tc_dma; | ||
| 795 | ha->eft = tc; | ||
| 796 | |||
| 797 | /* Allocate memory for Fibre Channel Event Buffer. */ | 778 | /* Allocate memory for Fibre Channel Event Buffer. */ |
| 798 | if (!IS_QLA25XX(ha)) | 779 | if (!IS_QLA25XX(ha)) |
| 799 | goto cont_alloc; | 780 | goto try_eft; |
| 800 | 781 | ||
| 801 | tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma, | 782 | tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma, |
| 802 | GFP_KERNEL); | 783 | GFP_KERNEL); |
| 803 | if (!tc) { | 784 | if (!tc) { |
| 804 | qla_printk(KERN_WARNING, ha, "Unable to allocate " | 785 | qla_printk(KERN_WARNING, ha, "Unable to allocate " |
| 805 | "(%d KB) for FCE.\n", FCE_SIZE / 1024); | 786 | "(%d KB) for FCE.\n", FCE_SIZE / 1024); |
| 806 | goto cont_alloc; | 787 | goto try_eft; |
| 807 | } | 788 | } |
| 808 | 789 | ||
| 809 | memset(tc, 0, FCE_SIZE); | 790 | memset(tc, 0, FCE_SIZE); |
| @@ -815,7 +796,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha) | |||
| 815 | dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc, | 796 | dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc, |
| 816 | tc_dma); | 797 | tc_dma); |
| 817 | ha->flags.fce_enabled = 0; | 798 | ha->flags.fce_enabled = 0; |
| 818 | goto cont_alloc; | 799 | goto try_eft; |
| 819 | } | 800 | } |
| 820 | 801 | ||
| 821 | qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n", | 802 | qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n", |
| @@ -825,6 +806,32 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha) | |||
| 825 | ha->flags.fce_enabled = 1; | 806 | ha->flags.fce_enabled = 1; |
| 826 | ha->fce_dma = tc_dma; | 807 | ha->fce_dma = tc_dma; |
| 827 | ha->fce = tc; | 808 | ha->fce = tc; |
| 809 | try_eft: | ||
| 810 | /* Allocate memory for Extended Trace Buffer. */ | ||
| 811 | tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma, | ||
| 812 | GFP_KERNEL); | ||
| 813 | if (!tc) { | ||
| 814 | qla_printk(KERN_WARNING, ha, "Unable to allocate " | ||
| 815 | "(%d KB) for EFT.\n", EFT_SIZE / 1024); | ||
| 816 | goto cont_alloc; | ||
| 817 | } | ||
| 818 | |||
| 819 | memset(tc, 0, EFT_SIZE); | ||
| 820 | rval = qla2x00_enable_eft_trace(ha, tc_dma, EFT_NUM_BUFFERS); | ||
| 821 | if (rval) { | ||
| 822 | qla_printk(KERN_WARNING, ha, "Unable to initialize " | ||
| 823 | "EFT (%d).\n", rval); | ||
| 824 | dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc, | ||
| 825 | tc_dma); | ||
| 826 | goto cont_alloc; | ||
| 827 | } | ||
| 828 | |||
| 829 | qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n", | ||
| 830 | EFT_SIZE / 1024); | ||
| 831 | |||
| 832 | eft_size = EFT_SIZE; | ||
| 833 | ha->eft_dma = tc_dma; | ||
| 834 | ha->eft = tc; | ||
| 828 | } | 835 | } |
| 829 | cont_alloc: | 836 | cont_alloc: |
| 830 | req_q_size = ha->request_q_length * sizeof(request_t); | 837 | req_q_size = ha->request_q_length * sizeof(request_t); |
| @@ -1501,18 +1508,25 @@ qla2x00_set_model_info(scsi_qla_host_t *ha, uint8_t *model, size_t len, char *de | |||
| 1501 | index = (ha->pdev->subsystem_device & 0xff); | 1508 | index = (ha->pdev->subsystem_device & 0xff); |
| 1502 | if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && | 1509 | if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && |
| 1503 | index < QLA_MODEL_NAMES) | 1510 | index < QLA_MODEL_NAMES) |
| 1504 | ha->model_desc = qla2x00_model_name[index * 2 + 1]; | 1511 | strncpy(ha->model_desc, |
| 1512 | qla2x00_model_name[index * 2 + 1], | ||
| 1513 | sizeof(ha->model_desc) - 1); | ||
| 1505 | } else { | 1514 | } else { |
| 1506 | index = (ha->pdev->subsystem_device & 0xff); | 1515 | index = (ha->pdev->subsystem_device & 0xff); |
| 1507 | if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && | 1516 | if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && |
| 1508 | index < QLA_MODEL_NAMES) { | 1517 | index < QLA_MODEL_NAMES) { |
| 1509 | strcpy(ha->model_number, | 1518 | strcpy(ha->model_number, |
| 1510 | qla2x00_model_name[index * 2]); | 1519 | qla2x00_model_name[index * 2]); |
| 1511 | ha->model_desc = qla2x00_model_name[index * 2 + 1]; | 1520 | strncpy(ha->model_desc, |
| 1521 | qla2x00_model_name[index * 2 + 1], | ||
| 1522 | sizeof(ha->model_desc) - 1); | ||
| 1512 | } else { | 1523 | } else { |
| 1513 | strcpy(ha->model_number, def); | 1524 | strcpy(ha->model_number, def); |
| 1514 | } | 1525 | } |
| 1515 | } | 1526 | } |
| 1527 | if (IS_FWI2_CAPABLE(ha)) | ||
| 1528 | qla2xxx_get_vpd_field(ha, "\x82", ha->model_desc, | ||
| 1529 | sizeof(ha->model_desc)); | ||
| 1516 | } | 1530 | } |
| 1517 | 1531 | ||
| 1518 | /* On sparc systems, obtain port and node WWN from firmware | 1532 | /* On sparc systems, obtain port and node WWN from firmware |
| @@ -1864,12 +1878,11 @@ qla2x00_rport_del(void *data) | |||
| 1864 | { | 1878 | { |
| 1865 | fc_port_t *fcport = data; | 1879 | fc_port_t *fcport = data; |
| 1866 | struct fc_rport *rport; | 1880 | struct fc_rport *rport; |
| 1867 | unsigned long flags; | ||
| 1868 | 1881 | ||
| 1869 | spin_lock_irqsave(&fcport->rport_lock, flags); | 1882 | spin_lock_irq(fcport->ha->host->host_lock); |
| 1870 | rport = fcport->drport; | 1883 | rport = fcport->drport; |
| 1871 | fcport->drport = NULL; | 1884 | fcport->drport = NULL; |
| 1872 | spin_unlock_irqrestore(&fcport->rport_lock, flags); | 1885 | spin_unlock_irq(fcport->ha->host->host_lock); |
| 1873 | if (rport) | 1886 | if (rport) |
| 1874 | fc_remote_port_delete(rport); | 1887 | fc_remote_port_delete(rport); |
| 1875 | } | 1888 | } |
| @@ -1898,7 +1911,6 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags) | |||
| 1898 | atomic_set(&fcport->state, FCS_UNCONFIGURED); | 1911 | atomic_set(&fcport->state, FCS_UNCONFIGURED); |
| 1899 | fcport->flags = FCF_RLC_SUPPORT; | 1912 | fcport->flags = FCF_RLC_SUPPORT; |
| 1900 | fcport->supported_classes = FC_COS_UNSPECIFIED; | 1913 | fcport->supported_classes = FC_COS_UNSPECIFIED; |
| 1901 | spin_lock_init(&fcport->rport_lock); | ||
| 1902 | 1914 | ||
| 1903 | return fcport; | 1915 | return fcport; |
| 1904 | } | 1916 | } |
| @@ -2007,8 +2019,10 @@ qla2x00_configure_loop(scsi_qla_host_t *ha) | |||
| 2007 | if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) { | 2019 | if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) { |
| 2008 | if (test_bit(LOCAL_LOOP_UPDATE, &save_flags)) | 2020 | if (test_bit(LOCAL_LOOP_UPDATE, &save_flags)) |
| 2009 | set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); | 2021 | set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); |
| 2010 | if (test_bit(RSCN_UPDATE, &save_flags)) | 2022 | if (test_bit(RSCN_UPDATE, &save_flags)) { |
| 2023 | ha->flags.rscn_queue_overflow = 1; | ||
| 2011 | set_bit(RSCN_UPDATE, &ha->dpc_flags); | 2024 | set_bit(RSCN_UPDATE, &ha->dpc_flags); |
| 2025 | } | ||
| 2012 | } | 2026 | } |
| 2013 | 2027 | ||
| 2014 | return (rval); | 2028 | return (rval); |
| @@ -2243,28 +2257,24 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport) | |||
| 2243 | { | 2257 | { |
| 2244 | struct fc_rport_identifiers rport_ids; | 2258 | struct fc_rport_identifiers rport_ids; |
| 2245 | struct fc_rport *rport; | 2259 | struct fc_rport *rport; |
| 2246 | unsigned long flags; | ||
| 2247 | 2260 | ||
| 2248 | if (fcport->drport) | 2261 | if (fcport->drport) |
| 2249 | qla2x00_rport_del(fcport); | 2262 | qla2x00_rport_del(fcport); |
| 2250 | if (fcport->rport) | ||
| 2251 | return; | ||
| 2252 | 2263 | ||
| 2253 | rport_ids.node_name = wwn_to_u64(fcport->node_name); | 2264 | rport_ids.node_name = wwn_to_u64(fcport->node_name); |
| 2254 | rport_ids.port_name = wwn_to_u64(fcport->port_name); | 2265 | rport_ids.port_name = wwn_to_u64(fcport->port_name); |
| 2255 | rport_ids.port_id = fcport->d_id.b.domain << 16 | | 2266 | rport_ids.port_id = fcport->d_id.b.domain << 16 | |
| 2256 | fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa; | 2267 | fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa; |
| 2257 | rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; | 2268 | rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; |
| 2258 | rport = fc_remote_port_add(ha->host, 0, &rport_ids); | 2269 | fcport->rport = rport = fc_remote_port_add(ha->host, 0, &rport_ids); |
| 2259 | if (!rport) { | 2270 | if (!rport) { |
| 2260 | qla_printk(KERN_WARNING, ha, | 2271 | qla_printk(KERN_WARNING, ha, |
| 2261 | "Unable to allocate fc remote port!\n"); | 2272 | "Unable to allocate fc remote port!\n"); |
| 2262 | return; | 2273 | return; |
| 2263 | } | 2274 | } |
| 2264 | spin_lock_irqsave(&fcport->rport_lock, flags); | 2275 | spin_lock_irq(fcport->ha->host->host_lock); |
| 2265 | fcport->rport = rport; | ||
| 2266 | *((fc_port_t **)rport->dd_data) = fcport; | 2276 | *((fc_port_t **)rport->dd_data) = fcport; |
| 2267 | spin_unlock_irqrestore(&fcport->rport_lock, flags); | 2277 | spin_unlock_irq(fcport->ha->host->host_lock); |
| 2268 | 2278 | ||
| 2269 | rport->supported_classes = fcport->supported_classes; | 2279 | rport->supported_classes = fcport->supported_classes; |
| 2270 | 2280 | ||
| @@ -2565,7 +2575,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) | |||
| 2565 | } else if (qla2x00_gnn_id(ha, swl) != QLA_SUCCESS) { | 2575 | } else if (qla2x00_gnn_id(ha, swl) != QLA_SUCCESS) { |
| 2566 | kfree(swl); | 2576 | kfree(swl); |
| 2567 | swl = NULL; | 2577 | swl = NULL; |
| 2568 | } else if (qla2x00_gfpn_id(ha, swl) == QLA_SUCCESS) { | 2578 | } else if (ql2xiidmaenable && |
| 2579 | qla2x00_gfpn_id(ha, swl) == QLA_SUCCESS) { | ||
| 2569 | qla2x00_gpsc(ha, swl); | 2580 | qla2x00_gpsc(ha, swl); |
| 2570 | } | 2581 | } |
| 2571 | } | 2582 | } |
| @@ -3220,7 +3231,8 @@ qla2x00_update_fcports(scsi_qla_host_t *ha) | |||
| 3220 | 3231 | ||
| 3221 | /* Go with deferred removal of rport references. */ | 3232 | /* Go with deferred removal of rport references. */ |
| 3222 | list_for_each_entry(fcport, &ha->fcports, list) | 3233 | list_for_each_entry(fcport, &ha->fcports, list) |
| 3223 | if (fcport->drport) | 3234 | if (fcport->drport && |
| 3235 | atomic_read(&fcport->state) != FCS_UNCONFIGURED) | ||
| 3224 | qla2x00_rport_del(fcport); | 3236 | qla2x00_rport_del(fcport); |
| 3225 | } | 3237 | } |
| 3226 | 3238 | ||
| @@ -3243,6 +3255,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) | |||
| 3243 | if (ha->flags.online) { | 3255 | if (ha->flags.online) { |
| 3244 | ha->flags.online = 0; | 3256 | ha->flags.online = 0; |
| 3245 | clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); | 3257 | clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); |
| 3258 | ha->qla_stats.total_isp_aborts++; | ||
| 3246 | 3259 | ||
| 3247 | qla_printk(KERN_INFO, ha, | 3260 | qla_printk(KERN_INFO, ha, |
| 3248 | "Performing ISP error recovery - ha= %p.\n", ha); | 3261 | "Performing ISP error recovery - ha= %p.\n", ha); |
| @@ -3283,17 +3296,6 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) | |||
| 3283 | ha->isp_abort_cnt = 0; | 3296 | ha->isp_abort_cnt = 0; |
| 3284 | clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags); | 3297 | clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags); |
| 3285 | 3298 | ||
| 3286 | if (ha->eft) { | ||
| 3287 | memset(ha->eft, 0, EFT_SIZE); | ||
| 3288 | rval = qla2x00_enable_eft_trace(ha, | ||
| 3289 | ha->eft_dma, EFT_NUM_BUFFERS); | ||
| 3290 | if (rval) { | ||
| 3291 | qla_printk(KERN_WARNING, ha, | ||
| 3292 | "Unable to reinitialize EFT " | ||
| 3293 | "(%d).\n", rval); | ||
| 3294 | } | ||
| 3295 | } | ||
| 3296 | |||
| 3297 | if (ha->fce) { | 3299 | if (ha->fce) { |
| 3298 | ha->flags.fce_enabled = 1; | 3300 | ha->flags.fce_enabled = 1; |
| 3299 | memset(ha->fce, 0, | 3301 | memset(ha->fce, 0, |
| @@ -3308,6 +3310,17 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) | |||
| 3308 | ha->flags.fce_enabled = 0; | 3310 | ha->flags.fce_enabled = 0; |
| 3309 | } | 3311 | } |
| 3310 | } | 3312 | } |
| 3313 | |||
| 3314 | if (ha->eft) { | ||
| 3315 | memset(ha->eft, 0, EFT_SIZE); | ||
| 3316 | rval = qla2x00_enable_eft_trace(ha, | ||
| 3317 | ha->eft_dma, EFT_NUM_BUFFERS); | ||
| 3318 | if (rval) { | ||
| 3319 | qla_printk(KERN_WARNING, ha, | ||
| 3320 | "Unable to reinitialize EFT " | ||
| 3321 | "(%d).\n", rval); | ||
| 3322 | } | ||
| 3323 | } | ||
| 3311 | } else { /* failed the ISP abort */ | 3324 | } else { /* failed the ISP abort */ |
| 3312 | ha->flags.online = 1; | 3325 | ha->flags.online = 1; |
| 3313 | if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) { | 3326 | if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) { |
| @@ -4026,8 +4039,8 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha) | |||
| 4026 | ret = qla2x00_stop_firmware(ha); | 4039 | ret = qla2x00_stop_firmware(ha); |
| 4027 | for (retries = 5; ret != QLA_SUCCESS && ret != QLA_FUNCTION_TIMEOUT && | 4040 | for (retries = 5; ret != QLA_SUCCESS && ret != QLA_FUNCTION_TIMEOUT && |
| 4028 | retries ; retries--) { | 4041 | retries ; retries--) { |
| 4029 | qla2x00_reset_chip(ha); | 4042 | ha->isp_ops->reset_chip(ha); |
| 4030 | if (qla2x00_chip_diag(ha) != QLA_SUCCESS) | 4043 | if (ha->isp_ops->chip_diag(ha) != QLA_SUCCESS) |
| 4031 | continue; | 4044 | continue; |
| 4032 | if (qla2x00_setup_chip(ha) != QLA_SUCCESS) | 4045 | if (qla2x00_setup_chip(ha) != QLA_SUCCESS) |
| 4033 | continue; | 4046 | continue; |
| @@ -4049,7 +4062,7 @@ qla24xx_configure_vhba(scsi_qla_host_t *ha) | |||
| 4049 | rval = qla2x00_fw_ready(ha->parent); | 4062 | rval = qla2x00_fw_ready(ha->parent); |
| 4050 | if (rval == QLA_SUCCESS) { | 4063 | if (rval == QLA_SUCCESS) { |
| 4051 | clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); | 4064 | clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); |
| 4052 | qla2x00_marker(ha->parent, 0, 0, MK_SYNC_ALL); | 4065 | qla2x00_marker(ha, 0, 0, MK_SYNC_ALL); |
| 4053 | } | 4066 | } |
| 4054 | 4067 | ||
| 4055 | ha->flags.management_server_logged_in = 0; | 4068 | ha->flags.management_server_logged_in = 0; |
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 5489d5024673..d57669aa4615 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c | |||
| @@ -454,10 +454,11 @@ qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun, | |||
| 454 | { | 454 | { |
| 455 | int ret; | 455 | int ret; |
| 456 | unsigned long flags = 0; | 456 | unsigned long flags = 0; |
| 457 | scsi_qla_host_t *pha = to_qla_parent(ha); | ||
| 457 | 458 | ||
| 458 | spin_lock_irqsave(&ha->hardware_lock, flags); | 459 | spin_lock_irqsave(&pha->hardware_lock, flags); |
| 459 | ret = __qla2x00_marker(ha, loop_id, lun, type); | 460 | ret = __qla2x00_marker(ha, loop_id, lun, type); |
| 460 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 461 | spin_unlock_irqrestore(&pha->hardware_lock, flags); |
| 461 | 462 | ||
| 462 | return (ret); | 463 | return (ret); |
| 463 | } | 464 | } |
| @@ -672,7 +673,7 @@ qla24xx_start_scsi(srb_t *sp) | |||
| 672 | { | 673 | { |
| 673 | int ret, nseg; | 674 | int ret, nseg; |
| 674 | unsigned long flags; | 675 | unsigned long flags; |
| 675 | scsi_qla_host_t *ha; | 676 | scsi_qla_host_t *ha, *pha; |
| 676 | struct scsi_cmnd *cmd; | 677 | struct scsi_cmnd *cmd; |
| 677 | uint32_t *clr_ptr; | 678 | uint32_t *clr_ptr; |
| 678 | uint32_t index; | 679 | uint32_t index; |
| @@ -686,6 +687,7 @@ qla24xx_start_scsi(srb_t *sp) | |||
| 686 | /* Setup device pointers. */ | 687 | /* Setup device pointers. */ |
| 687 | ret = 0; | 688 | ret = 0; |
| 688 | ha = sp->ha; | 689 | ha = sp->ha; |
| 690 | pha = to_qla_parent(ha); | ||
| 689 | reg = &ha->iobase->isp24; | 691 | reg = &ha->iobase->isp24; |
| 690 | cmd = sp->cmd; | 692 | cmd = sp->cmd; |
| 691 | /* So we know we haven't pci_map'ed anything yet */ | 693 | /* So we know we haven't pci_map'ed anything yet */ |
| @@ -700,7 +702,7 @@ qla24xx_start_scsi(srb_t *sp) | |||
| 700 | } | 702 | } |
| 701 | 703 | ||
| 702 | /* Acquire ring specific lock */ | 704 | /* Acquire ring specific lock */ |
| 703 | spin_lock_irqsave(&ha->hardware_lock, flags); | 705 | spin_lock_irqsave(&pha->hardware_lock, flags); |
| 704 | 706 | ||
| 705 | /* Check for room in outstanding command list. */ | 707 | /* Check for room in outstanding command list. */ |
| 706 | handle = ha->current_outstanding_cmd; | 708 | handle = ha->current_outstanding_cmd; |
| @@ -795,14 +797,14 @@ qla24xx_start_scsi(srb_t *sp) | |||
| 795 | ha->response_ring_ptr->signature != RESPONSE_PROCESSED) | 797 | ha->response_ring_ptr->signature != RESPONSE_PROCESSED) |
| 796 | qla24xx_process_response_queue(ha); | 798 | qla24xx_process_response_queue(ha); |
| 797 | 799 | ||
| 798 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 800 | spin_unlock_irqrestore(&pha->hardware_lock, flags); |
| 799 | return QLA_SUCCESS; | 801 | return QLA_SUCCESS; |
| 800 | 802 | ||
| 801 | queuing_error: | 803 | queuing_error: |
| 802 | if (tot_dsds) | 804 | if (tot_dsds) |
| 803 | scsi_dma_unmap(cmd); | 805 | scsi_dma_unmap(cmd); |
| 804 | 806 | ||
| 805 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 807 | spin_unlock_irqrestore(&pha->hardware_lock, flags); |
| 806 | 808 | ||
| 807 | return QLA_FUNCTION_FAILED; | 809 | return QLA_FUNCTION_FAILED; |
| 808 | } | 810 | } |
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index ec63b79f900a..874d802edb7d 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c | |||
| @@ -542,10 +542,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) | |||
| 542 | break; | 542 | break; |
| 543 | 543 | ||
| 544 | case MBA_PORT_UPDATE: /* Port database update */ | 544 | case MBA_PORT_UPDATE: /* Port database update */ |
| 545 | /* Only handle SCNs for our Vport index. */ | ||
| 546 | if (ha->parent && ha->vp_idx != (mb[3] & 0xff)) | ||
| 547 | break; | ||
| 548 | |||
| 549 | /* | 545 | /* |
| 550 | * If PORT UPDATE is global (recieved LIP_OCCURED/LIP_RESET | 546 | * If PORT UPDATE is global (recieved LIP_OCCURED/LIP_RESET |
| 551 | * event etc. earlier indicating loop is down) then process | 547 | * event etc. earlier indicating loop is down) then process |
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 250d2f604397..bc90d6b8d0a0 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c | |||
| @@ -918,6 +918,8 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa, | |||
| 918 | rval = qla2x00_mailbox_command(ha, mcp); | 918 | rval = qla2x00_mailbox_command(ha, mcp); |
| 919 | if (mcp->mb[0] == MBS_COMMAND_ERROR) | 919 | if (mcp->mb[0] == MBS_COMMAND_ERROR) |
| 920 | rval = QLA_COMMAND_ERROR; | 920 | rval = QLA_COMMAND_ERROR; |
| 921 | else if (mcp->mb[0] == MBS_INVALID_COMMAND) | ||
| 922 | rval = QLA_INVALID_COMMAND; | ||
| 921 | 923 | ||
| 922 | /* Return data. */ | 924 | /* Return data. */ |
| 923 | *id = mcp->mb[1]; | 925 | *id = mcp->mb[1]; |
| @@ -2161,17 +2163,18 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp) | |||
| 2161 | struct abort_entry_24xx *abt; | 2163 | struct abort_entry_24xx *abt; |
| 2162 | dma_addr_t abt_dma; | 2164 | dma_addr_t abt_dma; |
| 2163 | uint32_t handle; | 2165 | uint32_t handle; |
| 2166 | scsi_qla_host_t *pha = to_qla_parent(ha); | ||
| 2164 | 2167 | ||
| 2165 | DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); | 2168 | DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); |
| 2166 | 2169 | ||
| 2167 | fcport = sp->fcport; | 2170 | fcport = sp->fcport; |
| 2168 | 2171 | ||
| 2169 | spin_lock_irqsave(&ha->hardware_lock, flags); | 2172 | spin_lock_irqsave(&pha->hardware_lock, flags); |
| 2170 | for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) { | 2173 | for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) { |
| 2171 | if (ha->outstanding_cmds[handle] == sp) | 2174 | if (pha->outstanding_cmds[handle] == sp) |
| 2172 | break; | 2175 | break; |
| 2173 | } | 2176 | } |
| 2174 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 2177 | spin_unlock_irqrestore(&pha->hardware_lock, flags); |
| 2175 | if (handle == MAX_OUTSTANDING_COMMANDS) { | 2178 | if (handle == MAX_OUTSTANDING_COMMANDS) { |
| 2176 | /* Command not found. */ | 2179 | /* Command not found. */ |
| 2177 | return QLA_FUNCTION_FAILED; | 2180 | return QLA_FUNCTION_FAILED; |
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 62a3ad6e8ecb..50baf6a1d67c 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c | |||
| @@ -43,6 +43,7 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha) | |||
| 43 | 43 | ||
| 44 | set_bit(vp_id, ha->vp_idx_map); | 44 | set_bit(vp_id, ha->vp_idx_map); |
| 45 | ha->num_vhosts++; | 45 | ha->num_vhosts++; |
| 46 | ha->cur_vport_count++; | ||
| 46 | vha->vp_idx = vp_id; | 47 | vha->vp_idx = vp_id; |
| 47 | list_add_tail(&vha->vp_list, &ha->vp_list); | 48 | list_add_tail(&vha->vp_list, &ha->vp_list); |
| 48 | mutex_unlock(&ha->vport_lock); | 49 | mutex_unlock(&ha->vport_lock); |
| @@ -58,6 +59,7 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha) | |||
| 58 | mutex_lock(&ha->vport_lock); | 59 | mutex_lock(&ha->vport_lock); |
| 59 | vp_id = vha->vp_idx; | 60 | vp_id = vha->vp_idx; |
| 60 | ha->num_vhosts--; | 61 | ha->num_vhosts--; |
| 62 | ha->cur_vport_count--; | ||
| 61 | clear_bit(vp_id, ha->vp_idx_map); | 63 | clear_bit(vp_id, ha->vp_idx_map); |
| 62 | list_del(&vha->vp_list); | 64 | list_del(&vha->vp_list); |
| 63 | mutex_unlock(&ha->vport_lock); | 65 | mutex_unlock(&ha->vport_lock); |
| @@ -103,8 +105,8 @@ qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha) | |||
| 103 | "loop_id=0x%04x :%x\n", | 105 | "loop_id=0x%04x :%x\n", |
| 104 | vha->host_no, fcport->loop_id, fcport->vp_idx)); | 106 | vha->host_no, fcport->loop_id, fcport->vp_idx)); |
| 105 | 107 | ||
| 106 | atomic_set(&fcport->state, FCS_DEVICE_DEAD); | ||
| 107 | qla2x00_mark_device_lost(vha, fcport, 0, 0); | 108 | qla2x00_mark_device_lost(vha, fcport, 0, 0); |
| 109 | atomic_set(&fcport->state, FCS_UNCONFIGURED); | ||
| 108 | } | 110 | } |
| 109 | } | 111 | } |
| 110 | 112 | ||
| @@ -276,7 +278,8 @@ qla2x00_do_dpc_vp(scsi_qla_host_t *vha) | |||
| 276 | clear_bit(RESET_ACTIVE, &vha->dpc_flags); | 278 | clear_bit(RESET_ACTIVE, &vha->dpc_flags); |
| 277 | } | 279 | } |
| 278 | 280 | ||
| 279 | if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) { | 281 | if (atomic_read(&vha->vp_state) == VP_ACTIVE && |
| 282 | test_and_clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) { | ||
| 280 | if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))) { | 283 | if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))) { |
| 281 | qla2x00_loop_resync(vha); | 284 | qla2x00_loop_resync(vha); |
| 282 | clear_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags); | 285 | clear_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags); |
| @@ -390,7 +393,6 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) | |||
| 390 | vha->parent = ha; | 393 | vha->parent = ha; |
| 391 | vha->fc_vport = fc_vport; | 394 | vha->fc_vport = fc_vport; |
| 392 | vha->device_flags = 0; | 395 | vha->device_flags = 0; |
| 393 | vha->instance = num_hosts; | ||
| 394 | vha->vp_idx = qla24xx_allocate_vp_id(vha); | 396 | vha->vp_idx = qla24xx_allocate_vp_id(vha); |
| 395 | if (vha->vp_idx > ha->max_npiv_vports) { | 397 | if (vha->vp_idx > ha->max_npiv_vports) { |
| 396 | DEBUG15(printk("scsi(%ld): Couldn't allocate vp_id.\n", | 398 | DEBUG15(printk("scsi(%ld): Couldn't allocate vp_id.\n", |
| @@ -428,7 +430,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) | |||
| 428 | host->max_cmd_len = MAX_CMDSZ; | 430 | host->max_cmd_len = MAX_CMDSZ; |
| 429 | host->max_channel = MAX_BUSES - 1; | 431 | host->max_channel = MAX_BUSES - 1; |
| 430 | host->max_lun = MAX_LUNS; | 432 | host->max_lun = MAX_LUNS; |
| 431 | host->unique_id = vha->instance; | 433 | host->unique_id = host->host_no; |
| 432 | host->max_id = MAX_TARGETS_2200; | 434 | host->max_id = MAX_TARGETS_2200; |
| 433 | host->transportt = qla2xxx_transport_vport_template; | 435 | host->transportt = qla2xxx_transport_vport_template; |
| 434 | 436 | ||
| @@ -436,12 +438,6 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) | |||
| 436 | vha->host_no, vha)); | 438 | vha->host_no, vha)); |
| 437 | 439 | ||
| 438 | vha->flags.init_done = 1; | 440 | vha->flags.init_done = 1; |
| 439 | num_hosts++; | ||
| 440 | |||
| 441 | mutex_lock(&ha->vport_lock); | ||
| 442 | set_bit(vha->vp_idx, ha->vp_idx_map); | ||
| 443 | ha->cur_vport_count++; | ||
| 444 | mutex_unlock(&ha->vport_lock); | ||
| 445 | 441 | ||
| 446 | return vha; | 442 | return vha; |
| 447 | 443 | ||
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 48eaa3bb5433..7c8af7ed2a5d 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c | |||
| @@ -27,7 +27,6 @@ char qla2x00_version_str[40]; | |||
| 27 | */ | 27 | */ |
| 28 | static struct kmem_cache *srb_cachep; | 28 | static struct kmem_cache *srb_cachep; |
| 29 | 29 | ||
| 30 | int num_hosts; | ||
| 31 | int ql2xlogintimeout = 20; | 30 | int ql2xlogintimeout = 20; |
| 32 | module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR); | 31 | module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR); |
| 33 | MODULE_PARM_DESC(ql2xlogintimeout, | 32 | MODULE_PARM_DESC(ql2xlogintimeout, |
| @@ -87,6 +86,13 @@ MODULE_PARM_DESC(ql2xqfullrampup, | |||
| 87 | "depth for a device after a queue-full condition has been " | 86 | "depth for a device after a queue-full condition has been " |
| 88 | "detected. Default is 120 seconds."); | 87 | "detected. Default is 120 seconds."); |
| 89 | 88 | ||
| 89 | int ql2xiidmaenable=1; | ||
| 90 | module_param(ql2xiidmaenable, int, S_IRUGO|S_IRUSR); | ||
| 91 | MODULE_PARM_DESC(ql2xiidmaenable, | ||
| 92 | "Enables iIDMA settings " | ||
| 93 | "Default is 1 - perform iIDMA. 0 - no iIDMA."); | ||
| 94 | |||
| 95 | |||
| 90 | /* | 96 | /* |
| 91 | * SCSI host template entry points | 97 | * SCSI host template entry points |
| 92 | */ | 98 | */ |
| @@ -388,7 +394,7 @@ qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) | |||
| 388 | } | 394 | } |
| 389 | 395 | ||
| 390 | /* Close window on fcport/rport state-transitioning. */ | 396 | /* Close window on fcport/rport state-transitioning. */ |
| 391 | if (!*(fc_port_t **)rport->dd_data) { | 397 | if (fcport->drport) { |
| 392 | cmd->result = DID_IMM_RETRY << 16; | 398 | cmd->result = DID_IMM_RETRY << 16; |
| 393 | goto qc_fail_command; | 399 | goto qc_fail_command; |
| 394 | } | 400 | } |
| @@ -443,7 +449,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) | |||
| 443 | int rval; | 449 | int rval; |
| 444 | scsi_qla_host_t *pha = to_qla_parent(ha); | 450 | scsi_qla_host_t *pha = to_qla_parent(ha); |
| 445 | 451 | ||
| 446 | if (unlikely(pci_channel_offline(ha->pdev))) { | 452 | if (unlikely(pci_channel_offline(pha->pdev))) { |
| 447 | cmd->result = DID_REQUEUE << 16; | 453 | cmd->result = DID_REQUEUE << 16; |
| 448 | goto qc24_fail_command; | 454 | goto qc24_fail_command; |
| 449 | } | 455 | } |
| @@ -455,7 +461,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) | |||
| 455 | } | 461 | } |
| 456 | 462 | ||
| 457 | /* Close window on fcport/rport state-transitioning. */ | 463 | /* Close window on fcport/rport state-transitioning. */ |
| 458 | if (!*(fc_port_t **)rport->dd_data) { | 464 | if (fcport->drport) { |
| 459 | cmd->result = DID_IMM_RETRY << 16; | 465 | cmd->result = DID_IMM_RETRY << 16; |
| 460 | goto qc24_fail_command; | 466 | goto qc24_fail_command; |
| 461 | } | 467 | } |
| @@ -617,6 +623,40 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha) | |||
| 617 | return (return_status); | 623 | return (return_status); |
| 618 | } | 624 | } |
| 619 | 625 | ||
| 626 | void | ||
| 627 | qla2x00_abort_fcport_cmds(fc_port_t *fcport) | ||
| 628 | { | ||
| 629 | int cnt; | ||
| 630 | unsigned long flags; | ||
| 631 | srb_t *sp; | ||
| 632 | scsi_qla_host_t *ha = fcport->ha; | ||
| 633 | scsi_qla_host_t *pha = to_qla_parent(ha); | ||
| 634 | |||
| 635 | spin_lock_irqsave(&pha->hardware_lock, flags); | ||
| 636 | for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { | ||
| 637 | sp = pha->outstanding_cmds[cnt]; | ||
| 638 | if (!sp) | ||
| 639 | continue; | ||
| 640 | if (sp->fcport != fcport) | ||
| 641 | continue; | ||
| 642 | |||
| 643 | spin_unlock_irqrestore(&pha->hardware_lock, flags); | ||
| 644 | if (ha->isp_ops->abort_command(ha, sp)) { | ||
| 645 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
| 646 | "Abort failed -- %lx\n", sp->cmd->serial_number)); | ||
| 647 | } else { | ||
| 648 | if (qla2x00_eh_wait_on_command(ha, sp->cmd) != | ||
| 649 | QLA_SUCCESS) | ||
| 650 | DEBUG2(qla_printk(KERN_WARNING, ha, | ||
| 651 | "Abort failed while waiting -- %lx\n", | ||
| 652 | sp->cmd->serial_number)); | ||
| 653 | |||
| 654 | } | ||
| 655 | spin_lock_irqsave(&pha->hardware_lock, flags); | ||
| 656 | } | ||
| 657 | spin_unlock_irqrestore(&pha->hardware_lock, flags); | ||
| 658 | } | ||
| 659 | |||
| 620 | static void | 660 | static void |
| 621 | qla2x00_block_error_handler(struct scsi_cmnd *cmnd) | 661 | qla2x00_block_error_handler(struct scsi_cmnd *cmnd) |
| 622 | { | 662 | { |
| @@ -1073,7 +1113,7 @@ qla2xxx_slave_configure(struct scsi_device *sdev) | |||
| 1073 | else | 1113 | else |
| 1074 | scsi_deactivate_tcq(sdev, ha->max_q_depth); | 1114 | scsi_deactivate_tcq(sdev, ha->max_q_depth); |
| 1075 | 1115 | ||
| 1076 | rport->dev_loss_tmo = ha->port_down_retry_count + 5; | 1116 | rport->dev_loss_tmo = ha->port_down_retry_count; |
| 1077 | 1117 | ||
| 1078 | return 0; | 1118 | return 0; |
| 1079 | } | 1119 | } |
| @@ -1629,9 +1669,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 1629 | } | 1669 | } |
| 1630 | host->can_queue = ha->request_q_length + 128; | 1670 | host->can_queue = ha->request_q_length + 128; |
| 1631 | 1671 | ||
| 1632 | /* load the F/W, read paramaters, and init the H/W */ | ||
| 1633 | ha->instance = num_hosts; | ||
| 1634 | |||
| 1635 | mutex_init(&ha->vport_lock); | 1672 | mutex_init(&ha->vport_lock); |
| 1636 | init_completion(&ha->mbx_cmd_comp); | 1673 | init_completion(&ha->mbx_cmd_comp); |
| 1637 | complete(&ha->mbx_cmd_comp); | 1674 | complete(&ha->mbx_cmd_comp); |
| @@ -1679,7 +1716,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 1679 | 1716 | ||
| 1680 | host->this_id = 255; | 1717 | host->this_id = 255; |
| 1681 | host->cmd_per_lun = 3; | 1718 | host->cmd_per_lun = 3; |
| 1682 | host->unique_id = ha->instance; | 1719 | host->unique_id = host->host_no; |
| 1683 | host->max_cmd_len = MAX_CMDSZ; | 1720 | host->max_cmd_len = MAX_CMDSZ; |
| 1684 | host->max_channel = MAX_BUSES - 1; | 1721 | host->max_channel = MAX_BUSES - 1; |
| 1685 | host->max_lun = MAX_LUNS; | 1722 | host->max_lun = MAX_LUNS; |
| @@ -1700,8 +1737,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 1700 | ha->flags.init_done = 1; | 1737 | ha->flags.init_done = 1; |
| 1701 | ha->flags.online = 1; | 1738 | ha->flags.online = 1; |
| 1702 | 1739 | ||
| 1703 | num_hosts++; | ||
| 1704 | |||
| 1705 | ret = scsi_add_host(host, &pdev->dev); | 1740 | ret = scsi_add_host(host, &pdev->dev); |
| 1706 | if (ret) | 1741 | if (ret) |
| 1707 | goto probe_failed; | 1742 | goto probe_failed; |
| @@ -1813,27 +1848,21 @@ static inline void | |||
| 1813 | qla2x00_schedule_rport_del(struct scsi_qla_host *ha, fc_port_t *fcport, | 1848 | qla2x00_schedule_rport_del(struct scsi_qla_host *ha, fc_port_t *fcport, |
| 1814 | int defer) | 1849 | int defer) |
| 1815 | { | 1850 | { |
| 1816 | unsigned long flags; | ||
| 1817 | struct fc_rport *rport; | 1851 | struct fc_rport *rport; |
| 1852 | scsi_qla_host_t *pha = to_qla_parent(ha); | ||
| 1818 | 1853 | ||
| 1819 | if (!fcport->rport) | 1854 | if (!fcport->rport) |
| 1820 | return; | 1855 | return; |
| 1821 | 1856 | ||
| 1822 | rport = fcport->rport; | 1857 | rport = fcport->rport; |
| 1823 | if (defer) { | 1858 | if (defer) { |
| 1824 | spin_lock_irqsave(&fcport->rport_lock, flags); | 1859 | spin_lock_irq(ha->host->host_lock); |
| 1825 | fcport->drport = rport; | 1860 | fcport->drport = rport; |
| 1826 | fcport->rport = NULL; | 1861 | spin_unlock_irq(ha->host->host_lock); |
| 1827 | *(fc_port_t **)rport->dd_data = NULL; | 1862 | set_bit(FCPORT_UPDATE_NEEDED, &pha->dpc_flags); |
| 1828 | spin_unlock_irqrestore(&fcport->rport_lock, flags); | 1863 | qla2xxx_wake_dpc(pha); |
| 1829 | set_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags); | 1864 | } else |
| 1830 | } else { | ||
| 1831 | spin_lock_irqsave(&fcport->rport_lock, flags); | ||
| 1832 | fcport->rport = NULL; | ||
| 1833 | *(fc_port_t **)rport->dd_data = NULL; | ||
| 1834 | spin_unlock_irqrestore(&fcport->rport_lock, flags); | ||
| 1835 | fc_remote_port_delete(rport); | 1865 | fc_remote_port_delete(rport); |
| 1836 | } | ||
| 1837 | } | 1866 | } |
| 1838 | 1867 | ||
| 1839 | /* | 1868 | /* |
| @@ -1903,7 +1932,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer) | |||
| 1903 | scsi_qla_host_t *pha = to_qla_parent(ha); | 1932 | scsi_qla_host_t *pha = to_qla_parent(ha); |
| 1904 | 1933 | ||
| 1905 | list_for_each_entry(fcport, &pha->fcports, list) { | 1934 | list_for_each_entry(fcport, &pha->fcports, list) { |
| 1906 | if (ha->vp_idx != 0 && ha->vp_idx != fcport->vp_idx) | 1935 | if (ha->vp_idx != fcport->vp_idx) |
| 1907 | continue; | 1936 | continue; |
| 1908 | /* | 1937 | /* |
| 1909 | * No point in marking the device as lost, if the device is | 1938 | * No point in marking the device as lost, if the device is |
| @@ -1911,17 +1940,10 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer) | |||
| 1911 | */ | 1940 | */ |
| 1912 | if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD) | 1941 | if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD) |
| 1913 | continue; | 1942 | continue; |
| 1914 | if (atomic_read(&fcport->state) == FCS_ONLINE) { | 1943 | if (atomic_read(&fcport->state) == FCS_ONLINE) |
| 1915 | if (defer) | 1944 | qla2x00_schedule_rport_del(ha, fcport, defer); |
| 1916 | qla2x00_schedule_rport_del(ha, fcport, defer); | ||
| 1917 | else if (ha->vp_idx == fcport->vp_idx) | ||
| 1918 | qla2x00_schedule_rport_del(ha, fcport, defer); | ||
| 1919 | } | ||
| 1920 | atomic_set(&fcport->state, FCS_DEVICE_LOST); | 1945 | atomic_set(&fcport->state, FCS_DEVICE_LOST); |
| 1921 | } | 1946 | } |
| 1922 | |||
| 1923 | if (defer) | ||
| 1924 | qla2xxx_wake_dpc(ha); | ||
| 1925 | } | 1947 | } |
| 1926 | 1948 | ||
| 1927 | /* | 1949 | /* |
| @@ -2156,7 +2178,7 @@ qla2x00_alloc_work(struct scsi_qla_host *ha, enum qla_work_type type, | |||
| 2156 | static int | 2178 | static int |
| 2157 | qla2x00_post_work(struct scsi_qla_host *ha, struct qla_work_evt *e, int locked) | 2179 | qla2x00_post_work(struct scsi_qla_host *ha, struct qla_work_evt *e, int locked) |
| 2158 | { | 2180 | { |
| 2159 | unsigned long flags; | 2181 | unsigned long uninitialized_var(flags); |
| 2160 | scsi_qla_host_t *pha = to_qla_parent(ha); | 2182 | scsi_qla_host_t *pha = to_qla_parent(ha); |
| 2161 | 2183 | ||
| 2162 | if (!locked) | 2184 | if (!locked) |
| @@ -2313,8 +2335,10 @@ qla2x00_do_dpc(void *data) | |||
| 2313 | ha->host_no)); | 2335 | ha->host_no)); |
| 2314 | } | 2336 | } |
| 2315 | 2337 | ||
| 2316 | if (test_and_clear_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags)) | 2338 | if (test_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags)) { |
| 2317 | qla2x00_update_fcports(ha); | 2339 | qla2x00_update_fcports(ha); |
| 2340 | clear_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags); | ||
| 2341 | } | ||
| 2318 | 2342 | ||
| 2319 | if (test_and_clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) && | 2343 | if (test_and_clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) && |
| 2320 | (!(test_and_set_bit(RESET_ACTIVE, &ha->dpc_flags)))) { | 2344 | (!(test_and_set_bit(RESET_ACTIVE, &ha->dpc_flags)))) { |
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 1728ab3ccb20..1bca74474935 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c | |||
| @@ -869,11 +869,9 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr, | |||
| 869 | uint32_t i; | 869 | uint32_t i; |
| 870 | uint32_t *dwptr; | 870 | uint32_t *dwptr; |
| 871 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | 871 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; |
| 872 | unsigned long flags; | ||
| 873 | 872 | ||
| 874 | ret = QLA_SUCCESS; | 873 | ret = QLA_SUCCESS; |
| 875 | 874 | ||
| 876 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
| 877 | /* Enable flash write. */ | 875 | /* Enable flash write. */ |
| 878 | WRT_REG_DWORD(®->ctrl_status, | 876 | WRT_REG_DWORD(®->ctrl_status, |
| 879 | RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE); | 877 | RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE); |
| @@ -907,7 +905,6 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr, | |||
| 907 | WRT_REG_DWORD(®->ctrl_status, | 905 | WRT_REG_DWORD(®->ctrl_status, |
| 908 | RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); | 906 | RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); |
| 909 | RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ | 907 | RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ |
| 910 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
| 911 | 908 | ||
| 912 | return ret; | 909 | return ret; |
| 913 | } | 910 | } |
| @@ -2306,6 +2303,51 @@ qla24xx_get_flash_version(scsi_qla_host_t *ha, void *mbuf) | |||
| 2306 | } | 2303 | } |
| 2307 | 2304 | ||
| 2308 | static int | 2305 | static int |
| 2306 | qla2xxx_is_vpd_valid(uint8_t *pos, uint8_t *end) | ||
| 2307 | { | ||
| 2308 | if (pos >= end || *pos != 0x82) | ||
| 2309 | return 0; | ||
| 2310 | |||
| 2311 | pos += 3 + pos[1]; | ||
| 2312 | if (pos >= end || *pos != 0x90) | ||
| 2313 | return 0; | ||
| 2314 | |||
| 2315 | pos += 3 + pos[1]; | ||
| 2316 | if (pos >= end || *pos != 0x78) | ||
| 2317 | return 0; | ||
| 2318 | |||
| 2319 | return 1; | ||
| 2320 | } | ||
| 2321 | |||
| 2322 | int | ||
| 2323 | qla2xxx_get_vpd_field(scsi_qla_host_t *ha, char *key, char *str, size_t size) | ||
| 2324 | { | ||
| 2325 | uint8_t *pos = ha->vpd; | ||
| 2326 | uint8_t *end = pos + ha->vpd_size; | ||
| 2327 | int len = 0; | ||
| 2328 | |||
| 2329 | if (!IS_FWI2_CAPABLE(ha) || !qla2xxx_is_vpd_valid(pos, end)) | ||
| 2330 | return 0; | ||
| 2331 | |||
| 2332 | while (pos < end && *pos != 0x78) { | ||
| 2333 | len = (*pos == 0x82) ? pos[1] : pos[2]; | ||
| 2334 | |||
| 2335 | if (!strncmp(pos, key, strlen(key))) | ||
| 2336 | break; | ||
| 2337 | |||
| 2338 | if (*pos != 0x90 && *pos != 0x91) | ||
| 2339 | pos += len; | ||
| 2340 | |||
| 2341 | pos += 3; | ||
| 2342 | } | ||
| 2343 | |||
| 2344 | if (pos < end - len && *pos != 0x78) | ||
| 2345 | return snprintf(str, size, "%.*s", len, pos + 3); | ||
| 2346 | |||
| 2347 | return 0; | ||
| 2348 | } | ||
| 2349 | |||
| 2350 | static int | ||
| 2309 | qla2xxx_hw_event_store(scsi_qla_host_t *ha, uint32_t *fdata) | 2351 | qla2xxx_hw_event_store(scsi_qla_host_t *ha, uint32_t *fdata) |
| 2310 | { | 2352 | { |
| 2311 | uint32_t d[2], faddr; | 2353 | uint32_t d[2], faddr; |
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index d058c8862b35..676c390db354 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | /* | 7 | /* |
| 8 | * Driver version | 8 | * Driver version |
| 9 | */ | 9 | */ |
| 10 | #define QLA2XXX_VERSION "8.02.01-k4" | 10 | #define QLA2XXX_VERSION "8.02.01-k6" |
| 11 | 11 | ||
| 12 | #define QLA_DRIVER_MAJOR_VER 8 | 12 | #define QLA_DRIVER_MAJOR_VER 8 |
| 13 | #define QLA_DRIVER_MINOR_VER 2 | 13 | #define QLA_DRIVER_MINOR_VER 2 |
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 5822dd595826..88bebb13bc52 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c | |||
| @@ -46,6 +46,8 @@ MODULE_PARM_DESC(ql4xextended_error_logging, | |||
| 46 | 46 | ||
| 47 | int ql4_mod_unload = 0; | 47 | int ql4_mod_unload = 0; |
| 48 | 48 | ||
| 49 | #define QL4_DEF_QDEPTH 32 | ||
| 50 | |||
| 49 | /* | 51 | /* |
| 50 | * SCSI host template entry points | 52 | * SCSI host template entry points |
| 51 | */ | 53 | */ |
| @@ -1387,7 +1389,7 @@ static int qla4xxx_slave_alloc(struct scsi_device *sdev) | |||
| 1387 | 1389 | ||
| 1388 | sdev->hostdata = ddb; | 1390 | sdev->hostdata = ddb; |
| 1389 | sdev->tagged_supported = 1; | 1391 | sdev->tagged_supported = 1; |
| 1390 | scsi_activate_tcq(sdev, sdev->host->can_queue); | 1392 | scsi_activate_tcq(sdev, QL4_DEF_QDEPTH); |
| 1391 | return 0; | 1393 | return 0; |
| 1392 | } | 1394 | } |
| 1393 | 1395 | ||
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 36c92f961e15..ee6be596503d 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c | |||
| @@ -197,11 +197,43 @@ static void | |||
| 197 | scsi_pool_free_command(struct scsi_host_cmd_pool *pool, | 197 | scsi_pool_free_command(struct scsi_host_cmd_pool *pool, |
| 198 | struct scsi_cmnd *cmd) | 198 | struct scsi_cmnd *cmd) |
| 199 | { | 199 | { |
| 200 | if (cmd->prot_sdb) | ||
| 201 | kmem_cache_free(scsi_sdb_cache, cmd->prot_sdb); | ||
| 202 | |||
| 200 | kmem_cache_free(pool->sense_slab, cmd->sense_buffer); | 203 | kmem_cache_free(pool->sense_slab, cmd->sense_buffer); |
| 201 | kmem_cache_free(pool->cmd_slab, cmd); | 204 | kmem_cache_free(pool->cmd_slab, cmd); |
| 202 | } | 205 | } |
| 203 | 206 | ||
| 204 | /** | 207 | /** |
| 208 | * scsi_host_alloc_command - internal function to allocate command | ||
| 209 | * @shost: SCSI host whose pool to allocate from | ||
| 210 | * @gfp_mask: mask for the allocation | ||
| 211 | * | ||
| 212 | * Returns a fully allocated command with sense buffer and protection | ||
| 213 | * data buffer (where applicable) or NULL on failure | ||
| 214 | */ | ||
| 215 | static struct scsi_cmnd * | ||
| 216 | scsi_host_alloc_command(struct Scsi_Host *shost, gfp_t gfp_mask) | ||
| 217 | { | ||
| 218 | struct scsi_cmnd *cmd; | ||
| 219 | |||
| 220 | cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask); | ||
| 221 | if (!cmd) | ||
| 222 | return NULL; | ||
| 223 | |||
| 224 | if (scsi_host_get_prot(shost) >= SHOST_DIX_TYPE0_PROTECTION) { | ||
| 225 | cmd->prot_sdb = kmem_cache_zalloc(scsi_sdb_cache, gfp_mask); | ||
| 226 | |||
| 227 | if (!cmd->prot_sdb) { | ||
| 228 | scsi_pool_free_command(shost->cmd_pool, cmd); | ||
| 229 | return NULL; | ||
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | return cmd; | ||
| 234 | } | ||
| 235 | |||
| 236 | /** | ||
| 205 | * __scsi_get_command - Allocate a struct scsi_cmnd | 237 | * __scsi_get_command - Allocate a struct scsi_cmnd |
| 206 | * @shost: host to transmit command | 238 | * @shost: host to transmit command |
| 207 | * @gfp_mask: allocation mask | 239 | * @gfp_mask: allocation mask |
| @@ -214,7 +246,7 @@ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask) | |||
| 214 | struct scsi_cmnd *cmd; | 246 | struct scsi_cmnd *cmd; |
| 215 | unsigned char *buf; | 247 | unsigned char *buf; |
| 216 | 248 | ||
| 217 | cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask); | 249 | cmd = scsi_host_alloc_command(shost, gfp_mask); |
| 218 | 250 | ||
| 219 | if (unlikely(!cmd)) { | 251 | if (unlikely(!cmd)) { |
| 220 | unsigned long flags; | 252 | unsigned long flags; |
| @@ -457,7 +489,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost) | |||
| 457 | /* | 489 | /* |
| 458 | * Get one backup command for this host. | 490 | * Get one backup command for this host. |
| 459 | */ | 491 | */ |
| 460 | cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask); | 492 | cmd = scsi_host_alloc_command(shost, gfp_mask); |
| 461 | if (!cmd) { | 493 | if (!cmd) { |
| 462 | scsi_put_host_cmd_pool(gfp_mask); | 494 | scsi_put_host_cmd_pool(gfp_mask); |
| 463 | shost->cmd_pool = NULL; | 495 | shost->cmd_pool = NULL; |
| @@ -902,11 +934,20 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags) | |||
| 902 | 934 | ||
| 903 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | 935 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); |
| 904 | 936 | ||
| 905 | /* Check to see if the queue is managed by the block layer. | 937 | /* |
| 906 | * If it is, and we fail to adjust the depth, exit. */ | 938 | * Check to see if the queue is managed by the block layer. |
| 907 | if (blk_queue_tagged(sdev->request_queue) && | 939 | * If it is, and we fail to adjust the depth, exit. |
| 908 | blk_queue_resize_tags(sdev->request_queue, tags) != 0) | 940 | * |
| 909 | goto out; | 941 | * Do not resize the tag map if it is a host wide share bqt, |
| 942 | * because the size should be the hosts's can_queue. If there | ||
| 943 | * is more IO than the LLD's can_queue (so there are not enuogh | ||
| 944 | * tags) request_fn's host queue ready check will handle it. | ||
| 945 | */ | ||
| 946 | if (!sdev->host->bqt) { | ||
| 947 | if (blk_queue_tagged(sdev->request_queue) && | ||
| 948 | blk_queue_resize_tags(sdev->request_queue, tags) != 0) | ||
| 949 | goto out; | ||
| 950 | } | ||
| 910 | 951 | ||
| 911 | sdev->queue_depth = tags; | 952 | sdev->queue_depth = tags; |
| 912 | switch (tagged) { | 953 | switch (tagged) { |
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 01d11a01ffbf..27c633f55794 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c | |||
| @@ -1753,7 +1753,7 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) | |||
| 1753 | open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); | 1753 | open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); |
| 1754 | if (!open_devip) { | 1754 | if (!open_devip) { |
| 1755 | printk(KERN_ERR "%s: out of memory at line %d\n", | 1755 | printk(KERN_ERR "%s: out of memory at line %d\n", |
| 1756 | __FUNCTION__, __LINE__); | 1756 | __func__, __LINE__); |
| 1757 | return NULL; | 1757 | return NULL; |
| 1758 | } | 1758 | } |
| 1759 | } | 1759 | } |
| @@ -2656,7 +2656,7 @@ static int sdebug_add_adapter(void) | |||
| 2656 | sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); | 2656 | sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); |
| 2657 | if (NULL == sdbg_host) { | 2657 | if (NULL == sdbg_host) { |
| 2658 | printk(KERN_ERR "%s: out of memory at line %d\n", | 2658 | printk(KERN_ERR "%s: out of memory at line %d\n", |
| 2659 | __FUNCTION__, __LINE__); | 2659 | __func__, __LINE__); |
| 2660 | return -ENOMEM; | 2660 | return -ENOMEM; |
| 2661 | } | 2661 | } |
| 2662 | 2662 | ||
| @@ -2667,7 +2667,7 @@ static int sdebug_add_adapter(void) | |||
| 2667 | sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); | 2667 | sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); |
| 2668 | if (!sdbg_devinfo) { | 2668 | if (!sdbg_devinfo) { |
| 2669 | printk(KERN_ERR "%s: out of memory at line %d\n", | 2669 | printk(KERN_ERR "%s: out of memory at line %d\n", |
| 2670 | __FUNCTION__, __LINE__); | 2670 | __func__, __LINE__); |
| 2671 | error = -ENOMEM; | 2671 | error = -ENOMEM; |
| 2672 | goto clean; | 2672 | goto clean; |
| 2673 | } | 2673 | } |
| @@ -2987,7 +2987,7 @@ static int sdebug_driver_probe(struct device * dev) | |||
| 2987 | 2987 | ||
| 2988 | hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); | 2988 | hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); |
| 2989 | if (NULL == hpnt) { | 2989 | if (NULL == hpnt) { |
| 2990 | printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__); | 2990 | printk(KERN_ERR "%s: scsi_register failed\n", __func__); |
| 2991 | error = -ENODEV; | 2991 | error = -ENODEV; |
| 2992 | return error; | 2992 | return error; |
| 2993 | } | 2993 | } |
| @@ -3002,7 +3002,7 @@ static int sdebug_driver_probe(struct device * dev) | |||
| 3002 | 3002 | ||
| 3003 | error = scsi_add_host(hpnt, &sdbg_host->dev); | 3003 | error = scsi_add_host(hpnt, &sdbg_host->dev); |
| 3004 | if (error) { | 3004 | if (error) { |
| 3005 | printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__); | 3005 | printk(KERN_ERR "%s: scsi_add_host failed\n", __func__); |
| 3006 | error = -ENODEV; | 3006 | error = -ENODEV; |
| 3007 | scsi_host_put(hpnt); | 3007 | scsi_host_put(hpnt); |
| 3008 | } else | 3008 | } else |
| @@ -3021,7 +3021,7 @@ static int sdebug_driver_remove(struct device * dev) | |||
| 3021 | 3021 | ||
| 3022 | if (!sdbg_host) { | 3022 | if (!sdbg_host) { |
| 3023 | printk(KERN_ERR "%s: Unable to locate host info\n", | 3023 | printk(KERN_ERR "%s: Unable to locate host info\n", |
| 3024 | __FUNCTION__); | 3024 | __func__); |
| 3025 | return -ENODEV; | 3025 | return -ENODEV; |
| 3026 | } | 3026 | } |
| 3027 | 3027 | ||
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index a235802f2981..4969e4ec75ea 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c | |||
| @@ -272,7 +272,7 @@ static void scsi_strcpy_devinfo(char *name, char *to, size_t to_length, | |||
| 272 | } | 272 | } |
| 273 | if (from_length > to_length) | 273 | if (from_length > to_length) |
| 274 | printk(KERN_WARNING "%s: %s string '%s' is too long\n", | 274 | printk(KERN_WARNING "%s: %s string '%s' is too long\n", |
| 275 | __FUNCTION__, name, from); | 275 | __func__, name, from); |
| 276 | } | 276 | } |
| 277 | 277 | ||
| 278 | /** | 278 | /** |
| @@ -298,7 +298,7 @@ static int scsi_dev_info_list_add(int compatible, char *vendor, char *model, | |||
| 298 | 298 | ||
| 299 | devinfo = kmalloc(sizeof(*devinfo), GFP_KERNEL); | 299 | devinfo = kmalloc(sizeof(*devinfo), GFP_KERNEL); |
| 300 | if (!devinfo) { | 300 | if (!devinfo) { |
| 301 | printk(KERN_ERR "%s: no memory\n", __FUNCTION__); | 301 | printk(KERN_ERR "%s: no memory\n", __func__); |
| 302 | return -ENOMEM; | 302 | return -ENOMEM; |
| 303 | } | 303 | } |
| 304 | 304 | ||
| @@ -363,7 +363,7 @@ static int scsi_dev_info_list_add_str(char *dev_list) | |||
| 363 | strflags = strsep(&next, next_check); | 363 | strflags = strsep(&next, next_check); |
| 364 | if (!model || !strflags) { | 364 | if (!model || !strflags) { |
| 365 | printk(KERN_ERR "%s: bad dev info string '%s' '%s'" | 365 | printk(KERN_ERR "%s: bad dev info string '%s' '%s'" |
| 366 | " '%s'\n", __FUNCTION__, vendor, model, | 366 | " '%s'\n", __func__, vendor, model, |
| 367 | strflags); | 367 | strflags); |
| 368 | res = -EINVAL; | 368 | res = -EINVAL; |
| 369 | } else | 369 | } else |
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 006a95916f72..880051c89bde 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c | |||
| @@ -139,7 +139,7 @@ void scsi_add_timer(struct scsi_cmnd *scmd, int timeout, | |||
| 139 | scmd->eh_timeout.function = (void (*)(unsigned long)) complete; | 139 | scmd->eh_timeout.function = (void (*)(unsigned long)) complete; |
| 140 | 140 | ||
| 141 | SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p, time:" | 141 | SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p, time:" |
| 142 | " %d, (%p)\n", __FUNCTION__, | 142 | " %d, (%p)\n", __func__, |
| 143 | scmd, timeout, complete)); | 143 | scmd, timeout, complete)); |
| 144 | 144 | ||
| 145 | add_timer(&scmd->eh_timeout); | 145 | add_timer(&scmd->eh_timeout); |
| @@ -163,7 +163,7 @@ int scsi_delete_timer(struct scsi_cmnd *scmd) | |||
| 163 | rtn = del_timer(&scmd->eh_timeout); | 163 | rtn = del_timer(&scmd->eh_timeout); |
| 164 | 164 | ||
| 165 | SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p," | 165 | SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p," |
| 166 | " rtn: %d\n", __FUNCTION__, | 166 | " rtn: %d\n", __func__, |
| 167 | scmd, rtn)); | 167 | scmd, rtn)); |
| 168 | 168 | ||
| 169 | scmd->eh_timeout.data = (unsigned long)NULL; | 169 | scmd->eh_timeout.data = (unsigned long)NULL; |
| @@ -233,7 +233,7 @@ int scsi_block_when_processing_errors(struct scsi_device *sdev) | |||
| 233 | 233 | ||
| 234 | online = scsi_device_online(sdev); | 234 | online = scsi_device_online(sdev); |
| 235 | 235 | ||
| 236 | SCSI_LOG_ERROR_RECOVERY(5, printk("%s: rtn: %d\n", __FUNCTION__, | 236 | SCSI_LOG_ERROR_RECOVERY(5, printk("%s: rtn: %d\n", __func__, |
| 237 | online)); | 237 | online)); |
| 238 | 238 | ||
| 239 | return online; | 239 | return online; |
| @@ -271,7 +271,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost, | |||
| 271 | SCSI_LOG_ERROR_RECOVERY(3, | 271 | SCSI_LOG_ERROR_RECOVERY(3, |
| 272 | sdev_printk(KERN_INFO, sdev, | 272 | sdev_printk(KERN_INFO, sdev, |
| 273 | "%s: cmds failed: %d, cancel: %d\n", | 273 | "%s: cmds failed: %d, cancel: %d\n", |
| 274 | __FUNCTION__, cmd_failed, | 274 | __func__, cmd_failed, |
| 275 | cmd_cancel)); | 275 | cmd_cancel)); |
| 276 | cmd_cancel = 0; | 276 | cmd_cancel = 0; |
| 277 | cmd_failed = 0; | 277 | cmd_failed = 0; |
| @@ -344,6 +344,9 @@ static int scsi_check_sense(struct scsi_cmnd *scmd) | |||
| 344 | return /* soft_error */ SUCCESS; | 344 | return /* soft_error */ SUCCESS; |
| 345 | 345 | ||
| 346 | case ABORTED_COMMAND: | 346 | case ABORTED_COMMAND: |
| 347 | if (sshdr.asc == 0x10) /* DIF */ | ||
| 348 | return SUCCESS; | ||
| 349 | |||
| 347 | return NEEDS_RETRY; | 350 | return NEEDS_RETRY; |
| 348 | case NOT_READY: | 351 | case NOT_READY: |
| 349 | case UNIT_ATTENTION: | 352 | case UNIT_ATTENTION: |
| @@ -470,7 +473,7 @@ static void scsi_eh_done(struct scsi_cmnd *scmd) | |||
| 470 | 473 | ||
| 471 | SCSI_LOG_ERROR_RECOVERY(3, | 474 | SCSI_LOG_ERROR_RECOVERY(3, |
| 472 | printk("%s scmd: %p result: %x\n", | 475 | printk("%s scmd: %p result: %x\n", |
| 473 | __FUNCTION__, scmd, scmd->result)); | 476 | __func__, scmd, scmd->result)); |
| 474 | 477 | ||
| 475 | eh_action = scmd->device->host->eh_action; | 478 | eh_action = scmd->device->host->eh_action; |
| 476 | if (eh_action) | 479 | if (eh_action) |
| @@ -487,7 +490,7 @@ static int scsi_try_host_reset(struct scsi_cmnd *scmd) | |||
| 487 | int rtn; | 490 | int rtn; |
| 488 | 491 | ||
| 489 | SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Host RST\n", | 492 | SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Host RST\n", |
| 490 | __FUNCTION__)); | 493 | __func__)); |
| 491 | 494 | ||
| 492 | if (!scmd->device->host->hostt->eh_host_reset_handler) | 495 | if (!scmd->device->host->hostt->eh_host_reset_handler) |
| 493 | return FAILED; | 496 | return FAILED; |
| @@ -516,7 +519,7 @@ static int scsi_try_bus_reset(struct scsi_cmnd *scmd) | |||
| 516 | int rtn; | 519 | int rtn; |
| 517 | 520 | ||
| 518 | SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Bus RST\n", | 521 | SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Bus RST\n", |
| 519 | __FUNCTION__)); | 522 | __func__)); |
| 520 | 523 | ||
| 521 | if (!scmd->device->host->hostt->eh_bus_reset_handler) | 524 | if (!scmd->device->host->hostt->eh_bus_reset_handler) |
| 522 | return FAILED; | 525 | return FAILED; |
| @@ -664,7 +667,10 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses, | |||
| 664 | ses->sdb = scmd->sdb; | 667 | ses->sdb = scmd->sdb; |
| 665 | ses->next_rq = scmd->request->next_rq; | 668 | ses->next_rq = scmd->request->next_rq; |
| 666 | ses->result = scmd->result; | 669 | ses->result = scmd->result; |
| 670 | ses->underflow = scmd->underflow; | ||
| 671 | ses->prot_op = scmd->prot_op; | ||
| 667 | 672 | ||
| 673 | scmd->prot_op = SCSI_PROT_NORMAL; | ||
| 668 | scmd->cmnd = ses->eh_cmnd; | 674 | scmd->cmnd = ses->eh_cmnd; |
| 669 | memset(scmd->cmnd, 0, BLK_MAX_CDB); | 675 | memset(scmd->cmnd, 0, BLK_MAX_CDB); |
| 670 | memset(&scmd->sdb, 0, sizeof(scmd->sdb)); | 676 | memset(&scmd->sdb, 0, sizeof(scmd->sdb)); |
| @@ -722,6 +728,8 @@ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses) | |||
| 722 | scmd->sdb = ses->sdb; | 728 | scmd->sdb = ses->sdb; |
| 723 | scmd->request->next_rq = ses->next_rq; | 729 | scmd->request->next_rq = ses->next_rq; |
| 724 | scmd->result = ses->result; | 730 | scmd->result = ses->result; |
| 731 | scmd->underflow = ses->underflow; | ||
| 732 | scmd->prot_op = ses->prot_op; | ||
| 725 | } | 733 | } |
| 726 | EXPORT_SYMBOL(scsi_eh_restore_cmnd); | 734 | EXPORT_SYMBOL(scsi_eh_restore_cmnd); |
| 727 | 735 | ||
| @@ -766,7 +774,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, | |||
| 766 | 774 | ||
| 767 | SCSI_LOG_ERROR_RECOVERY(3, | 775 | SCSI_LOG_ERROR_RECOVERY(3, |
| 768 | printk("%s: scmd: %p, timeleft: %ld\n", | 776 | printk("%s: scmd: %p, timeleft: %ld\n", |
| 769 | __FUNCTION__, scmd, timeleft)); | 777 | __func__, scmd, timeleft)); |
| 770 | 778 | ||
| 771 | /* | 779 | /* |
| 772 | * If there is time left scsi_eh_done got called, and we will | 780 | * If there is time left scsi_eh_done got called, and we will |
| @@ -778,7 +786,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, | |||
| 778 | rtn = scsi_eh_completed_normally(scmd); | 786 | rtn = scsi_eh_completed_normally(scmd); |
| 779 | SCSI_LOG_ERROR_RECOVERY(3, | 787 | SCSI_LOG_ERROR_RECOVERY(3, |
| 780 | printk("%s: scsi_eh_completed_normally %x\n", | 788 | printk("%s: scsi_eh_completed_normally %x\n", |
| 781 | __FUNCTION__, rtn)); | 789 | __func__, rtn)); |
| 782 | 790 | ||
| 783 | switch (rtn) { | 791 | switch (rtn) { |
| 784 | case SUCCESS: | 792 | case SUCCESS: |
| @@ -913,7 +921,7 @@ retry_tur: | |||
| 913 | rtn = scsi_send_eh_cmnd(scmd, tur_command, 6, SENSE_TIMEOUT, 0); | 921 | rtn = scsi_send_eh_cmnd(scmd, tur_command, 6, SENSE_TIMEOUT, 0); |
| 914 | 922 | ||
| 915 | SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n", | 923 | SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n", |
| 916 | __FUNCTION__, scmd, rtn)); | 924 | __func__, scmd, rtn)); |
| 917 | 925 | ||
| 918 | switch (rtn) { | 926 | switch (rtn) { |
| 919 | case NEEDS_RETRY: | 927 | case NEEDS_RETRY: |
| @@ -1296,7 +1304,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd) | |||
| 1296 | if (!scsi_device_online(scmd->device)) { | 1304 | if (!scsi_device_online(scmd->device)) { |
| 1297 | SCSI_LOG_ERROR_RECOVERY(5, printk("%s: device offline - report" | 1305 | SCSI_LOG_ERROR_RECOVERY(5, printk("%s: device offline - report" |
| 1298 | " as SUCCESS\n", | 1306 | " as SUCCESS\n", |
| 1299 | __FUNCTION__)); | 1307 | __func__)); |
| 1300 | return SUCCESS; | 1308 | return SUCCESS; |
| 1301 | } | 1309 | } |
| 1302 | 1310 | ||
| @@ -1511,7 +1519,7 @@ static void scsi_restart_operations(struct Scsi_Host *shost) | |||
| 1511 | * ioctls to queued block devices. | 1519 | * ioctls to queued block devices. |
| 1512 | */ | 1520 | */ |
| 1513 | SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n", | 1521 | SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n", |
| 1514 | __FUNCTION__)); | 1522 | __func__)); |
| 1515 | 1523 | ||
| 1516 | spin_lock_irqsave(shost->host_lock, flags); | 1524 | spin_lock_irqsave(shost->host_lock, flags); |
| 1517 | if (scsi_host_set_state(shost, SHOST_RUNNING)) | 1525 | if (scsi_host_set_state(shost, SHOST_RUNNING)) |
| @@ -1835,7 +1843,7 @@ scsi_reset_provider(struct scsi_device *dev, int flag) | |||
| 1835 | */ | 1843 | */ |
| 1836 | SCSI_LOG_ERROR_RECOVERY(3, | 1844 | SCSI_LOG_ERROR_RECOVERY(3, |
| 1837 | printk("%s: waking up host to restart after TMF\n", | 1845 | printk("%s: waking up host to restart after TMF\n", |
| 1838 | __FUNCTION__)); | 1846 | __func__)); |
| 1839 | 1847 | ||
| 1840 | wake_up(&shost->host_wait); | 1848 | wake_up(&shost->host_wait); |
| 1841 | 1849 | ||
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 88d1b5f44e59..ff5d56b3ee4d 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
| @@ -65,7 +65,7 @@ static struct scsi_host_sg_pool scsi_sg_pools[] = { | |||
| 65 | }; | 65 | }; |
| 66 | #undef SP | 66 | #undef SP |
| 67 | 67 | ||
| 68 | static struct kmem_cache *scsi_sdb_cache; | 68 | struct kmem_cache *scsi_sdb_cache; |
| 69 | 69 | ||
| 70 | static void scsi_run_queue(struct request_queue *q); | 70 | static void scsi_run_queue(struct request_queue *q); |
| 71 | 71 | ||
| @@ -787,6 +787,9 @@ void scsi_release_buffers(struct scsi_cmnd *cmd) | |||
| 787 | kmem_cache_free(scsi_sdb_cache, bidi_sdb); | 787 | kmem_cache_free(scsi_sdb_cache, bidi_sdb); |
| 788 | cmd->request->next_rq->special = NULL; | 788 | cmd->request->next_rq->special = NULL; |
| 789 | } | 789 | } |
| 790 | |||
| 791 | if (scsi_prot_sg_count(cmd)) | ||
| 792 | scsi_free_sgtable(cmd->prot_sdb); | ||
| 790 | } | 793 | } |
| 791 | EXPORT_SYMBOL(scsi_release_buffers); | 794 | EXPORT_SYMBOL(scsi_release_buffers); |
| 792 | 795 | ||
| @@ -947,9 +950,14 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) | |||
| 947 | * 6-byte command. | 950 | * 6-byte command. |
| 948 | */ | 951 | */ |
| 949 | scsi_requeue_command(q, cmd); | 952 | scsi_requeue_command(q, cmd); |
| 950 | return; | 953 | } else if (sshdr.asc == 0x10) /* DIX */ |
| 951 | } else { | 954 | scsi_end_request(cmd, -EIO, this_count, 0); |
| 955 | else | ||
| 952 | scsi_end_request(cmd, -EIO, this_count, 1); | 956 | scsi_end_request(cmd, -EIO, this_count, 1); |
| 957 | return; | ||
| 958 | case ABORTED_COMMAND: | ||
| 959 | if (sshdr.asc == 0x10) { /* DIF */ | ||
| 960 | scsi_end_request(cmd, -EIO, this_count, 0); | ||
| 953 | return; | 961 | return; |
| 954 | } | 962 | } |
| 955 | break; | 963 | break; |
| @@ -1072,6 +1080,26 @@ int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask) | |||
| 1072 | goto err_exit; | 1080 | goto err_exit; |
| 1073 | } | 1081 | } |
| 1074 | 1082 | ||
| 1083 | if (blk_integrity_rq(cmd->request)) { | ||
| 1084 | struct scsi_data_buffer *prot_sdb = cmd->prot_sdb; | ||
| 1085 | int ivecs, count; | ||
| 1086 | |||
| 1087 | BUG_ON(prot_sdb == NULL); | ||
| 1088 | ivecs = blk_rq_count_integrity_sg(cmd->request); | ||
| 1089 | |||
| 1090 | if (scsi_alloc_sgtable(prot_sdb, ivecs, gfp_mask)) { | ||
| 1091 | error = BLKPREP_DEFER; | ||
| 1092 | goto err_exit; | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | count = blk_rq_map_integrity_sg(cmd->request, | ||
| 1096 | prot_sdb->table.sgl); | ||
| 1097 | BUG_ON(unlikely(count > ivecs)); | ||
| 1098 | |||
| 1099 | cmd->prot_sdb = prot_sdb; | ||
| 1100 | cmd->prot_sdb->table.nents = count; | ||
| 1101 | } | ||
| 1102 | |||
| 1075 | return BLKPREP_OK ; | 1103 | return BLKPREP_OK ; |
| 1076 | 1104 | ||
| 1077 | err_exit: | 1105 | err_exit: |
| @@ -1367,7 +1395,7 @@ static void scsi_kill_request(struct request *req, struct request_queue *q) | |||
| 1367 | 1395 | ||
| 1368 | if (unlikely(cmd == NULL)) { | 1396 | if (unlikely(cmd == NULL)) { |
| 1369 | printk(KERN_CRIT "impossible request in %s.\n", | 1397 | printk(KERN_CRIT "impossible request in %s.\n", |
| 1370 | __FUNCTION__); | 1398 | __func__); |
| 1371 | BUG(); | 1399 | BUG(); |
| 1372 | } | 1400 | } |
| 1373 | 1401 | ||
| @@ -1491,12 +1519,27 @@ static void scsi_request_fn(struct request_queue *q) | |||
| 1491 | printk(KERN_CRIT "impossible request in %s.\n" | 1519 | printk(KERN_CRIT "impossible request in %s.\n" |
| 1492 | "please mail a stack trace to " | 1520 | "please mail a stack trace to " |
| 1493 | "linux-scsi@vger.kernel.org\n", | 1521 | "linux-scsi@vger.kernel.org\n", |
| 1494 | __FUNCTION__); | 1522 | __func__); |
| 1495 | blk_dump_rq_flags(req, "foo"); | 1523 | blk_dump_rq_flags(req, "foo"); |
| 1496 | BUG(); | 1524 | BUG(); |
| 1497 | } | 1525 | } |
| 1498 | spin_lock(shost->host_lock); | 1526 | spin_lock(shost->host_lock); |
| 1499 | 1527 | ||
| 1528 | /* | ||
| 1529 | * We hit this when the driver is using a host wide | ||
| 1530 | * tag map. For device level tag maps the queue_depth check | ||
| 1531 | * in the device ready fn would prevent us from trying | ||
| 1532 | * to allocate a tag. Since the map is a shared host resource | ||
| 1533 | * we add the dev to the starved list so it eventually gets | ||
| 1534 | * a run when a tag is freed. | ||
| 1535 | */ | ||
| 1536 | if (blk_queue_tagged(q) && !blk_rq_tagged(req)) { | ||
| 1537 | if (list_empty(&sdev->starved_entry)) | ||
| 1538 | list_add_tail(&sdev->starved_entry, | ||
| 1539 | &shost->starved_list); | ||
| 1540 | goto not_ready; | ||
| 1541 | } | ||
| 1542 | |||
| 1500 | if (!scsi_host_queue_ready(q, shost, sdev)) | 1543 | if (!scsi_host_queue_ready(q, shost, sdev)) |
| 1501 | goto not_ready; | 1544 | goto not_ready; |
| 1502 | if (scsi_target(sdev)->single_lun) { | 1545 | if (scsi_target(sdev)->single_lun) { |
| @@ -2486,7 +2529,7 @@ void *scsi_kmap_atomic_sg(struct scatterlist *sgl, int sg_count, | |||
| 2486 | if (unlikely(i == sg_count)) { | 2529 | if (unlikely(i == sg_count)) { |
| 2487 | printk(KERN_ERR "%s: Bytes in sg: %zu, requested offset %zu, " | 2530 | printk(KERN_ERR "%s: Bytes in sg: %zu, requested offset %zu, " |
| 2488 | "elements %d\n", | 2531 | "elements %d\n", |
| 2489 | __FUNCTION__, sg_len, *offset, sg_count); | 2532 | __func__, sg_len, *offset, sg_count); |
| 2490 | WARN_ON(1); | 2533 | WARN_ON(1); |
| 2491 | return NULL; | 2534 | return NULL; |
| 2492 | } | 2535 | } |
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c index 370c78cc1cb5..ae7ed9a22662 100644 --- a/drivers/scsi/scsi_netlink.c +++ b/drivers/scsi/scsi_netlink.c | |||
| @@ -55,7 +55,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb) | |||
| 55 | if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*hdr))) || | 55 | if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*hdr))) || |
| 56 | (skb->len < nlh->nlmsg_len)) { | 56 | (skb->len < nlh->nlmsg_len)) { |
| 57 | printk(KERN_WARNING "%s: discarding partial skb\n", | 57 | printk(KERN_WARNING "%s: discarding partial skb\n", |
| 58 | __FUNCTION__); | 58 | __func__); |
| 59 | return; | 59 | return; |
| 60 | } | 60 | } |
| 61 | 61 | ||
| @@ -82,7 +82,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb) | |||
| 82 | 82 | ||
| 83 | if (nlh->nlmsg_len < (sizeof(*nlh) + hdr->msglen)) { | 83 | if (nlh->nlmsg_len < (sizeof(*nlh) + hdr->msglen)) { |
| 84 | printk(KERN_WARNING "%s: discarding partial message\n", | 84 | printk(KERN_WARNING "%s: discarding partial message\n", |
| 85 | __FUNCTION__); | 85 | __func__); |
| 86 | return; | 86 | return; |
| 87 | } | 87 | } |
| 88 | 88 | ||
| @@ -139,7 +139,7 @@ scsi_netlink_init(void) | |||
| 139 | error = netlink_register_notifier(&scsi_netlink_notifier); | 139 | error = netlink_register_notifier(&scsi_netlink_notifier); |
| 140 | if (error) { | 140 | if (error) { |
| 141 | printk(KERN_ERR "%s: register of event handler failed - %d\n", | 141 | printk(KERN_ERR "%s: register of event handler failed - %d\n", |
| 142 | __FUNCTION__, error); | 142 | __func__, error); |
| 143 | return; | 143 | return; |
| 144 | } | 144 | } |
| 145 | 145 | ||
| @@ -148,7 +148,7 @@ scsi_netlink_init(void) | |||
| 148 | THIS_MODULE); | 148 | THIS_MODULE); |
| 149 | if (!scsi_nl_sock) { | 149 | if (!scsi_nl_sock) { |
| 150 | printk(KERN_ERR "%s: register of recieve handler failed\n", | 150 | printk(KERN_ERR "%s: register of recieve handler failed\n", |
| 151 | __FUNCTION__); | 151 | __func__); |
| 152 | netlink_unregister_notifier(&scsi_netlink_notifier); | 152 | netlink_unregister_notifier(&scsi_netlink_notifier); |
| 153 | } | 153 | } |
| 154 | 154 | ||
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index b33e72516ef8..79f0f7511204 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h | |||
| @@ -77,6 +77,7 @@ extern void scsi_exit_queue(void); | |||
| 77 | struct request_queue; | 77 | struct request_queue; |
| 78 | struct request; | 78 | struct request; |
| 79 | extern int scsi_prep_fn(struct request_queue *, struct request *); | 79 | extern int scsi_prep_fn(struct request_queue *, struct request *); |
| 80 | extern struct kmem_cache *scsi_sdb_cache; | ||
| 80 | 81 | ||
| 81 | /* scsi_proc.c */ | 82 | /* scsi_proc.c */ |
| 82 | #ifdef CONFIG_SCSI_PROC_FS | 83 | #ifdef CONFIG_SCSI_PROC_FS |
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index e4a0d2f9b357..c6a904a45bf9 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c | |||
| @@ -114,7 +114,7 @@ void scsi_proc_hostdir_add(struct scsi_host_template *sht) | |||
| 114 | sht->proc_dir = proc_mkdir(sht->proc_name, proc_scsi); | 114 | sht->proc_dir = proc_mkdir(sht->proc_name, proc_scsi); |
| 115 | if (!sht->proc_dir) | 115 | if (!sht->proc_dir) |
| 116 | printk(KERN_ERR "%s: proc_mkdir failed for %s\n", | 116 | printk(KERN_ERR "%s: proc_mkdir failed for %s\n", |
| 117 | __FUNCTION__, sht->proc_name); | 117 | __func__, sht->proc_name); |
| 118 | else | 118 | else |
| 119 | sht->proc_dir->owner = sht->module; | 119 | sht->proc_dir->owner = sht->module; |
| 120 | } | 120 | } |
| @@ -157,7 +157,7 @@ void scsi_proc_host_add(struct Scsi_Host *shost) | |||
| 157 | sht->proc_dir, proc_scsi_read, shost); | 157 | sht->proc_dir, proc_scsi_read, shost); |
| 158 | if (!p) { | 158 | if (!p) { |
| 159 | printk(KERN_ERR "%s: Failed to register host %d in" | 159 | printk(KERN_ERR "%s: Failed to register host %d in" |
| 160 | "%s\n", __FUNCTION__, shost->host_no, | 160 | "%s\n", __func__, shost->host_no, |
| 161 | sht->proc_name); | 161 | sht->proc_name); |
| 162 | return; | 162 | return; |
| 163 | } | 163 | } |
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 196fe3af0d5e..84b4879cff11 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c | |||
| @@ -318,7 +318,7 @@ out_device_destroy: | |||
| 318 | put_device(&sdev->sdev_gendev); | 318 | put_device(&sdev->sdev_gendev); |
| 319 | out: | 319 | out: |
| 320 | if (display_failure_msg) | 320 | if (display_failure_msg) |
| 321 | printk(ALLOC_FAILURE_MSG, __FUNCTION__); | 321 | printk(ALLOC_FAILURE_MSG, __func__); |
| 322 | return NULL; | 322 | return NULL; |
| 323 | } | 323 | } |
| 324 | 324 | ||
| @@ -404,7 +404,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
| 404 | 404 | ||
| 405 | starget = kzalloc(size, GFP_KERNEL); | 405 | starget = kzalloc(size, GFP_KERNEL); |
| 406 | if (!starget) { | 406 | if (!starget) { |
| 407 | printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__); | 407 | printk(KERN_ERR "%s: allocation failure\n", __func__); |
| 408 | return NULL; | 408 | return NULL; |
| 409 | } | 409 | } |
| 410 | dev = &starget->dev; | 410 | dev = &starget->dev; |
| @@ -1337,7 +1337,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, | |||
| 1337 | lun_data = kmalloc(length, GFP_ATOMIC | | 1337 | lun_data = kmalloc(length, GFP_ATOMIC | |
| 1338 | (sdev->host->unchecked_isa_dma ? __GFP_DMA : 0)); | 1338 | (sdev->host->unchecked_isa_dma ? __GFP_DMA : 0)); |
| 1339 | if (!lun_data) { | 1339 | if (!lun_data) { |
| 1340 | printk(ALLOC_FAILURE_MSG, __FUNCTION__); | 1340 | printk(ALLOC_FAILURE_MSG, __func__); |
| 1341 | goto out; | 1341 | goto out; |
| 1342 | } | 1342 | } |
| 1343 | 1343 | ||
| @@ -1649,7 +1649,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, | |||
| 1649 | { | 1649 | { |
| 1650 | SCSI_LOG_SCAN_BUS(3, shost_printk (KERN_INFO, shost, | 1650 | SCSI_LOG_SCAN_BUS(3, shost_printk (KERN_INFO, shost, |
| 1651 | "%s: <%u:%u:%u>\n", | 1651 | "%s: <%u:%u:%u>\n", |
| 1652 | __FUNCTION__, channel, id, lun)); | 1652 | __func__, channel, id, lun)); |
| 1653 | 1653 | ||
| 1654 | if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) || | 1654 | if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) || |
| 1655 | ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) || | 1655 | ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) || |
| @@ -1703,7 +1703,7 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost) | |||
| 1703 | return NULL; | 1703 | return NULL; |
| 1704 | 1704 | ||
| 1705 | if (shost->async_scan) { | 1705 | if (shost->async_scan) { |
| 1706 | printk("%s called twice for host %d", __FUNCTION__, | 1706 | printk("%s called twice for host %d", __func__, |
| 1707 | shost->host_no); | 1707 | shost->host_no); |
| 1708 | dump_stack(); | 1708 | dump_stack(); |
| 1709 | return NULL; | 1709 | return NULL; |
| @@ -1757,9 +1757,10 @@ static void scsi_finish_async_scan(struct async_scan_data *data) | |||
| 1757 | mutex_lock(&shost->scan_mutex); | 1757 | mutex_lock(&shost->scan_mutex); |
| 1758 | 1758 | ||
| 1759 | if (!shost->async_scan) { | 1759 | if (!shost->async_scan) { |
| 1760 | printk("%s called twice for host %d", __FUNCTION__, | 1760 | printk("%s called twice for host %d", __func__, |
| 1761 | shost->host_no); | 1761 | shost->host_no); |
| 1762 | dump_stack(); | 1762 | dump_stack(); |
| 1763 | mutex_unlock(&shost->scan_mutex); | ||
| 1763 | return; | 1764 | return; |
| 1764 | } | 1765 | } |
| 1765 | 1766 | ||
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index b6e561059779..ab3c71869be5 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c | |||
| @@ -249,6 +249,8 @@ shost_rd_attr(cmd_per_lun, "%hd\n"); | |||
| 249 | shost_rd_attr(can_queue, "%hd\n"); | 249 | shost_rd_attr(can_queue, "%hd\n"); |
| 250 | shost_rd_attr(sg_tablesize, "%hu\n"); | 250 | shost_rd_attr(sg_tablesize, "%hu\n"); |
| 251 | shost_rd_attr(unchecked_isa_dma, "%d\n"); | 251 | shost_rd_attr(unchecked_isa_dma, "%d\n"); |
| 252 | shost_rd_attr(prot_capabilities, "%u\n"); | ||
| 253 | shost_rd_attr(prot_guard_type, "%hd\n"); | ||
| 252 | shost_rd_attr2(proc_name, hostt->proc_name, "%s\n"); | 254 | shost_rd_attr2(proc_name, hostt->proc_name, "%s\n"); |
| 253 | 255 | ||
| 254 | static struct attribute *scsi_sysfs_shost_attrs[] = { | 256 | static struct attribute *scsi_sysfs_shost_attrs[] = { |
| @@ -263,6 +265,8 @@ static struct attribute *scsi_sysfs_shost_attrs[] = { | |||
| 263 | &dev_attr_hstate.attr, | 265 | &dev_attr_hstate.attr, |
| 264 | &dev_attr_supported_mode.attr, | 266 | &dev_attr_supported_mode.attr, |
| 265 | &dev_attr_active_mode.attr, | 267 | &dev_attr_active_mode.attr, |
| 268 | &dev_attr_prot_capabilities.attr, | ||
| 269 | &dev_attr_prot_guard_type.attr, | ||
| 266 | NULL | 270 | NULL |
| 267 | }; | 271 | }; |
| 268 | 272 | ||
diff --git a/drivers/scsi/scsi_tgt_priv.h b/drivers/scsi/scsi_tgt_priv.h index cb92888948f9..fe4c62177f78 100644 --- a/drivers/scsi/scsi_tgt_priv.h +++ b/drivers/scsi/scsi_tgt_priv.h | |||
| @@ -6,7 +6,7 @@ struct task_struct; | |||
| 6 | /* tmp - will replace with SCSI logging stuff */ | 6 | /* tmp - will replace with SCSI logging stuff */ |
| 7 | #define eprintk(fmt, args...) \ | 7 | #define eprintk(fmt, args...) \ |
| 8 | do { \ | 8 | do { \ |
| 9 | printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args); \ | 9 | printk("%s(%d) " fmt, __func__, __LINE__, ##args); \ |
| 10 | } while (0) | 10 | } while (0) |
| 11 | 11 | ||
| 12 | #define dprintk(fmt, args...) | 12 | #define dprintk(fmt, args...) |
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index a272b9a2c869..56823fd1fb84 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c | |||
| @@ -571,7 +571,7 @@ send_fail: | |||
| 571 | name = get_fc_host_event_code_name(event_code); | 571 | name = get_fc_host_event_code_name(event_code); |
| 572 | printk(KERN_WARNING | 572 | printk(KERN_WARNING |
| 573 | "%s: Dropped Event : host %d %s data 0x%08x - err %d\n", | 573 | "%s: Dropped Event : host %d %s data 0x%08x - err %d\n", |
| 574 | __FUNCTION__, shost->host_no, | 574 | __func__, shost->host_no, |
| 575 | (name) ? name : "<unknown>", event_data, err); | 575 | (name) ? name : "<unknown>", event_data, err); |
| 576 | return; | 576 | return; |
| 577 | } | 577 | } |
| @@ -644,7 +644,7 @@ send_vendor_fail_skb: | |||
| 644 | send_vendor_fail: | 644 | send_vendor_fail: |
| 645 | printk(KERN_WARNING | 645 | printk(KERN_WARNING |
| 646 | "%s: Dropped Event : host %d vendor_unique - err %d\n", | 646 | "%s: Dropped Event : host %d vendor_unique - err %d\n", |
| 647 | __FUNCTION__, shost->host_no, err); | 647 | __func__, shost->host_no, err); |
| 648 | return; | 648 | return; |
| 649 | } | 649 | } |
| 650 | EXPORT_SYMBOL(fc_host_post_vendor_event); | 650 | EXPORT_SYMBOL(fc_host_post_vendor_event); |
| @@ -2464,7 +2464,7 @@ fc_rport_create(struct Scsi_Host *shost, int channel, | |||
| 2464 | size = (sizeof(struct fc_rport) + fci->f->dd_fcrport_size); | 2464 | size = (sizeof(struct fc_rport) + fci->f->dd_fcrport_size); |
| 2465 | rport = kzalloc(size, GFP_KERNEL); | 2465 | rport = kzalloc(size, GFP_KERNEL); |
| 2466 | if (unlikely(!rport)) { | 2466 | if (unlikely(!rport)) { |
| 2467 | printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__); | 2467 | printk(KERN_ERR "%s: allocation failure\n", __func__); |
| 2468 | return NULL; | 2468 | return NULL; |
| 2469 | } | 2469 | } |
| 2470 | 2470 | ||
| @@ -3137,7 +3137,7 @@ fc_vport_create(struct Scsi_Host *shost, int channel, struct device *pdev, | |||
| 3137 | size = (sizeof(struct fc_vport) + fci->f->dd_fcvport_size); | 3137 | size = (sizeof(struct fc_vport) + fci->f->dd_fcvport_size); |
| 3138 | vport = kzalloc(size, GFP_KERNEL); | 3138 | vport = kzalloc(size, GFP_KERNEL); |
| 3139 | if (unlikely(!vport)) { | 3139 | if (unlikely(!vport)) { |
| 3140 | printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__); | 3140 | printk(KERN_ERR "%s: allocation failure\n", __func__); |
| 3141 | return -ENOMEM; | 3141 | return -ENOMEM; |
| 3142 | } | 3142 | } |
| 3143 | 3143 | ||
| @@ -3201,7 +3201,7 @@ fc_vport_create(struct Scsi_Host *shost, int channel, struct device *pdev, | |||
| 3201 | printk(KERN_ERR | 3201 | printk(KERN_ERR |
| 3202 | "%s: Cannot create vport symlinks for " | 3202 | "%s: Cannot create vport symlinks for " |
| 3203 | "%s, err=%d\n", | 3203 | "%s, err=%d\n", |
| 3204 | __FUNCTION__, dev->bus_id, error); | 3204 | __func__, dev->bus_id, error); |
| 3205 | } | 3205 | } |
| 3206 | spin_lock_irqsave(shost->host_lock, flags); | 3206 | spin_lock_irqsave(shost->host_lock, flags); |
| 3207 | vport->flags &= ~FC_VPORT_CREATING; | 3207 | vport->flags &= ~FC_VPORT_CREATING; |
| @@ -3314,7 +3314,7 @@ fc_vport_sched_delete(struct work_struct *work) | |||
| 3314 | if (stat) | 3314 | if (stat) |
| 3315 | dev_printk(KERN_ERR, vport->dev.parent, | 3315 | dev_printk(KERN_ERR, vport->dev.parent, |
| 3316 | "%s: %s could not be deleted created via " | 3316 | "%s: %s could not be deleted created via " |
| 3317 | "shost%d channel %d - error %d\n", __FUNCTION__, | 3317 | "shost%d channel %d - error %d\n", __func__, |
| 3318 | vport->dev.bus_id, vport->shost->host_no, | 3318 | vport->dev.bus_id, vport->shost->host_no, |
| 3319 | vport->channel, stat); | 3319 | vport->channel, stat); |
| 3320 | } | 3320 | } |
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index f4461d35ffb9..366609386be1 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c | |||
| @@ -779,7 +779,7 @@ static void sas_port_create_link(struct sas_port *port, | |||
| 779 | return; | 779 | return; |
| 780 | err: | 780 | err: |
| 781 | printk(KERN_ERR "%s: Cannot create port links, err=%d\n", | 781 | printk(KERN_ERR "%s: Cannot create port links, err=%d\n", |
| 782 | __FUNCTION__, res); | 782 | __func__, res); |
| 783 | } | 783 | } |
| 784 | 784 | ||
| 785 | static void sas_port_delete_link(struct sas_port *port, | 785 | static void sas_port_delete_link(struct sas_port *port, |
| @@ -1029,7 +1029,7 @@ void sas_port_mark_backlink(struct sas_port *port) | |||
| 1029 | return; | 1029 | return; |
| 1030 | err: | 1030 | err: |
| 1031 | printk(KERN_ERR "%s: Cannot create port backlink, err=%d\n", | 1031 | printk(KERN_ERR "%s: Cannot create port backlink, err=%d\n", |
| 1032 | __FUNCTION__, res); | 1032 | __func__, res); |
| 1033 | 1033 | ||
| 1034 | } | 1034 | } |
| 1035 | EXPORT_SYMBOL(sas_port_mark_backlink); | 1035 | EXPORT_SYMBOL(sas_port_mark_backlink); |
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 0c63947d8a9d..e5e7d7856454 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
| @@ -99,8 +99,7 @@ static void scsi_disk_release(struct device *cdev); | |||
| 99 | static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *); | 99 | static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *); |
| 100 | static void sd_print_result(struct scsi_disk *, int); | 100 | static void sd_print_result(struct scsi_disk *, int); |
| 101 | 101 | ||
| 102 | static DEFINE_IDR(sd_index_idr); | 102 | static DEFINE_IDA(sd_index_ida); |
| 103 | static DEFINE_SPINLOCK(sd_index_lock); | ||
| 104 | 103 | ||
| 105 | /* This semaphore is used to mediate the 0->1 reference get in the | 104 | /* This semaphore is used to mediate the 0->1 reference get in the |
| 106 | * face of object destruction (i.e. we can't allow a get on an | 105 | * face of object destruction (i.e. we can't allow a get on an |
| @@ -234,6 +233,24 @@ sd_show_allow_restart(struct device *dev, struct device_attribute *attr, | |||
| 234 | return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart); | 233 | return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart); |
| 235 | } | 234 | } |
| 236 | 235 | ||
| 236 | static ssize_t | ||
| 237 | sd_show_protection_type(struct device *dev, struct device_attribute *attr, | ||
| 238 | char *buf) | ||
| 239 | { | ||
| 240 | struct scsi_disk *sdkp = to_scsi_disk(dev); | ||
| 241 | |||
| 242 | return snprintf(buf, 20, "%u\n", sdkp->protection_type); | ||
| 243 | } | ||
| 244 | |||
| 245 | static ssize_t | ||
| 246 | sd_show_app_tag_own(struct device *dev, struct device_attribute *attr, | ||
| 247 | char *buf) | ||
| 248 | { | ||
| 249 | struct scsi_disk *sdkp = to_scsi_disk(dev); | ||
| 250 | |||
| 251 | return snprintf(buf, 20, "%u\n", sdkp->ATO); | ||
| 252 | } | ||
| 253 | |||
| 237 | static struct device_attribute sd_disk_attrs[] = { | 254 | static struct device_attribute sd_disk_attrs[] = { |
| 238 | __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type, | 255 | __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type, |
| 239 | sd_store_cache_type), | 256 | sd_store_cache_type), |
| @@ -242,6 +259,8 @@ static struct device_attribute sd_disk_attrs[] = { | |||
| 242 | sd_store_allow_restart), | 259 | sd_store_allow_restart), |
| 243 | __ATTR(manage_start_stop, S_IRUGO|S_IWUSR, sd_show_manage_start_stop, | 260 | __ATTR(manage_start_stop, S_IRUGO|S_IWUSR, sd_show_manage_start_stop, |
| 244 | sd_store_manage_start_stop), | 261 | sd_store_manage_start_stop), |
| 262 | __ATTR(protection_type, S_IRUGO, sd_show_protection_type, NULL), | ||
| 263 | __ATTR(app_tag_own, S_IRUGO, sd_show_app_tag_own, NULL), | ||
| 245 | __ATTR_NULL, | 264 | __ATTR_NULL, |
| 246 | }; | 265 | }; |
| 247 | 266 | ||
| @@ -354,7 +373,9 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) | |||
| 354 | struct scsi_cmnd *SCpnt; | 373 | struct scsi_cmnd *SCpnt; |
| 355 | struct scsi_device *sdp = q->queuedata; | 374 | struct scsi_device *sdp = q->queuedata; |
| 356 | struct gendisk *disk = rq->rq_disk; | 375 | struct gendisk *disk = rq->rq_disk; |
| 376 | struct scsi_disk *sdkp; | ||
| 357 | sector_t block = rq->sector; | 377 | sector_t block = rq->sector; |
| 378 | sector_t threshold; | ||
| 358 | unsigned int this_count = rq->nr_sectors; | 379 | unsigned int this_count = rq->nr_sectors; |
| 359 | unsigned int timeout = sdp->timeout; | 380 | unsigned int timeout = sdp->timeout; |
| 360 | int ret; | 381 | int ret; |
| @@ -370,6 +391,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) | |||
| 370 | if (ret != BLKPREP_OK) | 391 | if (ret != BLKPREP_OK) |
| 371 | goto out; | 392 | goto out; |
| 372 | SCpnt = rq->special; | 393 | SCpnt = rq->special; |
| 394 | sdkp = scsi_disk(disk); | ||
| 373 | 395 | ||
| 374 | /* from here on until we're complete, any goto out | 396 | /* from here on until we're complete, any goto out |
| 375 | * is used for a killable error condition */ | 397 | * is used for a killable error condition */ |
| @@ -401,13 +423,21 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) | |||
| 401 | } | 423 | } |
| 402 | 424 | ||
| 403 | /* | 425 | /* |
| 404 | * Some devices (some sdcards for one) don't like it if the | 426 | * Some SD card readers can't handle multi-sector accesses which touch |
| 405 | * last sector gets read in a larger then 1 sector read. | 427 | * the last one or two hardware sectors. Split accesses as needed. |
| 406 | */ | 428 | */ |
| 407 | if (unlikely(sdp->last_sector_bug && | 429 | threshold = get_capacity(disk) - SD_LAST_BUGGY_SECTORS * |
| 408 | rq->nr_sectors > sdp->sector_size / 512 && | 430 | (sdp->sector_size / 512); |
| 409 | block + this_count == get_capacity(disk))) | 431 | |
| 410 | this_count -= sdp->sector_size / 512; | 432 | if (unlikely(sdp->last_sector_bug && block + this_count > threshold)) { |
| 433 | if (block < threshold) { | ||
| 434 | /* Access up to the threshold but not beyond */ | ||
| 435 | this_count = threshold - block; | ||
| 436 | } else { | ||
| 437 | /* Access only a single hardware sector */ | ||
| 438 | this_count = sdp->sector_size / 512; | ||
| 439 | } | ||
| 440 | } | ||
| 411 | 441 | ||
| 412 | SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n", | 442 | SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n", |
| 413 | (unsigned long long)block)); | 443 | (unsigned long long)block)); |
| @@ -459,6 +489,11 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) | |||
| 459 | } | 489 | } |
| 460 | SCpnt->cmnd[0] = WRITE_6; | 490 | SCpnt->cmnd[0] = WRITE_6; |
| 461 | SCpnt->sc_data_direction = DMA_TO_DEVICE; | 491 | SCpnt->sc_data_direction = DMA_TO_DEVICE; |
| 492 | |||
| 493 | if (blk_integrity_rq(rq) && | ||
| 494 | sd_dif_prepare(rq, block, sdp->sector_size) == -EIO) | ||
| 495 | goto out; | ||
| 496 | |||
| 462 | } else if (rq_data_dir(rq) == READ) { | 497 | } else if (rq_data_dir(rq) == READ) { |
| 463 | SCpnt->cmnd[0] = READ_6; | 498 | SCpnt->cmnd[0] = READ_6; |
| 464 | SCpnt->sc_data_direction = DMA_FROM_DEVICE; | 499 | SCpnt->sc_data_direction = DMA_FROM_DEVICE; |
| @@ -473,8 +508,12 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) | |||
| 473 | "writing" : "reading", this_count, | 508 | "writing" : "reading", this_count, |
| 474 | rq->nr_sectors)); | 509 | rq->nr_sectors)); |
| 475 | 510 | ||
| 476 | SCpnt->cmnd[1] = 0; | 511 | /* Set RDPROTECT/WRPROTECT if disk is formatted with DIF */ |
| 477 | 512 | if (scsi_host_dif_capable(sdp->host, sdkp->protection_type)) | |
| 513 | SCpnt->cmnd[1] = 1 << 5; | ||
| 514 | else | ||
| 515 | SCpnt->cmnd[1] = 0; | ||
| 516 | |||
| 478 | if (block > 0xffffffff) { | 517 | if (block > 0xffffffff) { |
| 479 | SCpnt->cmnd[0] += READ_16 - READ_6; | 518 | SCpnt->cmnd[0] += READ_16 - READ_6; |
| 480 | SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0; | 519 | SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0; |
| @@ -492,6 +531,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) | |||
| 492 | SCpnt->cmnd[13] = (unsigned char) this_count & 0xff; | 531 | SCpnt->cmnd[13] = (unsigned char) this_count & 0xff; |
| 493 | SCpnt->cmnd[14] = SCpnt->cmnd[15] = 0; | 532 | SCpnt->cmnd[14] = SCpnt->cmnd[15] = 0; |
| 494 | } else if ((this_count > 0xff) || (block > 0x1fffff) || | 533 | } else if ((this_count > 0xff) || (block > 0x1fffff) || |
| 534 | scsi_device_protection(SCpnt->device) || | ||
| 495 | SCpnt->device->use_10_for_rw) { | 535 | SCpnt->device->use_10_for_rw) { |
| 496 | if (this_count > 0xffff) | 536 | if (this_count > 0xffff) |
| 497 | this_count = 0xffff; | 537 | this_count = 0xffff; |
| @@ -526,6 +566,10 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) | |||
| 526 | } | 566 | } |
| 527 | SCpnt->sdb.length = this_count * sdp->sector_size; | 567 | SCpnt->sdb.length = this_count * sdp->sector_size; |
| 528 | 568 | ||
| 569 | /* If DIF or DIX is enabled, tell HBA how to handle request */ | ||
| 570 | if (sdkp->protection_type || scsi_prot_sg_count(SCpnt)) | ||
| 571 | sd_dif_op(SCpnt, sdkp->protection_type, scsi_prot_sg_count(SCpnt)); | ||
| 572 | |||
| 529 | /* | 573 | /* |
| 530 | * We shouldn't disconnect in the middle of a sector, so with a dumb | 574 | * We shouldn't disconnect in the middle of a sector, so with a dumb |
| 531 | * host adapter, it's safe to assume that we can at least transfer | 575 | * host adapter, it's safe to assume that we can at least transfer |
| @@ -920,6 +964,48 @@ static struct block_device_operations sd_fops = { | |||
| 920 | .revalidate_disk = sd_revalidate_disk, | 964 | .revalidate_disk = sd_revalidate_disk, |
| 921 | }; | 965 | }; |
| 922 | 966 | ||
| 967 | static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd) | ||
| 968 | { | ||
| 969 | u64 start_lba = scmd->request->sector; | ||
| 970 | u64 end_lba = scmd->request->sector + (scsi_bufflen(scmd) / 512); | ||
| 971 | u64 bad_lba; | ||
| 972 | int info_valid; | ||
| 973 | |||
| 974 | if (!blk_fs_request(scmd->request)) | ||
| 975 | return 0; | ||
| 976 | |||
| 977 | info_valid = scsi_get_sense_info_fld(scmd->sense_buffer, | ||
| 978 | SCSI_SENSE_BUFFERSIZE, | ||
| 979 | &bad_lba); | ||
| 980 | if (!info_valid) | ||
| 981 | return 0; | ||
| 982 | |||
| 983 | if (scsi_bufflen(scmd) <= scmd->device->sector_size) | ||
| 984 | return 0; | ||
| 985 | |||
| 986 | if (scmd->device->sector_size < 512) { | ||
| 987 | /* only legitimate sector_size here is 256 */ | ||
| 988 | start_lba <<= 1; | ||
| 989 | end_lba <<= 1; | ||
| 990 | } else { | ||
| 991 | /* be careful ... don't want any overflows */ | ||
| 992 | u64 factor = scmd->device->sector_size / 512; | ||
| 993 | do_div(start_lba, factor); | ||
| 994 | do_div(end_lba, factor); | ||
| 995 | } | ||
| 996 | |||
| 997 | /* The bad lba was reported incorrectly, we have no idea where | ||
| 998 | * the error is. | ||
| 999 | */ | ||
| 1000 | if (bad_lba < start_lba || bad_lba >= end_lba) | ||
| 1001 | return 0; | ||
| 1002 | |||
| 1003 | /* This computation should always be done in terms of | ||
| 1004 | * the resolution of the device's medium. | ||
| 1005 | */ | ||
| 1006 | return (bad_lba - start_lba) * scmd->device->sector_size; | ||
| 1007 | } | ||
| 1008 | |||
| 923 | /** | 1009 | /** |
| 924 | * sd_done - bottom half handler: called when the lower level | 1010 | * sd_done - bottom half handler: called when the lower level |
| 925 | * driver has completed (successfully or otherwise) a scsi command. | 1011 | * driver has completed (successfully or otherwise) a scsi command. |
| @@ -930,15 +1016,10 @@ static struct block_device_operations sd_fops = { | |||
| 930 | static int sd_done(struct scsi_cmnd *SCpnt) | 1016 | static int sd_done(struct scsi_cmnd *SCpnt) |
| 931 | { | 1017 | { |
| 932 | int result = SCpnt->result; | 1018 | int result = SCpnt->result; |
| 933 | unsigned int xfer_size = scsi_bufflen(SCpnt); | 1019 | unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt); |
| 934 | unsigned int good_bytes = result ? 0 : xfer_size; | ||
| 935 | u64 start_lba = SCpnt->request->sector; | ||
| 936 | u64 end_lba = SCpnt->request->sector + (xfer_size / 512); | ||
| 937 | u64 bad_lba; | ||
| 938 | struct scsi_sense_hdr sshdr; | 1020 | struct scsi_sense_hdr sshdr; |
| 939 | int sense_valid = 0; | 1021 | int sense_valid = 0; |
| 940 | int sense_deferred = 0; | 1022 | int sense_deferred = 0; |
| 941 | int info_valid; | ||
| 942 | 1023 | ||
| 943 | if (result) { | 1024 | if (result) { |
| 944 | sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr); | 1025 | sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr); |
| @@ -963,36 +1044,7 @@ static int sd_done(struct scsi_cmnd *SCpnt) | |||
| 963 | switch (sshdr.sense_key) { | 1044 | switch (sshdr.sense_key) { |
| 964 | case HARDWARE_ERROR: | 1045 | case HARDWARE_ERROR: |
| 965 | case MEDIUM_ERROR: | 1046 | case MEDIUM_ERROR: |
| 966 | if (!blk_fs_request(SCpnt->request)) | 1047 | good_bytes = sd_completed_bytes(SCpnt); |
| 967 | goto out; | ||
| 968 | info_valid = scsi_get_sense_info_fld(SCpnt->sense_buffer, | ||
| 969 | SCSI_SENSE_BUFFERSIZE, | ||
| 970 | &bad_lba); | ||
| 971 | if (!info_valid) | ||
| 972 | goto out; | ||
| 973 | if (xfer_size <= SCpnt->device->sector_size) | ||
| 974 | goto out; | ||
| 975 | if (SCpnt->device->sector_size < 512) { | ||
| 976 | /* only legitimate sector_size here is 256 */ | ||
| 977 | start_lba <<= 1; | ||
| 978 | end_lba <<= 1; | ||
| 979 | } else { | ||
| 980 | /* be careful ... don't want any overflows */ | ||
| 981 | u64 factor = SCpnt->device->sector_size / 512; | ||
| 982 | do_div(start_lba, factor); | ||
| 983 | do_div(end_lba, factor); | ||
| 984 | } | ||
| 985 | |||
| 986 | if (bad_lba < start_lba || bad_lba >= end_lba) | ||
| 987 | /* the bad lba was reported incorrectly, we have | ||
| 988 | * no idea where the error is | ||
| 989 | */ | ||
| 990 | goto out; | ||
| 991 | |||
| 992 | /* This computation should always be done in terms of | ||
| 993 | * the resolution of the device's medium. | ||
| 994 | */ | ||
| 995 | good_bytes = (bad_lba - start_lba)*SCpnt->device->sector_size; | ||
| 996 | break; | 1048 | break; |
| 997 | case RECOVERED_ERROR: | 1049 | case RECOVERED_ERROR: |
| 998 | case NO_SENSE: | 1050 | case NO_SENSE: |
| @@ -1002,10 +1054,23 @@ static int sd_done(struct scsi_cmnd *SCpnt) | |||
| 1002 | scsi_print_sense("sd", SCpnt); | 1054 | scsi_print_sense("sd", SCpnt); |
| 1003 | SCpnt->result = 0; | 1055 | SCpnt->result = 0; |
| 1004 | memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); | 1056 | memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); |
| 1005 | good_bytes = xfer_size; | 1057 | good_bytes = scsi_bufflen(SCpnt); |
| 1058 | break; | ||
| 1059 | case ABORTED_COMMAND: | ||
| 1060 | if (sshdr.asc == 0x10) { /* DIF: Disk detected corruption */ | ||
| 1061 | scsi_print_result(SCpnt); | ||
| 1062 | scsi_print_sense("sd", SCpnt); | ||
| 1063 | good_bytes = sd_completed_bytes(SCpnt); | ||
| 1064 | } | ||
| 1006 | break; | 1065 | break; |
| 1007 | case ILLEGAL_REQUEST: | 1066 | case ILLEGAL_REQUEST: |
| 1008 | if (SCpnt->device->use_10_for_rw && | 1067 | if (sshdr.asc == 0x10) { /* DIX: HBA detected corruption */ |
| 1068 | scsi_print_result(SCpnt); | ||
| 1069 | scsi_print_sense("sd", SCpnt); | ||
| 1070 | good_bytes = sd_completed_bytes(SCpnt); | ||
| 1071 | } | ||
| 1072 | if (!scsi_device_protection(SCpnt->device) && | ||
| 1073 | SCpnt->device->use_10_for_rw && | ||
| 1009 | (SCpnt->cmnd[0] == READ_10 || | 1074 | (SCpnt->cmnd[0] == READ_10 || |
| 1010 | SCpnt->cmnd[0] == WRITE_10)) | 1075 | SCpnt->cmnd[0] == WRITE_10)) |
| 1011 | SCpnt->device->use_10_for_rw = 0; | 1076 | SCpnt->device->use_10_for_rw = 0; |
| @@ -1018,6 +1083,9 @@ static int sd_done(struct scsi_cmnd *SCpnt) | |||
| 1018 | break; | 1083 | break; |
| 1019 | } | 1084 | } |
| 1020 | out: | 1085 | out: |
| 1086 | if (rq_data_dir(SCpnt->request) == READ && scsi_prot_sg_count(SCpnt)) | ||
| 1087 | sd_dif_complete(SCpnt, good_bytes); | ||
| 1088 | |||
| 1021 | return good_bytes; | 1089 | return good_bytes; |
| 1022 | } | 1090 | } |
| 1023 | 1091 | ||
| @@ -1165,6 +1233,49 @@ sd_spinup_disk(struct scsi_disk *sdkp) | |||
| 1165 | } | 1233 | } |
| 1166 | } | 1234 | } |
| 1167 | 1235 | ||
| 1236 | |||
| 1237 | /* | ||
| 1238 | * Determine whether disk supports Data Integrity Field. | ||
| 1239 | */ | ||
| 1240 | void sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer) | ||
| 1241 | { | ||
| 1242 | struct scsi_device *sdp = sdkp->device; | ||
| 1243 | u8 type; | ||
| 1244 | |||
| 1245 | if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) | ||
| 1246 | type = 0; | ||
| 1247 | else | ||
| 1248 | type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */ | ||
| 1249 | |||
| 1250 | switch (type) { | ||
| 1251 | case SD_DIF_TYPE0_PROTECTION: | ||
| 1252 | sdkp->protection_type = 0; | ||
| 1253 | break; | ||
| 1254 | |||
| 1255 | case SD_DIF_TYPE1_PROTECTION: | ||
| 1256 | case SD_DIF_TYPE3_PROTECTION: | ||
| 1257 | sdkp->protection_type = type; | ||
| 1258 | break; | ||
| 1259 | |||
| 1260 | case SD_DIF_TYPE2_PROTECTION: | ||
| 1261 | sd_printk(KERN_ERR, sdkp, "formatted with DIF Type 2 " \ | ||
| 1262 | "protection which is currently unsupported. " \ | ||
| 1263 | "Disabling disk!\n"); | ||
| 1264 | goto disable; | ||
| 1265 | |||
| 1266 | default: | ||
| 1267 | sd_printk(KERN_ERR, sdkp, "formatted with unknown " \ | ||
| 1268 | "protection type %d. Disabling disk!\n", type); | ||
| 1269 | goto disable; | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | return; | ||
| 1273 | |||
| 1274 | disable: | ||
| 1275 | sdkp->protection_type = 0; | ||
| 1276 | sdkp->capacity = 0; | ||
| 1277 | } | ||
| 1278 | |||
| 1168 | /* | 1279 | /* |
| 1169 | * read disk capacity | 1280 | * read disk capacity |
| 1170 | */ | 1281 | */ |
| @@ -1174,7 +1285,8 @@ sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer) | |||
| 1174 | unsigned char cmd[16]; | 1285 | unsigned char cmd[16]; |
| 1175 | int the_result, retries; | 1286 | int the_result, retries; |
| 1176 | int sector_size = 0; | 1287 | int sector_size = 0; |
| 1177 | int longrc = 0; | 1288 | /* Force READ CAPACITY(16) when PROTECT=1 */ |
| 1289 | int longrc = scsi_device_protection(sdkp->device) ? 1 : 0; | ||
| 1178 | struct scsi_sense_hdr sshdr; | 1290 | struct scsi_sense_hdr sshdr; |
| 1179 | int sense_valid = 0; | 1291 | int sense_valid = 0; |
| 1180 | struct scsi_device *sdp = sdkp->device; | 1292 | struct scsi_device *sdp = sdkp->device; |
| @@ -1186,8 +1298,8 @@ repeat: | |||
| 1186 | memset((void *) cmd, 0, 16); | 1298 | memset((void *) cmd, 0, 16); |
| 1187 | cmd[0] = SERVICE_ACTION_IN; | 1299 | cmd[0] = SERVICE_ACTION_IN; |
| 1188 | cmd[1] = SAI_READ_CAPACITY_16; | 1300 | cmd[1] = SAI_READ_CAPACITY_16; |
| 1189 | cmd[13] = 12; | 1301 | cmd[13] = 13; |
| 1190 | memset((void *) buffer, 0, 12); | 1302 | memset((void *) buffer, 0, 13); |
| 1191 | } else { | 1303 | } else { |
| 1192 | cmd[0] = READ_CAPACITY; | 1304 | cmd[0] = READ_CAPACITY; |
| 1193 | memset((void *) &cmd[1], 0, 9); | 1305 | memset((void *) &cmd[1], 0, 9); |
| @@ -1195,7 +1307,7 @@ repeat: | |||
| 1195 | } | 1307 | } |
| 1196 | 1308 | ||
| 1197 | the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE, | 1309 | the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE, |
| 1198 | buffer, longrc ? 12 : 8, &sshdr, | 1310 | buffer, longrc ? 13 : 8, &sshdr, |
| 1199 | SD_TIMEOUT, SD_MAX_RETRIES); | 1311 | SD_TIMEOUT, SD_MAX_RETRIES); |
| 1200 | 1312 | ||
| 1201 | if (media_not_present(sdkp, &sshdr)) | 1313 | if (media_not_present(sdkp, &sshdr)) |
| @@ -1270,6 +1382,8 @@ repeat: | |||
| 1270 | 1382 | ||
| 1271 | sector_size = (buffer[8] << 24) | | 1383 | sector_size = (buffer[8] << 24) | |
| 1272 | (buffer[9] << 16) | (buffer[10] << 8) | buffer[11]; | 1384 | (buffer[9] << 16) | (buffer[10] << 8) | buffer[11]; |
| 1385 | |||
| 1386 | sd_read_protection_type(sdkp, buffer); | ||
| 1273 | } | 1387 | } |
| 1274 | 1388 | ||
| 1275 | /* Some devices return the total number of sectors, not the | 1389 | /* Some devices return the total number of sectors, not the |
| @@ -1531,6 +1645,52 @@ defaults: | |||
| 1531 | sdkp->DPOFUA = 0; | 1645 | sdkp->DPOFUA = 0; |
| 1532 | } | 1646 | } |
| 1533 | 1647 | ||
| 1648 | /* | ||
| 1649 | * The ATO bit indicates whether the DIF application tag is available | ||
| 1650 | * for use by the operating system. | ||
| 1651 | */ | ||
| 1652 | void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer) | ||
| 1653 | { | ||
| 1654 | int res, offset; | ||
| 1655 | struct scsi_device *sdp = sdkp->device; | ||
| 1656 | struct scsi_mode_data data; | ||
| 1657 | struct scsi_sense_hdr sshdr; | ||
| 1658 | |||
| 1659 | if (sdp->type != TYPE_DISK) | ||
| 1660 | return; | ||
| 1661 | |||
| 1662 | if (sdkp->protection_type == 0) | ||
| 1663 | return; | ||
| 1664 | |||
| 1665 | res = scsi_mode_sense(sdp, 1, 0x0a, buffer, 36, SD_TIMEOUT, | ||
| 1666 | SD_MAX_RETRIES, &data, &sshdr); | ||
| 1667 | |||
| 1668 | if (!scsi_status_is_good(res) || !data.header_length || | ||
| 1669 | data.length < 6) { | ||
| 1670 | sd_printk(KERN_WARNING, sdkp, | ||
| 1671 | "getting Control mode page failed, assume no ATO\n"); | ||
| 1672 | |||
| 1673 | if (scsi_sense_valid(&sshdr)) | ||
| 1674 | sd_print_sense_hdr(sdkp, &sshdr); | ||
| 1675 | |||
| 1676 | return; | ||
| 1677 | } | ||
| 1678 | |||
| 1679 | offset = data.header_length + data.block_descriptor_length; | ||
| 1680 | |||
| 1681 | if ((buffer[offset] & 0x3f) != 0x0a) { | ||
| 1682 | sd_printk(KERN_ERR, sdkp, "ATO Got wrong page\n"); | ||
| 1683 | return; | ||
| 1684 | } | ||
| 1685 | |||
| 1686 | if ((buffer[offset + 5] & 0x80) == 0) | ||
| 1687 | return; | ||
| 1688 | |||
| 1689 | sdkp->ATO = 1; | ||
| 1690 | |||
| 1691 | return; | ||
| 1692 | } | ||
| 1693 | |||
| 1534 | /** | 1694 | /** |
| 1535 | * sd_revalidate_disk - called the first time a new disk is seen, | 1695 | * sd_revalidate_disk - called the first time a new disk is seen, |
| 1536 | * performs disk spin up, read_capacity, etc. | 1696 | * performs disk spin up, read_capacity, etc. |
| @@ -1567,6 +1727,7 @@ static int sd_revalidate_disk(struct gendisk *disk) | |||
| 1567 | sdkp->write_prot = 0; | 1727 | sdkp->write_prot = 0; |
| 1568 | sdkp->WCE = 0; | 1728 | sdkp->WCE = 0; |
| 1569 | sdkp->RCD = 0; | 1729 | sdkp->RCD = 0; |
| 1730 | sdkp->ATO = 0; | ||
| 1570 | 1731 | ||
| 1571 | sd_spinup_disk(sdkp); | 1732 | sd_spinup_disk(sdkp); |
| 1572 | 1733 | ||
| @@ -1578,6 +1739,7 @@ static int sd_revalidate_disk(struct gendisk *disk) | |||
| 1578 | sd_read_capacity(sdkp, buffer); | 1739 | sd_read_capacity(sdkp, buffer); |
| 1579 | sd_read_write_protect_flag(sdkp, buffer); | 1740 | sd_read_write_protect_flag(sdkp, buffer); |
| 1580 | sd_read_cache_type(sdkp, buffer); | 1741 | sd_read_cache_type(sdkp, buffer); |
| 1742 | sd_read_app_tag_own(sdkp, buffer); | ||
| 1581 | } | 1743 | } |
| 1582 | 1744 | ||
| 1583 | /* | 1745 | /* |
| @@ -1643,18 +1805,20 @@ static int sd_probe(struct device *dev) | |||
| 1643 | if (!gd) | 1805 | if (!gd) |
| 1644 | goto out_free; | 1806 | goto out_free; |
| 1645 | 1807 | ||
| 1646 | if (!idr_pre_get(&sd_index_idr, GFP_KERNEL)) | 1808 | do { |
| 1647 | goto out_put; | 1809 | if (!ida_pre_get(&sd_index_ida, GFP_KERNEL)) |
| 1810 | goto out_put; | ||
| 1648 | 1811 | ||
| 1649 | spin_lock(&sd_index_lock); | 1812 | error = ida_get_new(&sd_index_ida, &index); |
| 1650 | error = idr_get_new(&sd_index_idr, NULL, &index); | 1813 | } while (error == -EAGAIN); |
| 1651 | spin_unlock(&sd_index_lock); | ||
| 1652 | 1814 | ||
| 1653 | if (index >= SD_MAX_DISKS) | ||
| 1654 | error = -EBUSY; | ||
| 1655 | if (error) | 1815 | if (error) |
| 1656 | goto out_put; | 1816 | goto out_put; |
| 1657 | 1817 | ||
| 1818 | error = -EBUSY; | ||
| 1819 | if (index >= SD_MAX_DISKS) | ||
| 1820 | goto out_free_index; | ||
| 1821 | |||
| 1658 | sdkp->device = sdp; | 1822 | sdkp->device = sdp; |
| 1659 | sdkp->driver = &sd_template; | 1823 | sdkp->driver = &sd_template; |
| 1660 | sdkp->disk = gd; | 1824 | sdkp->disk = gd; |
| @@ -1675,7 +1839,7 @@ static int sd_probe(struct device *dev) | |||
| 1675 | strncpy(sdkp->dev.bus_id, sdp->sdev_gendev.bus_id, BUS_ID_SIZE); | 1839 | strncpy(sdkp->dev.bus_id, sdp->sdev_gendev.bus_id, BUS_ID_SIZE); |
| 1676 | 1840 | ||
| 1677 | if (device_add(&sdkp->dev)) | 1841 | if (device_add(&sdkp->dev)) |
| 1678 | goto out_put; | 1842 | goto out_free_index; |
| 1679 | 1843 | ||
| 1680 | get_device(&sdp->sdev_gendev); | 1844 | get_device(&sdp->sdev_gendev); |
| 1681 | 1845 | ||
| @@ -1711,12 +1875,15 @@ static int sd_probe(struct device *dev) | |||
| 1711 | 1875 | ||
| 1712 | dev_set_drvdata(dev, sdkp); | 1876 | dev_set_drvdata(dev, sdkp); |
| 1713 | add_disk(gd); | 1877 | add_disk(gd); |
| 1878 | sd_dif_config_host(sdkp); | ||
| 1714 | 1879 | ||
| 1715 | sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", | 1880 | sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", |
| 1716 | sdp->removable ? "removable " : ""); | 1881 | sdp->removable ? "removable " : ""); |
| 1717 | 1882 | ||
| 1718 | return 0; | 1883 | return 0; |
| 1719 | 1884 | ||
| 1885 | out_free_index: | ||
| 1886 | ida_remove(&sd_index_ida, index); | ||
| 1720 | out_put: | 1887 | out_put: |
| 1721 | put_disk(gd); | 1888 | put_disk(gd); |
| 1722 | out_free: | 1889 | out_free: |
| @@ -1766,9 +1933,7 @@ static void scsi_disk_release(struct device *dev) | |||
| 1766 | struct scsi_disk *sdkp = to_scsi_disk(dev); | 1933 | struct scsi_disk *sdkp = to_scsi_disk(dev); |
| 1767 | struct gendisk *disk = sdkp->disk; | 1934 | struct gendisk *disk = sdkp->disk; |
| 1768 | 1935 | ||
| 1769 | spin_lock(&sd_index_lock); | 1936 | ida_remove(&sd_index_ida, sdkp->index); |
| 1770 | idr_remove(&sd_index_idr, sdkp->index); | ||
| 1771 | spin_unlock(&sd_index_lock); | ||
| 1772 | 1937 | ||
| 1773 | disk->private_data = NULL; | 1938 | disk->private_data = NULL; |
| 1774 | put_disk(disk); | 1939 | put_disk(disk); |
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 03a3d45cfa42..95b9f06534d5 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h | |||
| @@ -31,6 +31,12 @@ | |||
| 31 | */ | 31 | */ |
| 32 | #define SD_BUF_SIZE 512 | 32 | #define SD_BUF_SIZE 512 |
| 33 | 33 | ||
| 34 | /* | ||
| 35 | * Number of sectors at the end of the device to avoid multi-sector | ||
| 36 | * accesses to in the case of last_sector_bug | ||
| 37 | */ | ||
| 38 | #define SD_LAST_BUGGY_SECTORS 8 | ||
| 39 | |||
| 34 | struct scsi_disk { | 40 | struct scsi_disk { |
| 35 | struct scsi_driver *driver; /* always &sd_template */ | 41 | struct scsi_driver *driver; /* always &sd_template */ |
| 36 | struct scsi_device *device; | 42 | struct scsi_device *device; |
| @@ -41,7 +47,9 @@ struct scsi_disk { | |||
| 41 | u32 index; | 47 | u32 index; |
| 42 | u8 media_present; | 48 | u8 media_present; |
| 43 | u8 write_prot; | 49 | u8 write_prot; |
| 50 | u8 protection_type;/* Data Integrity Field */ | ||
| 44 | unsigned previous_state : 1; | 51 | unsigned previous_state : 1; |
| 52 | unsigned ATO : 1; /* state of disk ATO bit */ | ||
| 45 | unsigned WCE : 1; /* state of disk WCE bit */ | 53 | unsigned WCE : 1; /* state of disk WCE bit */ |
| 46 | unsigned RCD : 1; /* state of disk RCD bit, unused */ | 54 | unsigned RCD : 1; /* state of disk RCD bit, unused */ |
| 47 | unsigned DPOFUA : 1; /* state of disk DPOFUA bit */ | 55 | unsigned DPOFUA : 1; /* state of disk DPOFUA bit */ |
| @@ -59,4 +67,50 @@ static inline struct scsi_disk *scsi_disk(struct gendisk *disk) | |||
| 59 | (sdsk)->disk->disk_name, ##a) : \ | 67 | (sdsk)->disk->disk_name, ##a) : \ |
| 60 | sdev_printk(prefix, (sdsk)->device, fmt, ##a) | 68 | sdev_printk(prefix, (sdsk)->device, fmt, ##a) |
| 61 | 69 | ||
| 70 | /* | ||
| 71 | * A DIF-capable target device can be formatted with different | ||
| 72 | * protection schemes. Currently 0 through 3 are defined: | ||
| 73 | * | ||
| 74 | * Type 0 is regular (unprotected) I/O | ||
| 75 | * | ||
| 76 | * Type 1 defines the contents of the guard and reference tags | ||
| 77 | * | ||
| 78 | * Type 2 defines the contents of the guard and reference tags and | ||
| 79 | * uses 32-byte commands to seed the latter | ||
| 80 | * | ||
| 81 | * Type 3 defines the contents of the guard tag only | ||
| 82 | */ | ||
| 83 | |||
| 84 | enum sd_dif_target_protection_types { | ||
| 85 | SD_DIF_TYPE0_PROTECTION = 0x0, | ||
| 86 | SD_DIF_TYPE1_PROTECTION = 0x1, | ||
| 87 | SD_DIF_TYPE2_PROTECTION = 0x2, | ||
| 88 | SD_DIF_TYPE3_PROTECTION = 0x3, | ||
| 89 | }; | ||
| 90 | |||
| 91 | /* | ||
| 92 | * Data Integrity Field tuple. | ||
| 93 | */ | ||
| 94 | struct sd_dif_tuple { | ||
| 95 | __be16 guard_tag; /* Checksum */ | ||
| 96 | __be16 app_tag; /* Opaque storage */ | ||
| 97 | __be32 ref_tag; /* Target LBA or indirect LBA */ | ||
| 98 | }; | ||
| 99 | |||
| 100 | #if defined(CONFIG_BLK_DEV_INTEGRITY) | ||
| 101 | |||
| 102 | extern void sd_dif_op(struct scsi_cmnd *, unsigned int, unsigned int); | ||
| 103 | extern void sd_dif_config_host(struct scsi_disk *); | ||
| 104 | extern int sd_dif_prepare(struct request *rq, sector_t, unsigned int); | ||
| 105 | extern void sd_dif_complete(struct scsi_cmnd *, unsigned int); | ||
| 106 | |||
| 107 | #else /* CONFIG_BLK_DEV_INTEGRITY */ | ||
| 108 | |||
| 109 | #define sd_dif_op(a, b, c) do { } while (0) | ||
| 110 | #define sd_dif_config_host(a) do { } while (0) | ||
| 111 | #define sd_dif_prepare(a, b, c) (0) | ||
| 112 | #define sd_dif_complete(a, b) (0) | ||
| 113 | |||
| 114 | #endif /* CONFIG_BLK_DEV_INTEGRITY */ | ||
| 115 | |||
| 62 | #endif /* _SCSI_DISK_H */ | 116 | #endif /* _SCSI_DISK_H */ |
diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c new file mode 100644 index 000000000000..4d17f3d35aac --- /dev/null +++ b/drivers/scsi/sd_dif.c | |||
| @@ -0,0 +1,538 @@ | |||
| 1 | /* | ||
| 2 | * sd_dif.c - SCSI Data Integrity Field | ||
| 3 | * | ||
| 4 | * Copyright (C) 2007, 2008 Oracle Corporation | ||
| 5 | * Written by: Martin K. Petersen <martin.petersen@oracle.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License version | ||
| 9 | * 2 as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, but | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; see the file COPYING. If not, write to | ||
| 18 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, | ||
| 19 | * USA. | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/blkdev.h> | ||
| 24 | #include <linux/crc-t10dif.h> | ||
| 25 | |||
| 26 | #include <scsi/scsi.h> | ||
| 27 | #include <scsi/scsi_cmnd.h> | ||
| 28 | #include <scsi/scsi_dbg.h> | ||
| 29 | #include <scsi/scsi_device.h> | ||
| 30 | #include <scsi/scsi_driver.h> | ||
| 31 | #include <scsi/scsi_eh.h> | ||
| 32 | #include <scsi/scsi_host.h> | ||
| 33 | #include <scsi/scsi_ioctl.h> | ||
| 34 | #include <scsi/scsicam.h> | ||
| 35 | |||
| 36 | #include <net/checksum.h> | ||
| 37 | |||
| 38 | #include "sd.h" | ||
| 39 | |||
| 40 | typedef __u16 (csum_fn) (void *, unsigned int); | ||
| 41 | |||
| 42 | static __u16 sd_dif_crc_fn(void *data, unsigned int len) | ||
| 43 | { | ||
| 44 | return cpu_to_be16(crc_t10dif(data, len)); | ||
| 45 | } | ||
| 46 | |||
| 47 | static __u16 sd_dif_ip_fn(void *data, unsigned int len) | ||
| 48 | { | ||
| 49 | return ip_compute_csum(data, len); | ||
| 50 | } | ||
| 51 | |||
| 52 | /* | ||
| 53 | * Type 1 and Type 2 protection use the same format: 16 bit guard tag, | ||
| 54 | * 16 bit app tag, 32 bit reference tag. | ||
| 55 | */ | ||
| 56 | static void sd_dif_type1_generate(struct blk_integrity_exchg *bix, csum_fn *fn) | ||
| 57 | { | ||
| 58 | void *buf = bix->data_buf; | ||
| 59 | struct sd_dif_tuple *sdt = bix->prot_buf; | ||
| 60 | sector_t sector = bix->sector; | ||
| 61 | unsigned int i; | ||
| 62 | |||
| 63 | for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) { | ||
| 64 | sdt->guard_tag = fn(buf, bix->sector_size); | ||
| 65 | sdt->ref_tag = cpu_to_be32(sector & 0xffffffff); | ||
| 66 | sdt->app_tag = 0; | ||
| 67 | |||
| 68 | buf += bix->sector_size; | ||
| 69 | sector++; | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | static void sd_dif_type1_generate_crc(struct blk_integrity_exchg *bix) | ||
| 74 | { | ||
| 75 | sd_dif_type1_generate(bix, sd_dif_crc_fn); | ||
| 76 | } | ||
| 77 | |||
| 78 | static void sd_dif_type1_generate_ip(struct blk_integrity_exchg *bix) | ||
| 79 | { | ||
| 80 | sd_dif_type1_generate(bix, sd_dif_ip_fn); | ||
| 81 | } | ||
| 82 | |||
| 83 | static int sd_dif_type1_verify(struct blk_integrity_exchg *bix, csum_fn *fn) | ||
| 84 | { | ||
| 85 | void *buf = bix->data_buf; | ||
| 86 | struct sd_dif_tuple *sdt = bix->prot_buf; | ||
| 87 | sector_t sector = bix->sector; | ||
| 88 | unsigned int i; | ||
| 89 | __u16 csum; | ||
| 90 | |||
| 91 | for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) { | ||
| 92 | /* Unwritten sectors */ | ||
| 93 | if (sdt->app_tag == 0xffff) | ||
| 94 | return 0; | ||
| 95 | |||
| 96 | /* Bad ref tag received from disk */ | ||
| 97 | if (sdt->ref_tag == 0xffffffff) { | ||
| 98 | printk(KERN_ERR | ||
| 99 | "%s: bad phys ref tag on sector %lu\n", | ||
| 100 | bix->disk_name, (unsigned long)sector); | ||
| 101 | return -EIO; | ||
| 102 | } | ||
| 103 | |||
| 104 | if (be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { | ||
| 105 | printk(KERN_ERR | ||
| 106 | "%s: ref tag error on sector %lu (rcvd %u)\n", | ||
| 107 | bix->disk_name, (unsigned long)sector, | ||
| 108 | be32_to_cpu(sdt->ref_tag)); | ||
| 109 | return -EIO; | ||
| 110 | } | ||
| 111 | |||
| 112 | csum = fn(buf, bix->sector_size); | ||
| 113 | |||
| 114 | if (sdt->guard_tag != csum) { | ||
| 115 | printk(KERN_ERR "%s: guard tag error on sector %lu " \ | ||
| 116 | "(rcvd %04x, data %04x)\n", bix->disk_name, | ||
| 117 | (unsigned long)sector, | ||
| 118 | be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum)); | ||
| 119 | return -EIO; | ||
| 120 | } | ||
| 121 | |||
| 122 | buf += bix->sector_size; | ||
| 123 | sector++; | ||
| 124 | } | ||
| 125 | |||
| 126 | return 0; | ||
| 127 | } | ||
| 128 | |||
| 129 | static int sd_dif_type1_verify_crc(struct blk_integrity_exchg *bix) | ||
| 130 | { | ||
| 131 | return sd_dif_type1_verify(bix, sd_dif_crc_fn); | ||
| 132 | } | ||
| 133 | |||
| 134 | static int sd_dif_type1_verify_ip(struct blk_integrity_exchg *bix) | ||
| 135 | { | ||
| 136 | return sd_dif_type1_verify(bix, sd_dif_ip_fn); | ||
| 137 | } | ||
| 138 | |||
| 139 | /* | ||
| 140 | * Functions for interleaving and deinterleaving application tags | ||
| 141 | */ | ||
| 142 | static void sd_dif_type1_set_tag(void *prot, void *tag_buf, unsigned int sectors) | ||
| 143 | { | ||
| 144 | struct sd_dif_tuple *sdt = prot; | ||
| 145 | char *tag = tag_buf; | ||
| 146 | unsigned int i, j; | ||
| 147 | |||
| 148 | for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) { | ||
| 149 | sdt->app_tag = tag[j] << 8 | tag[j+1]; | ||
| 150 | BUG_ON(sdt->app_tag == 0xffff); | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | static void sd_dif_type1_get_tag(void *prot, void *tag_buf, unsigned int sectors) | ||
| 155 | { | ||
| 156 | struct sd_dif_tuple *sdt = prot; | ||
| 157 | char *tag = tag_buf; | ||
| 158 | unsigned int i, j; | ||
| 159 | |||
| 160 | for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) { | ||
| 161 | tag[j] = (sdt->app_tag & 0xff00) >> 8; | ||
| 162 | tag[j+1] = sdt->app_tag & 0xff; | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | static struct blk_integrity dif_type1_integrity_crc = { | ||
| 167 | .name = "T10-DIF-TYPE1-CRC", | ||
| 168 | .generate_fn = sd_dif_type1_generate_crc, | ||
| 169 | .verify_fn = sd_dif_type1_verify_crc, | ||
| 170 | .get_tag_fn = sd_dif_type1_get_tag, | ||
| 171 | .set_tag_fn = sd_dif_type1_set_tag, | ||
| 172 | .tuple_size = sizeof(struct sd_dif_tuple), | ||
| 173 | .tag_size = 0, | ||
| 174 | }; | ||
| 175 | |||
| 176 | static struct blk_integrity dif_type1_integrity_ip = { | ||
| 177 | .name = "T10-DIF-TYPE1-IP", | ||
| 178 | .generate_fn = sd_dif_type1_generate_ip, | ||
| 179 | .verify_fn = sd_dif_type1_verify_ip, | ||
| 180 | .get_tag_fn = sd_dif_type1_get_tag, | ||
| 181 | .set_tag_fn = sd_dif_type1_set_tag, | ||
| 182 | .tuple_size = sizeof(struct sd_dif_tuple), | ||
| 183 | .tag_size = 0, | ||
| 184 | }; | ||
| 185 | |||
| 186 | |||
| 187 | /* | ||
| 188 | * Type 3 protection has a 16-bit guard tag and 16 + 32 bits of opaque | ||
| 189 | * tag space. | ||
| 190 | */ | ||
| 191 | static void sd_dif_type3_generate(struct blk_integrity_exchg *bix, csum_fn *fn) | ||
| 192 | { | ||
| 193 | void *buf = bix->data_buf; | ||
| 194 | struct sd_dif_tuple *sdt = bix->prot_buf; | ||
| 195 | unsigned int i; | ||
| 196 | |||
| 197 | for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) { | ||
| 198 | sdt->guard_tag = fn(buf, bix->sector_size); | ||
| 199 | sdt->ref_tag = 0; | ||
| 200 | sdt->app_tag = 0; | ||
| 201 | |||
| 202 | buf += bix->sector_size; | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | static void sd_dif_type3_generate_crc(struct blk_integrity_exchg *bix) | ||
| 207 | { | ||
| 208 | sd_dif_type3_generate(bix, sd_dif_crc_fn); | ||
| 209 | } | ||
| 210 | |||
| 211 | static void sd_dif_type3_generate_ip(struct blk_integrity_exchg *bix) | ||
| 212 | { | ||
| 213 | sd_dif_type3_generate(bix, sd_dif_ip_fn); | ||
| 214 | } | ||
| 215 | |||
| 216 | static int sd_dif_type3_verify(struct blk_integrity_exchg *bix, csum_fn *fn) | ||
| 217 | { | ||
| 218 | void *buf = bix->data_buf; | ||
| 219 | struct sd_dif_tuple *sdt = bix->prot_buf; | ||
| 220 | sector_t sector = bix->sector; | ||
| 221 | unsigned int i; | ||
| 222 | __u16 csum; | ||
| 223 | |||
| 224 | for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) { | ||
| 225 | /* Unwritten sectors */ | ||
| 226 | if (sdt->app_tag == 0xffff && sdt->ref_tag == 0xffffffff) | ||
| 227 | return 0; | ||
| 228 | |||
| 229 | csum = fn(buf, bix->sector_size); | ||
| 230 | |||
| 231 | if (sdt->guard_tag != csum) { | ||
| 232 | printk(KERN_ERR "%s: guard tag error on sector %lu " \ | ||
| 233 | "(rcvd %04x, data %04x)\n", bix->disk_name, | ||
| 234 | (unsigned long)sector, | ||
| 235 | be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum)); | ||
| 236 | return -EIO; | ||
| 237 | } | ||
| 238 | |||
| 239 | buf += bix->sector_size; | ||
| 240 | sector++; | ||
| 241 | } | ||
| 242 | |||
| 243 | return 0; | ||
| 244 | } | ||
| 245 | |||
| 246 | static int sd_dif_type3_verify_crc(struct blk_integrity_exchg *bix) | ||
| 247 | { | ||
| 248 | return sd_dif_type3_verify(bix, sd_dif_crc_fn); | ||
| 249 | } | ||
| 250 | |||
| 251 | static int sd_dif_type3_verify_ip(struct blk_integrity_exchg *bix) | ||
| 252 | { | ||
| 253 | return sd_dif_type3_verify(bix, sd_dif_ip_fn); | ||
| 254 | } | ||
| 255 | |||
| 256 | static void sd_dif_type3_set_tag(void *prot, void *tag_buf, unsigned int sectors) | ||
| 257 | { | ||
| 258 | struct sd_dif_tuple *sdt = prot; | ||
| 259 | char *tag = tag_buf; | ||
| 260 | unsigned int i, j; | ||
| 261 | |||
| 262 | for (i = 0, j = 0 ; i < sectors ; i++, j += 6, sdt++) { | ||
| 263 | sdt->app_tag = tag[j] << 8 | tag[j+1]; | ||
| 264 | sdt->ref_tag = tag[j+2] << 24 | tag[j+3] << 16 | | ||
| 265 | tag[j+4] << 8 | tag[j+5]; | ||
| 266 | } | ||
| 267 | } | ||
| 268 | |||
| 269 | static void sd_dif_type3_get_tag(void *prot, void *tag_buf, unsigned int sectors) | ||
| 270 | { | ||
| 271 | struct sd_dif_tuple *sdt = prot; | ||
| 272 | char *tag = tag_buf; | ||
| 273 | unsigned int i, j; | ||
| 274 | |||
| 275 | for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) { | ||
| 276 | tag[j] = (sdt->app_tag & 0xff00) >> 8; | ||
| 277 | tag[j+1] = sdt->app_tag & 0xff; | ||
| 278 | tag[j+2] = (sdt->ref_tag & 0xff000000) >> 24; | ||
| 279 | tag[j+3] = (sdt->ref_tag & 0xff0000) >> 16; | ||
| 280 | tag[j+4] = (sdt->ref_tag & 0xff00) >> 8; | ||
| 281 | tag[j+5] = sdt->ref_tag & 0xff; | ||
| 282 | BUG_ON(sdt->app_tag == 0xffff || sdt->ref_tag == 0xffffffff); | ||
| 283 | } | ||
| 284 | } | ||
| 285 | |||
| 286 | static struct blk_integrity dif_type3_integrity_crc = { | ||
| 287 | .name = "T10-DIF-TYPE3-CRC", | ||
| 288 | .generate_fn = sd_dif_type3_generate_crc, | ||
| 289 | .verify_fn = sd_dif_type3_verify_crc, | ||
| 290 | .get_tag_fn = sd_dif_type3_get_tag, | ||
| 291 | .set_tag_fn = sd_dif_type3_set_tag, | ||
| 292 | .tuple_size = sizeof(struct sd_dif_tuple), | ||
| 293 | .tag_size = 0, | ||
| 294 | }; | ||
| 295 | |||
| 296 | static struct blk_integrity dif_type3_integrity_ip = { | ||
| 297 | .name = "T10-DIF-TYPE3-IP", | ||
| 298 | .generate_fn = sd_dif_type3_generate_ip, | ||
| 299 | .verify_fn = sd_dif_type3_verify_ip, | ||
| 300 | .get_tag_fn = sd_dif_type3_get_tag, | ||
| 301 | .set_tag_fn = sd_dif_type3_set_tag, | ||
| 302 | .tuple_size = sizeof(struct sd_dif_tuple), | ||
| 303 | .tag_size = 0, | ||
| 304 | }; | ||
| 305 | |||
| 306 | /* | ||
| 307 | * Configure exchange of protection information between OS and HBA. | ||
| 308 | */ | ||
| 309 | void sd_dif_config_host(struct scsi_disk *sdkp) | ||
| 310 | { | ||
| 311 | struct scsi_device *sdp = sdkp->device; | ||
| 312 | struct gendisk *disk = sdkp->disk; | ||
| 313 | u8 type = sdkp->protection_type; | ||
| 314 | |||
| 315 | /* If this HBA doesn't support DIX, resort to normal I/O or DIF */ | ||
| 316 | if (scsi_host_dix_capable(sdp->host, type) == 0) { | ||
| 317 | |||
| 318 | if (type == SD_DIF_TYPE0_PROTECTION) | ||
| 319 | return; | ||
| 320 | |||
| 321 | if (scsi_host_dif_capable(sdp->host, type) == 0) { | ||
| 322 | sd_printk(KERN_INFO, sdkp, "Type %d protection " \ | ||
| 323 | "unsupported by HBA. Disabling DIF.\n", type); | ||
| 324 | sdkp->protection_type = 0; | ||
| 325 | return; | ||
| 326 | } | ||
| 327 | |||
| 328 | sd_printk(KERN_INFO, sdkp, "Enabling DIF Type %d protection\n", | ||
| 329 | type); | ||
| 330 | |||
| 331 | return; | ||
| 332 | } | ||
| 333 | |||
| 334 | /* Enable DMA of protection information */ | ||
| 335 | if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) | ||
| 336 | if (type == SD_DIF_TYPE3_PROTECTION) | ||
| 337 | blk_integrity_register(disk, &dif_type3_integrity_ip); | ||
| 338 | else | ||
| 339 | blk_integrity_register(disk, &dif_type1_integrity_ip); | ||
| 340 | else | ||
| 341 | if (type == SD_DIF_TYPE3_PROTECTION) | ||
| 342 | blk_integrity_register(disk, &dif_type3_integrity_crc); | ||
| 343 | else | ||
| 344 | blk_integrity_register(disk, &dif_type1_integrity_crc); | ||
| 345 | |||
| 346 | sd_printk(KERN_INFO, sdkp, | ||
| 347 | "Enabling %s integrity protection\n", disk->integrity->name); | ||
| 348 | |||
| 349 | /* Signal to block layer that we support sector tagging */ | ||
| 350 | if (type && sdkp->ATO) { | ||
| 351 | if (type == SD_DIF_TYPE3_PROTECTION) | ||
| 352 | disk->integrity->tag_size = sizeof(u16) + sizeof(u32); | ||
| 353 | else | ||
| 354 | disk->integrity->tag_size = sizeof(u16); | ||
| 355 | |||
| 356 | sd_printk(KERN_INFO, sdkp, "DIF application tag size %u\n", | ||
| 357 | disk->integrity->tag_size); | ||
| 358 | } | ||
| 359 | } | ||
| 360 | |||
| 361 | /* | ||
| 362 | * DIF DMA operation magic decoder ring. | ||
| 363 | */ | ||
| 364 | void sd_dif_op(struct scsi_cmnd *scmd, unsigned int dif, unsigned int dix) | ||
| 365 | { | ||
| 366 | int csum_convert, prot_op; | ||
| 367 | |||
| 368 | prot_op = 0; | ||
| 369 | |||
| 370 | /* Convert checksum? */ | ||
| 371 | if (scsi_host_get_guard(scmd->device->host) != SHOST_DIX_GUARD_CRC) | ||
| 372 | csum_convert = 1; | ||
| 373 | else | ||
| 374 | csum_convert = 0; | ||
| 375 | |||
| 376 | switch (scmd->cmnd[0]) { | ||
| 377 | case READ_10: | ||
| 378 | case READ_12: | ||
| 379 | case READ_16: | ||
| 380 | if (dif && dix) | ||
| 381 | if (csum_convert) | ||
| 382 | prot_op = SCSI_PROT_READ_CONVERT; | ||
| 383 | else | ||
| 384 | prot_op = SCSI_PROT_READ_PASS; | ||
| 385 | else if (dif && !dix) | ||
| 386 | prot_op = SCSI_PROT_READ_STRIP; | ||
| 387 | else if (!dif && dix) | ||
| 388 | prot_op = SCSI_PROT_READ_INSERT; | ||
| 389 | |||
| 390 | break; | ||
| 391 | |||
| 392 | case WRITE_10: | ||
| 393 | case WRITE_12: | ||
| 394 | case WRITE_16: | ||
| 395 | if (dif && dix) | ||
| 396 | if (csum_convert) | ||
| 397 | prot_op = SCSI_PROT_WRITE_CONVERT; | ||
| 398 | else | ||
| 399 | prot_op = SCSI_PROT_WRITE_PASS; | ||
| 400 | else if (dif && !dix) | ||
| 401 | prot_op = SCSI_PROT_WRITE_INSERT; | ||
| 402 | else if (!dif && dix) | ||
| 403 | prot_op = SCSI_PROT_WRITE_STRIP; | ||
| 404 | |||
| 405 | break; | ||
| 406 | } | ||
| 407 | |||
| 408 | scsi_set_prot_op(scmd, prot_op); | ||
| 409 | scsi_set_prot_type(scmd, dif); | ||
| 410 | } | ||
| 411 | |||
| 412 | /* | ||
| 413 | * The virtual start sector is the one that was originally submitted | ||
| 414 | * by the block layer. Due to partitioning, MD/DM cloning, etc. the | ||
| 415 | * actual physical start sector is likely to be different. Remap | ||
| 416 | * protection information to match the physical LBA. | ||
| 417 | * | ||
| 418 | * From a protocol perspective there's a slight difference between | ||
| 419 | * Type 1 and 2. The latter uses 32-byte CDBs exclusively, and the | ||
| 420 | * reference tag is seeded in the CDB. This gives us the potential to | ||
| 421 | * avoid virt->phys remapping during write. However, at read time we | ||
| 422 | * don't know whether the virt sector is the same as when we wrote it | ||
| 423 | * (we could be reading from real disk as opposed to MD/DM device. So | ||
| 424 | * we always remap Type 2 making it identical to Type 1. | ||
| 425 | * | ||
| 426 | * Type 3 does not have a reference tag so no remapping is required. | ||
| 427 | */ | ||
| 428 | int sd_dif_prepare(struct request *rq, sector_t hw_sector, unsigned int sector_sz) | ||
| 429 | { | ||
| 430 | const int tuple_sz = sizeof(struct sd_dif_tuple); | ||
| 431 | struct bio *bio; | ||
| 432 | struct scsi_disk *sdkp; | ||
| 433 | struct sd_dif_tuple *sdt; | ||
| 434 | unsigned int i, j; | ||
| 435 | u32 phys, virt; | ||
| 436 | |||
| 437 | /* Already remapped? */ | ||
| 438 | if (rq->cmd_flags & REQ_INTEGRITY) | ||
| 439 | return 0; | ||
| 440 | |||
| 441 | sdkp = rq->bio->bi_bdev->bd_disk->private_data; | ||
| 442 | |||
| 443 | if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION) | ||
| 444 | return 0; | ||
| 445 | |||
| 446 | rq->cmd_flags |= REQ_INTEGRITY; | ||
| 447 | phys = hw_sector & 0xffffffff; | ||
| 448 | |||
| 449 | __rq_for_each_bio(bio, rq) { | ||
| 450 | struct bio_vec *iv; | ||
| 451 | |||
| 452 | virt = bio->bi_integrity->bip_sector & 0xffffffff; | ||
| 453 | |||
| 454 | bip_for_each_vec(iv, bio->bi_integrity, i) { | ||
| 455 | sdt = kmap_atomic(iv->bv_page, KM_USER0) | ||
| 456 | + iv->bv_offset; | ||
| 457 | |||
| 458 | for (j = 0 ; j < iv->bv_len ; j += tuple_sz, sdt++) { | ||
| 459 | |||
| 460 | if (be32_to_cpu(sdt->ref_tag) != virt) | ||
| 461 | goto error; | ||
| 462 | |||
| 463 | sdt->ref_tag = cpu_to_be32(phys); | ||
| 464 | virt++; | ||
| 465 | phys++; | ||
| 466 | } | ||
| 467 | |||
| 468 | kunmap_atomic(sdt, KM_USER0); | ||
| 469 | } | ||
| 470 | } | ||
| 471 | |||
| 472 | return 0; | ||
| 473 | |||
| 474 | error: | ||
| 475 | kunmap_atomic(sdt, KM_USER0); | ||
| 476 | sd_printk(KERN_ERR, sdkp, "%s: virt %u, phys %u, ref %u\n", | ||
| 477 | __func__, virt, phys, be32_to_cpu(sdt->ref_tag)); | ||
| 478 | |||
| 479 | return -EIO; | ||
| 480 | } | ||
| 481 | |||
| 482 | /* | ||
| 483 | * Remap physical sector values in the reference tag to the virtual | ||
| 484 | * values expected by the block layer. | ||
| 485 | */ | ||
| 486 | void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes) | ||
| 487 | { | ||
| 488 | const int tuple_sz = sizeof(struct sd_dif_tuple); | ||
| 489 | struct scsi_disk *sdkp; | ||
| 490 | struct bio *bio; | ||
| 491 | struct sd_dif_tuple *sdt; | ||
| 492 | unsigned int i, j, sectors, sector_sz; | ||
| 493 | u32 phys, virt; | ||
| 494 | |||
| 495 | sdkp = scsi_disk(scmd->request->rq_disk); | ||
| 496 | |||
| 497 | if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION || good_bytes == 0) | ||
| 498 | return; | ||
| 499 | |||
| 500 | sector_sz = scmd->device->sector_size; | ||
| 501 | sectors = good_bytes / sector_sz; | ||
| 502 | |||
| 503 | phys = scmd->request->sector & 0xffffffff; | ||
| 504 | if (sector_sz == 4096) | ||
| 505 | phys >>= 3; | ||
| 506 | |||
| 507 | __rq_for_each_bio(bio, scmd->request) { | ||
| 508 | struct bio_vec *iv; | ||
| 509 | |||
| 510 | virt = bio->bi_integrity->bip_sector & 0xffffffff; | ||
| 511 | |||
| 512 | bip_for_each_vec(iv, bio->bi_integrity, i) { | ||
| 513 | sdt = kmap_atomic(iv->bv_page, KM_USER0) | ||
| 514 | + iv->bv_offset; | ||
| 515 | |||
| 516 | for (j = 0 ; j < iv->bv_len ; j += tuple_sz, sdt++) { | ||
| 517 | |||
| 518 | if (sectors == 0) { | ||
| 519 | kunmap_atomic(sdt, KM_USER0); | ||
| 520 | return; | ||
| 521 | } | ||
| 522 | |||
| 523 | if (be32_to_cpu(sdt->ref_tag) != phys && | ||
| 524 | sdt->app_tag != 0xffff) | ||
| 525 | sdt->ref_tag = 0xffffffff; /* Bad ref */ | ||
| 526 | else | ||
| 527 | sdt->ref_tag = cpu_to_be32(virt); | ||
| 528 | |||
| 529 | virt++; | ||
| 530 | phys++; | ||
| 531 | sectors--; | ||
| 532 | } | ||
| 533 | |||
| 534 | kunmap_atomic(sdt, KM_USER0); | ||
| 535 | } | ||
| 536 | } | ||
| 537 | } | ||
| 538 | |||
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 4684cc716aa4..c2bb53e3d941 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c | |||
| @@ -17,7 +17,7 @@ | |||
| 17 | Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support | 17 | Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support |
| 18 | */ | 18 | */ |
| 19 | 19 | ||
| 20 | static const char *verstr = "20080224"; | 20 | static const char *verstr = "20080504"; |
| 21 | 21 | ||
| 22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
| 23 | 23 | ||
| @@ -631,7 +631,7 @@ static int cross_eof(struct scsi_tape * STp, int forward) | |||
| 631 | /* Flush the write buffer (never need to write if variable blocksize). */ | 631 | /* Flush the write buffer (never need to write if variable blocksize). */ |
| 632 | static int st_flush_write_buffer(struct scsi_tape * STp) | 632 | static int st_flush_write_buffer(struct scsi_tape * STp) |
| 633 | { | 633 | { |
| 634 | int offset, transfer, blks; | 634 | int transfer, blks; |
| 635 | int result; | 635 | int result; |
| 636 | unsigned char cmd[MAX_COMMAND_SIZE]; | 636 | unsigned char cmd[MAX_COMMAND_SIZE]; |
| 637 | struct st_request *SRpnt; | 637 | struct st_request *SRpnt; |
| @@ -644,14 +644,10 @@ static int st_flush_write_buffer(struct scsi_tape * STp) | |||
| 644 | result = 0; | 644 | result = 0; |
| 645 | if (STp->dirty == 1) { | 645 | if (STp->dirty == 1) { |
| 646 | 646 | ||
| 647 | offset = (STp->buffer)->buffer_bytes; | 647 | transfer = STp->buffer->buffer_bytes; |
| 648 | transfer = ((offset + STp->block_size - 1) / | ||
| 649 | STp->block_size) * STp->block_size; | ||
| 650 | DEBC(printk(ST_DEB_MSG "%s: Flushing %d bytes.\n", | 648 | DEBC(printk(ST_DEB_MSG "%s: Flushing %d bytes.\n", |
| 651 | tape_name(STp), transfer)); | 649 | tape_name(STp), transfer)); |
| 652 | 650 | ||
| 653 | memset((STp->buffer)->b_data + offset, 0, transfer - offset); | ||
| 654 | |||
| 655 | memset(cmd, 0, MAX_COMMAND_SIZE); | 651 | memset(cmd, 0, MAX_COMMAND_SIZE); |
| 656 | cmd[0] = WRITE_6; | 652 | cmd[0] = WRITE_6; |
| 657 | cmd[1] = 1; | 653 | cmd[1] = 1; |
| @@ -1670,6 +1666,7 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) | |||
| 1670 | if (undone <= do_count) { | 1666 | if (undone <= do_count) { |
| 1671 | /* Only data from this write is not written */ | 1667 | /* Only data from this write is not written */ |
| 1672 | count += undone; | 1668 | count += undone; |
| 1669 | b_point -= undone; | ||
| 1673 | do_count -= undone; | 1670 | do_count -= undone; |
| 1674 | if (STp->block_size) | 1671 | if (STp->block_size) |
| 1675 | blks = (transfer - undone) / STp->block_size; | 1672 | blks = (transfer - undone) / STp->block_size; |
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index f308a0308829..3790906a77d1 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c | |||
| @@ -467,7 +467,7 @@ stex_slave_alloc(struct scsi_device *sdev) | |||
| 467 | /* Cheat: usually extracted from Inquiry data */ | 467 | /* Cheat: usually extracted from Inquiry data */ |
| 468 | sdev->tagged_supported = 1; | 468 | sdev->tagged_supported = 1; |
| 469 | 469 | ||
| 470 | scsi_activate_tcq(sdev, sdev->host->can_queue); | 470 | scsi_activate_tcq(sdev, ST_CMD_PER_LUN); |
| 471 | 471 | ||
| 472 | return 0; | 472 | return 0; |
| 473 | } | 473 | } |
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index 22a6aae78699..98df1651404f 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c | |||
| @@ -5741,6 +5741,8 @@ void sym_hcb_free(struct sym_hcb *np) | |||
| 5741 | 5741 | ||
| 5742 | for (target = 0; target < SYM_CONF_MAX_TARGET ; target++) { | 5742 | for (target = 0; target < SYM_CONF_MAX_TARGET ; target++) { |
| 5743 | tp = &np->target[target]; | 5743 | tp = &np->target[target]; |
| 5744 | if (tp->luntbl) | ||
| 5745 | sym_mfree_dma(tp->luntbl, 256, "LUNTBL"); | ||
| 5744 | #if SYM_CONF_MAX_LUN > 1 | 5746 | #if SYM_CONF_MAX_LUN > 1 |
| 5745 | kfree(tp->lunmp); | 5747 | kfree(tp->lunmp); |
| 5746 | #endif | 5748 | #endif |
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index 5b04ddfed26c..1723d71cbf3f 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c | |||
| @@ -452,7 +452,7 @@ static int dc390_pci_map (struct dc390_srb* pSRB) | |||
| 452 | /* TODO: error handling */ | 452 | /* TODO: error handling */ |
| 453 | if (pSRB->SGcount != 1) | 453 | if (pSRB->SGcount != 1) |
| 454 | error = 1; | 454 | error = 1; |
| 455 | DEBUG1(printk("%s(): Mapped sense buffer %p at %x\n", __FUNCTION__, pcmd->sense_buffer, cmdp->saved_dma_handle)); | 455 | DEBUG1(printk("%s(): Mapped sense buffer %p at %x\n", __func__, pcmd->sense_buffer, cmdp->saved_dma_handle)); |
| 456 | /* Map SG list */ | 456 | /* Map SG list */ |
| 457 | } else if (scsi_sg_count(pcmd)) { | 457 | } else if (scsi_sg_count(pcmd)) { |
| 458 | int nseg; | 458 | int nseg; |
| @@ -466,7 +466,7 @@ static int dc390_pci_map (struct dc390_srb* pSRB) | |||
| 466 | if (nseg < 0) | 466 | if (nseg < 0) |
| 467 | error = 1; | 467 | error = 1; |
| 468 | DEBUG1(printk("%s(): Mapped SG %p with %d (%d) elements\n",\ | 468 | DEBUG1(printk("%s(): Mapped SG %p with %d (%d) elements\n",\ |
| 469 | __FUNCTION__, scsi_sglist(pcmd), nseg, scsi_sg_count(pcmd))); | 469 | __func__, scsi_sglist(pcmd), nseg, scsi_sg_count(pcmd))); |
| 470 | /* Map single segment */ | 470 | /* Map single segment */ |
| 471 | } else | 471 | } else |
| 472 | pSRB->SGcount = 0; | 472 | pSRB->SGcount = 0; |
| @@ -483,11 +483,11 @@ static void dc390_pci_unmap (struct dc390_srb* pSRB) | |||
| 483 | 483 | ||
| 484 | if (pSRB->SRBFlag) { | 484 | if (pSRB->SRBFlag) { |
| 485 | pci_unmap_sg(pdev, &pSRB->Segmentx, 1, DMA_FROM_DEVICE); | 485 | pci_unmap_sg(pdev, &pSRB->Segmentx, 1, DMA_FROM_DEVICE); |
| 486 | DEBUG1(printk("%s(): Unmapped sense buffer at %x\n", __FUNCTION__, cmdp->saved_dma_handle)); | 486 | DEBUG1(printk("%s(): Unmapped sense buffer at %x\n", __func__, cmdp->saved_dma_handle)); |
| 487 | } else { | 487 | } else { |
| 488 | scsi_dma_unmap(pcmd); | 488 | scsi_dma_unmap(pcmd); |
| 489 | DEBUG1(printk("%s(): Unmapped SG at %p with %d elements\n", | 489 | DEBUG1(printk("%s(): Unmapped SG at %p with %d elements\n", |
| 490 | __FUNCTION__, scsi_sglist(pcmd), scsi_sg_count(pcmd))); | 490 | __func__, scsi_sglist(pcmd), scsi_sg_count(pcmd))); |
| 491 | } | 491 | } |
| 492 | } | 492 | } |
| 493 | 493 | ||
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c index c975c01b3a02..d4c13561f4a6 100644 --- a/drivers/scsi/wd7000.c +++ b/drivers/scsi/wd7000.c | |||
| @@ -148,7 +148,7 @@ | |||
| 148 | * | 148 | * |
| 149 | * 2002/10/04 - Alan Cox <alan@redhat.com> | 149 | * 2002/10/04 - Alan Cox <alan@redhat.com> |
| 150 | * | 150 | * |
| 151 | * Use dev_id for interrupts, kill __FUNCTION__ pasting | 151 | * Use dev_id for interrupts, kill __func__ pasting |
| 152 | * Add a lock for the scb pool, clean up all other cli/sti usage stuff | 152 | * Add a lock for the scb pool, clean up all other cli/sti usage stuff |
| 153 | * Use the adapter lock for the other places we had the cli's | 153 | * Use the adapter lock for the other places we had the cli's |
| 154 | * | 154 | * |
| @@ -640,12 +640,12 @@ static int __init wd7000_setup(char *str) | |||
| 640 | (void) get_options(str, ARRAY_SIZE(ints), ints); | 640 | (void) get_options(str, ARRAY_SIZE(ints), ints); |
| 641 | 641 | ||
| 642 | if (wd7000_card_num >= NUM_CONFIGS) { | 642 | if (wd7000_card_num >= NUM_CONFIGS) { |
| 643 | printk(KERN_ERR "%s: Too many \"wd7000=\" configurations in " "command line!\n", __FUNCTION__); | 643 | printk(KERN_ERR "%s: Too many \"wd7000=\" configurations in " "command line!\n", __func__); |
| 644 | return 0; | 644 | return 0; |
| 645 | } | 645 | } |
| 646 | 646 | ||
| 647 | if ((ints[0] < 3) || (ints[0] > 5)) { | 647 | if ((ints[0] < 3) || (ints[0] > 5)) { |
| 648 | printk(KERN_ERR "%s: Error in command line! " "Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>" "[,<BUS_OFF>]]\n", __FUNCTION__); | 648 | printk(KERN_ERR "%s: Error in command line! " "Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>" "[,<BUS_OFF>]]\n", __func__); |
| 649 | } else { | 649 | } else { |
| 650 | for (i = 0; i < NUM_IRQS; i++) | 650 | for (i = 0; i < NUM_IRQS; i++) |
| 651 | if (ints[1] == wd7000_irq[i]) | 651 | if (ints[1] == wd7000_irq[i]) |
| @@ -1642,7 +1642,7 @@ static int wd7000_biosparam(struct scsi_device *sdev, | |||
| 1642 | ip[2] = info[2]; | 1642 | ip[2] = info[2]; |
| 1643 | 1643 | ||
| 1644 | if (info[0] == 255) | 1644 | if (info[0] == 255) |
| 1645 | printk(KERN_INFO "%s: current partition table is " "using extended translation.\n", __FUNCTION__); | 1645 | printk(KERN_INFO "%s: current partition table is " "using extended translation.\n", __func__); |
| 1646 | } | 1646 | } |
| 1647 | } | 1647 | } |
| 1648 | 1648 | ||
diff --git a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c index 4b5f908d35c3..3c4a300494a4 100644 --- a/drivers/scsi/zalon.c +++ b/drivers/scsi/zalon.c | |||
| @@ -68,11 +68,11 @@ lasi_scsi_clock(void * hpa, int defaultclock) | |||
| 68 | if (status == PDC_RET_OK) { | 68 | if (status == PDC_RET_OK) { |
| 69 | clock = (int) pdc_result[16]; | 69 | clock = (int) pdc_result[16]; |
| 70 | } else { | 70 | } else { |
| 71 | printk(KERN_WARNING "%s: pdc_iodc_read returned %d\n", __FUNCTION__, status); | 71 | printk(KERN_WARNING "%s: pdc_iodc_read returned %d\n", __func__, status); |
| 72 | clock = defaultclock; | 72 | clock = defaultclock; |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | printk(KERN_DEBUG "%s: SCSI clock %d\n", __FUNCTION__, clock); | 75 | printk(KERN_DEBUG "%s: SCSI clock %d\n", __func__, clock); |
| 76 | return clock; | 76 | return clock; |
| 77 | } | 77 | } |
| 78 | #endif | 78 | #endif |
| @@ -108,13 +108,13 @@ zalon_probe(struct parisc_device *dev) | |||
| 108 | */ | 108 | */ |
| 109 | dev->irq = gsc_alloc_irq(&gsc_irq); | 109 | dev->irq = gsc_alloc_irq(&gsc_irq); |
| 110 | 110 | ||
| 111 | printk(KERN_INFO "%s: Zalon version %d, IRQ %d\n", __FUNCTION__, | 111 | printk(KERN_INFO "%s: Zalon version %d, IRQ %d\n", __func__, |
| 112 | zalon_vers, dev->irq); | 112 | zalon_vers, dev->irq); |
| 113 | 113 | ||
| 114 | __raw_writel(gsc_irq.txn_addr | gsc_irq.txn_data, zalon + IO_MODULE_EIM); | 114 | __raw_writel(gsc_irq.txn_addr | gsc_irq.txn_data, zalon + IO_MODULE_EIM); |
| 115 | 115 | ||
| 116 | if (zalon_vers == 0) | 116 | if (zalon_vers == 0) |
| 117 | printk(KERN_WARNING "%s: Zalon 1.1 or earlier\n", __FUNCTION__); | 117 | printk(KERN_WARNING "%s: Zalon 1.1 or earlier\n", __func__); |
| 118 | 118 | ||
| 119 | memset(&device, 0, sizeof(struct ncr_device)); | 119 | memset(&device, 0, sizeof(struct ncr_device)); |
| 120 | 120 | ||
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index e81d59d78910..0c7165660853 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c | |||
| @@ -313,14 +313,14 @@ atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer) | |||
| 313 | xfer->tx_dma = dma_map_single(dev, | 313 | xfer->tx_dma = dma_map_single(dev, |
| 314 | (void *) xfer->tx_buf, xfer->len, | 314 | (void *) xfer->tx_buf, xfer->len, |
| 315 | DMA_TO_DEVICE); | 315 | DMA_TO_DEVICE); |
| 316 | if (dma_mapping_error(xfer->tx_dma)) | 316 | if (dma_mapping_error(dev, xfer->tx_dma)) |
| 317 | return -ENOMEM; | 317 | return -ENOMEM; |
| 318 | } | 318 | } |
| 319 | if (xfer->rx_buf) { | 319 | if (xfer->rx_buf) { |
| 320 | xfer->rx_dma = dma_map_single(dev, | 320 | xfer->rx_dma = dma_map_single(dev, |
| 321 | xfer->rx_buf, xfer->len, | 321 | xfer->rx_buf, xfer->len, |
| 322 | DMA_FROM_DEVICE); | 322 | DMA_FROM_DEVICE); |
| 323 | if (dma_mapping_error(xfer->rx_dma)) { | 323 | if (dma_mapping_error(dev, xfer->rx_dma)) { |
| 324 | if (xfer->tx_buf) | 324 | if (xfer->tx_buf) |
| 325 | dma_unmap_single(dev, | 325 | dma_unmap_single(dev, |
| 326 | xfer->tx_dma, xfer->len, | 326 | xfer->tx_dma, xfer->len, |
diff --git a/drivers/spi/au1550_spi.c b/drivers/spi/au1550_spi.c index 9149689c79d9..87b73e0169c5 100644 --- a/drivers/spi/au1550_spi.c +++ b/drivers/spi/au1550_spi.c | |||
| @@ -334,7 +334,7 @@ static int au1550_spi_dma_rxtmp_alloc(struct au1550_spi *hw, unsigned size) | |||
| 334 | hw->dma_rx_tmpbuf_size = size; | 334 | hw->dma_rx_tmpbuf_size = size; |
| 335 | hw->dma_rx_tmpbuf_addr = dma_map_single(hw->dev, hw->dma_rx_tmpbuf, | 335 | hw->dma_rx_tmpbuf_addr = dma_map_single(hw->dev, hw->dma_rx_tmpbuf, |
| 336 | size, DMA_FROM_DEVICE); | 336 | size, DMA_FROM_DEVICE); |
| 337 | if (dma_mapping_error(hw->dma_rx_tmpbuf_addr)) { | 337 | if (dma_mapping_error(hw->dev, hw->dma_rx_tmpbuf_addr)) { |
| 338 | kfree(hw->dma_rx_tmpbuf); | 338 | kfree(hw->dma_rx_tmpbuf); |
| 339 | hw->dma_rx_tmpbuf = 0; | 339 | hw->dma_rx_tmpbuf = 0; |
| 340 | hw->dma_rx_tmpbuf_size = 0; | 340 | hw->dma_rx_tmpbuf_size = 0; |
| @@ -378,7 +378,7 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t) | |||
| 378 | dma_rx_addr = dma_map_single(hw->dev, | 378 | dma_rx_addr = dma_map_single(hw->dev, |
| 379 | (void *)t->rx_buf, | 379 | (void *)t->rx_buf, |
| 380 | t->len, DMA_FROM_DEVICE); | 380 | t->len, DMA_FROM_DEVICE); |
| 381 | if (dma_mapping_error(dma_rx_addr)) | 381 | if (dma_mapping_error(hw->dev, dma_rx_addr)) |
| 382 | dev_err(hw->dev, "rx dma map error\n"); | 382 | dev_err(hw->dev, "rx dma map error\n"); |
| 383 | } | 383 | } |
| 384 | } else { | 384 | } else { |
| @@ -401,7 +401,7 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t) | |||
| 401 | dma_tx_addr = dma_map_single(hw->dev, | 401 | dma_tx_addr = dma_map_single(hw->dev, |
| 402 | (void *)t->tx_buf, | 402 | (void *)t->tx_buf, |
| 403 | t->len, DMA_TO_DEVICE); | 403 | t->len, DMA_TO_DEVICE); |
| 404 | if (dma_mapping_error(dma_tx_addr)) | 404 | if (dma_mapping_error(hw->dev, dma_tx_addr)) |
| 405 | dev_err(hw->dev, "tx dma map error\n"); | 405 | dev_err(hw->dev, "tx dma map error\n"); |
| 406 | } | 406 | } |
| 407 | } else { | 407 | } else { |
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c index b1cc148036c1..f6f987bb71ca 100644 --- a/drivers/spi/omap2_mcspi.c +++ b/drivers/spi/omap2_mcspi.c | |||
| @@ -836,7 +836,7 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m) | |||
| 836 | if (tx_buf != NULL) { | 836 | if (tx_buf != NULL) { |
| 837 | t->tx_dma = dma_map_single(&spi->dev, (void *) tx_buf, | 837 | t->tx_dma = dma_map_single(&spi->dev, (void *) tx_buf, |
| 838 | len, DMA_TO_DEVICE); | 838 | len, DMA_TO_DEVICE); |
| 839 | if (dma_mapping_error(t->tx_dma)) { | 839 | if (dma_mapping_error(&spi->dev, t->tx_dma)) { |
| 840 | dev_dbg(&spi->dev, "dma %cX %d bytes error\n", | 840 | dev_dbg(&spi->dev, "dma %cX %d bytes error\n", |
| 841 | 'T', len); | 841 | 'T', len); |
| 842 | return -EINVAL; | 842 | return -EINVAL; |
| @@ -845,7 +845,7 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m) | |||
| 845 | if (rx_buf != NULL) { | 845 | if (rx_buf != NULL) { |
| 846 | t->rx_dma = dma_map_single(&spi->dev, rx_buf, t->len, | 846 | t->rx_dma = dma_map_single(&spi->dev, rx_buf, t->len, |
| 847 | DMA_FROM_DEVICE); | 847 | DMA_FROM_DEVICE); |
| 848 | if (dma_mapping_error(t->rx_dma)) { | 848 | if (dma_mapping_error(&spi->dev, t->rx_dma)) { |
| 849 | dev_dbg(&spi->dev, "dma %cX %d bytes error\n", | 849 | dev_dbg(&spi->dev, "dma %cX %d bytes error\n", |
| 850 | 'R', len); | 850 | 'R', len); |
| 851 | if (tx_buf != NULL) | 851 | if (tx_buf != NULL) |
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 0c452c46ab07..067299d6d192 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c | |||
| @@ -353,7 +353,7 @@ static int map_dma_buffers(struct driver_data *drv_data) | |||
| 353 | drv_data->rx_dma = dma_map_single(dev, drv_data->rx, | 353 | drv_data->rx_dma = dma_map_single(dev, drv_data->rx, |
| 354 | drv_data->rx_map_len, | 354 | drv_data->rx_map_len, |
| 355 | DMA_FROM_DEVICE); | 355 | DMA_FROM_DEVICE); |
| 356 | if (dma_mapping_error(drv_data->rx_dma)) | 356 | if (dma_mapping_error(dev, drv_data->rx_dma)) |
| 357 | return 0; | 357 | return 0; |
| 358 | 358 | ||
| 359 | /* Stream map the tx buffer */ | 359 | /* Stream map the tx buffer */ |
| @@ -361,7 +361,7 @@ static int map_dma_buffers(struct driver_data *drv_data) | |||
| 361 | drv_data->tx_map_len, | 361 | drv_data->tx_map_len, |
| 362 | DMA_TO_DEVICE); | 362 | DMA_TO_DEVICE); |
| 363 | 363 | ||
| 364 | if (dma_mapping_error(drv_data->tx_dma)) { | 364 | if (dma_mapping_error(dev, drv_data->tx_dma)) { |
| 365 | dma_unmap_single(dev, drv_data->rx_dma, | 365 | dma_unmap_single(dev, drv_data->rx_dma, |
| 366 | drv_data->rx_map_len, DMA_FROM_DEVICE); | 366 | drv_data->rx_map_len, DMA_FROM_DEVICE); |
| 367 | return 0; | 367 | return 0; |
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c index 54ac7bea5f8c..6fb77fcc4971 100644 --- a/drivers/spi/spi_imx.c +++ b/drivers/spi/spi_imx.c | |||
| @@ -491,7 +491,7 @@ static int map_dma_buffers(struct driver_data *drv_data) | |||
| 491 | buf, | 491 | buf, |
| 492 | drv_data->tx_map_len, | 492 | drv_data->tx_map_len, |
| 493 | DMA_TO_DEVICE); | 493 | DMA_TO_DEVICE); |
| 494 | if (dma_mapping_error(drv_data->tx_dma)) | 494 | if (dma_mapping_error(dev, drv_data->tx_dma)) |
| 495 | return -1; | 495 | return -1; |
| 496 | 496 | ||
| 497 | drv_data->tx_dma_needs_unmap = 1; | 497 | drv_data->tx_dma_needs_unmap = 1; |
| @@ -516,7 +516,7 @@ static int map_dma_buffers(struct driver_data *drv_data) | |||
| 516 | buf, | 516 | buf, |
| 517 | drv_data->len, | 517 | drv_data->len, |
| 518 | DMA_FROM_DEVICE); | 518 | DMA_FROM_DEVICE); |
| 519 | if (dma_mapping_error(drv_data->rx_dma)) | 519 | if (dma_mapping_error(dev, drv_data->rx_dma)) |
| 520 | return -1; | 520 | return -1; |
| 521 | drv_data->rx_dma_needs_unmap = 1; | 521 | drv_data->rx_dma_needs_unmap = 1; |
| 522 | } | 522 | } |
| @@ -534,7 +534,7 @@ static int map_dma_buffers(struct driver_data *drv_data) | |||
| 534 | buf, | 534 | buf, |
| 535 | drv_data->tx_map_len, | 535 | drv_data->tx_map_len, |
| 536 | DMA_TO_DEVICE); | 536 | DMA_TO_DEVICE); |
| 537 | if (dma_mapping_error(drv_data->tx_dma)) { | 537 | if (dma_mapping_error(dev, drv_data->tx_dma)) { |
| 538 | if (drv_data->rx_dma) { | 538 | if (drv_data->rx_dma) { |
| 539 | dma_unmap_single(dev, | 539 | dma_unmap_single(dev, |
| 540 | drv_data->rx_dma, | 540 | drv_data->rx_dma, |
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 5e3e4e9b6c77..1f715436d6d3 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c | |||
| @@ -87,7 +87,7 @@ struct mon_reader_text { | |||
| 87 | 87 | ||
| 88 | static struct dentry *mon_dir; /* Usually /sys/kernel/debug/usbmon */ | 88 | static struct dentry *mon_dir; /* Usually /sys/kernel/debug/usbmon */ |
| 89 | 89 | ||
| 90 | static void mon_text_ctor(struct kmem_cache *, void *); | 90 | static void mon_text_ctor(void *); |
| 91 | 91 | ||
| 92 | struct mon_text_ptr { | 92 | struct mon_text_ptr { |
| 93 | int cnt, limit; | 93 | int cnt, limit; |
| @@ -720,7 +720,7 @@ void mon_text_del(struct mon_bus *mbus) | |||
| 720 | /* | 720 | /* |
| 721 | * Slab interface: constructor. | 721 | * Slab interface: constructor. |
| 722 | */ | 722 | */ |
| 723 | static void mon_text_ctor(struct kmem_cache *slab, void *mem) | 723 | static void mon_text_ctor(void *mem) |
| 724 | { | 724 | { |
| 725 | /* | 725 | /* |
| 726 | * Nothing to initialize. No, really! | 726 | * Nothing to initialize. No, really! |
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 832a5a4f3cb3..cd9a2e138c8b 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c | |||
| @@ -651,15 +651,17 @@ static int ipaq_open(struct tty_struct *tty, | |||
| 651 | */ | 651 | */ |
| 652 | 652 | ||
| 653 | kfree(port->bulk_in_buffer); | 653 | kfree(port->bulk_in_buffer); |
| 654 | kfree(port->bulk_out_buffer); | ||
| 655 | /* make sure the generic serial code knows */ | ||
| 656 | port->bulk_out_buffer = NULL; | ||
| 657 | |||
| 654 | port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL); | 658 | port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL); |
| 655 | if (port->bulk_in_buffer == NULL) { | 659 | if (port->bulk_in_buffer == NULL) |
| 656 | port->bulk_out_buffer = NULL; /* prevent double free */ | ||
| 657 | goto enomem; | 660 | goto enomem; |
| 658 | } | ||
| 659 | 661 | ||
| 660 | kfree(port->bulk_out_buffer); | ||
| 661 | port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL); | 662 | port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL); |
| 662 | if (port->bulk_out_buffer == NULL) { | 663 | if (port->bulk_out_buffer == NULL) { |
| 664 | /* the buffer is useless, free it */ | ||
| 663 | kfree(port->bulk_in_buffer); | 665 | kfree(port->bulk_in_buffer); |
| 664 | port->bulk_in_buffer = NULL; | 666 | port->bulk_in_buffer = NULL; |
| 665 | goto enomem; | 667 | goto enomem; |
diff --git a/drivers/video/am200epd.c b/drivers/video/am200epd.c index 51e26c1f5e8b..32dd85126931 100644 --- a/drivers/video/am200epd.c +++ b/drivers/video/am200epd.c | |||
| @@ -221,7 +221,7 @@ static int am200_setup_irq(struct fb_info *info) | |||
| 221 | return retval; | 221 | return retval; |
| 222 | } | 222 | } |
| 223 | 223 | ||
| 224 | return set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQT_FALLING); | 224 | return set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQ_TYPE_EDGE_FALLING); |
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | static void am200_set_rst(struct metronomefb_par *par, int state) | 227 | static void am200_set_rst(struct metronomefb_par *par, int state) |
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index a11cc2fdd4cd..4055dbdd1b42 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c | |||
| @@ -370,7 +370,7 @@ static const struct consw sti_con = { | |||
| 370 | 370 | ||
| 371 | 371 | ||
| 372 | 372 | ||
| 373 | int __init sticonsole_init(void) | 373 | static int __init sticonsole_init(void) |
| 374 | { | 374 | { |
| 375 | /* already initialized ? */ | 375 | /* already initialized ? */ |
| 376 | if (sticon_sti) | 376 | if (sticon_sti) |
diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c index e9ab657f0bb7..d7822af0e00a 100644 --- a/drivers/video/console/sticore.c +++ b/drivers/video/console/sticore.c | |||
| @@ -29,7 +29,7 @@ | |||
| 29 | 29 | ||
| 30 | #define STI_DRIVERVERSION "Version 0.9a" | 30 | #define STI_DRIVERVERSION "Version 0.9a" |
| 31 | 31 | ||
| 32 | struct sti_struct *default_sti __read_mostly; | 32 | static struct sti_struct *default_sti __read_mostly; |
| 33 | 33 | ||
| 34 | /* number of STI ROMS found and their ptrs to each struct */ | 34 | /* number of STI ROMS found and their ptrs to each struct */ |
| 35 | static int num_sti_roms __read_mostly; | 35 | static int num_sti_roms __read_mostly; |
| @@ -68,8 +68,7 @@ static const struct sti_init_flags default_init_flags = { | |||
| 68 | .init_cmap_tx = 1, | 68 | .init_cmap_tx = 1, |
| 69 | }; | 69 | }; |
| 70 | 70 | ||
| 71 | int | 71 | static int sti_init_graph(struct sti_struct *sti) |
| 72 | sti_init_graph(struct sti_struct *sti) | ||
| 73 | { | 72 | { |
| 74 | struct sti_init_inptr_ext inptr_ext = { 0, }; | 73 | struct sti_init_inptr_ext inptr_ext = { 0, }; |
| 75 | struct sti_init_inptr inptr = { | 74 | struct sti_init_inptr inptr = { |
| @@ -100,8 +99,7 @@ static const struct sti_conf_flags default_conf_flags = { | |||
| 100 | .wait = STI_WAIT, | 99 | .wait = STI_WAIT, |
| 101 | }; | 100 | }; |
| 102 | 101 | ||
| 103 | void | 102 | static void sti_inq_conf(struct sti_struct *sti) |
| 104 | sti_inq_conf(struct sti_struct *sti) | ||
| 105 | { | 103 | { |
| 106 | struct sti_conf_inptr inptr = { 0, }; | 104 | struct sti_conf_inptr inptr = { 0, }; |
| 107 | unsigned long flags; | 105 | unsigned long flags; |
| @@ -237,8 +235,8 @@ static void sti_flush(unsigned long start, unsigned long end) | |||
| 237 | flush_icache_range(start, end); | 235 | flush_icache_range(start, end); |
| 238 | } | 236 | } |
| 239 | 237 | ||
| 240 | void __devinit | 238 | static void __devinit sti_rom_copy(unsigned long base, unsigned long count, |
| 241 | sti_rom_copy(unsigned long base, unsigned long count, void *dest) | 239 | void *dest) |
| 242 | { | 240 | { |
| 243 | unsigned long dest_start = (unsigned long) dest; | 241 | unsigned long dest_start = (unsigned long) dest; |
| 244 | 242 | ||
| @@ -478,8 +476,8 @@ sti_init_glob_cfg(struct sti_struct *sti, | |||
| 478 | } | 476 | } |
| 479 | 477 | ||
| 480 | #ifdef CONFIG_FB | 478 | #ifdef CONFIG_FB |
| 481 | struct sti_cooked_font * __devinit | 479 | static struct sti_cooked_font __devinit |
| 482 | sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name) | 480 | *sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name) |
| 483 | { | 481 | { |
| 484 | const struct font_desc *fbfont; | 482 | const struct font_desc *fbfont; |
| 485 | unsigned int size, bpc; | 483 | unsigned int size, bpc; |
| @@ -534,16 +532,16 @@ sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name) | |||
| 534 | return cooked_font; | 532 | return cooked_font; |
| 535 | } | 533 | } |
| 536 | #else | 534 | #else |
| 537 | struct sti_cooked_font * __devinit | 535 | static struct sti_cooked_font __devinit |
| 538 | sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name) | 536 | *sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name) |
| 539 | { | 537 | { |
| 540 | return NULL; | 538 | return NULL; |
| 541 | } | 539 | } |
| 542 | #endif | 540 | #endif |
| 543 | 541 | ||
| 544 | struct sti_cooked_font * __devinit | 542 | static struct sti_cooked_font __devinit |
| 545 | sti_select_font(struct sti_cooked_rom *rom, | 543 | *sti_select_font(struct sti_cooked_rom *rom, |
| 546 | int (*search_font_fnc) (struct sti_cooked_rom *,int,int) ) | 544 | int (*search_font_fnc)(struct sti_cooked_rom *, int, int)) |
| 547 | { | 545 | { |
| 548 | struct sti_cooked_font *font; | 546 | struct sti_cooked_font *font; |
| 549 | int i; | 547 | int i; |
| @@ -707,8 +705,7 @@ sti_get_bmode_rom (unsigned long address) | |||
| 707 | return raw; | 705 | return raw; |
| 708 | } | 706 | } |
| 709 | 707 | ||
| 710 | struct sti_rom * __devinit | 708 | static struct sti_rom __devinit *sti_get_wmode_rom(unsigned long address) |
| 711 | sti_get_wmode_rom (unsigned long address) | ||
| 712 | { | 709 | { |
| 713 | struct sti_rom *raw; | 710 | struct sti_rom *raw; |
| 714 | unsigned long size; | 711 | unsigned long size; |
| @@ -723,8 +720,8 @@ sti_get_wmode_rom (unsigned long address) | |||
| 723 | return raw; | 720 | return raw; |
| 724 | } | 721 | } |
| 725 | 722 | ||
| 726 | int __devinit | 723 | static int __devinit sti_read_rom(int wordmode, struct sti_struct *sti, |
| 727 | sti_read_rom(int wordmode, struct sti_struct *sti, unsigned long address) | 724 | unsigned long address) |
| 728 | { | 725 | { |
| 729 | struct sti_cooked_rom *cooked; | 726 | struct sti_cooked_rom *cooked; |
| 730 | struct sti_rom *raw = NULL; | 727 | struct sti_rom *raw = NULL; |
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 5d84b3431098..6b487801eeae 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c | |||
| @@ -35,7 +35,6 @@ | |||
| 35 | #include <linux/device.h> | 35 | #include <linux/device.h> |
| 36 | #include <linux/efi.h> | 36 | #include <linux/efi.h> |
| 37 | #include <linux/fb.h> | 37 | #include <linux/fb.h> |
| 38 | #include <linux/major.h> | ||
| 39 | 38 | ||
| 40 | #include <asm/fb.h> | 39 | #include <asm/fb.h> |
| 41 | 40 | ||
diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c index aa8c714d6245..b790ddff76f9 100644 --- a/drivers/video/macfb.c +++ b/drivers/video/macfb.c | |||
| @@ -596,7 +596,7 @@ static struct fb_ops macfb_ops = { | |||
| 596 | .fb_imageblit = cfb_imageblit, | 596 | .fb_imageblit = cfb_imageblit, |
| 597 | }; | 597 | }; |
| 598 | 598 | ||
| 599 | void __init macfb_setup(char *options) | 599 | static void __init macfb_setup(char *options) |
| 600 | { | 600 | { |
| 601 | char *this_opt; | 601 | char *this_opt; |
| 602 | 602 | ||
diff --git a/drivers/video/omap/sossi.c b/drivers/video/omap/sossi.c index 81dbcf53cf0e..fafd0f26b90f 100644 --- a/drivers/video/omap/sossi.c +++ b/drivers/video/omap/sossi.c | |||
| @@ -646,7 +646,7 @@ static int sossi_init(struct omapfb_device *fbdev) | |||
| 646 | sossi_write_reg(SOSSI_INIT1_REG, l); | 646 | sossi_write_reg(SOSSI_INIT1_REG, l); |
| 647 | 647 | ||
| 648 | if ((r = request_irq(INT_1610_SoSSI_MATCH, sossi_match_irq, | 648 | if ((r = request_irq(INT_1610_SoSSI_MATCH, sossi_match_irq, |
| 649 | IRQT_FALLING, | 649 | IRQ_TYPE_EDGE_FALLING, |
| 650 | "sossi_match", sossi.fbdev->dev)) < 0) { | 650 | "sossi_match", sossi.fbdev->dev)) < 0) { |
| 651 | dev_err(sossi.fbdev->dev, "can't get SoSSI match IRQ\n"); | 651 | dev_err(sossi.fbdev->dev, "can't get SoSSI match IRQ\n"); |
| 652 | goto err; | 652 | goto err; |
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 2b707a8ce5de..69de2fed6c58 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c | |||
| @@ -1336,7 +1336,7 @@ static int __devinit pxafb_map_video_memory(struct pxafb_info *fbi) | |||
| 1336 | fbi->dma_buff_phys = fbi->map_dma; | 1336 | fbi->dma_buff_phys = fbi->map_dma; |
| 1337 | fbi->palette_cpu = (u16 *) fbi->dma_buff->palette; | 1337 | fbi->palette_cpu = (u16 *) fbi->dma_buff->palette; |
| 1338 | 1338 | ||
| 1339 | pr_debug("pxafb: palette_mem_size = 0x%08lx\n", fbi->palette_size*sizeof(u16)); | 1339 | pr_debug("pxafb: palette_mem_size = 0x%08x\n", fbi->palette_size*sizeof(u16)); |
| 1340 | 1340 | ||
| 1341 | #ifdef CONFIG_FB_PXA_SMARTPANEL | 1341 | #ifdef CONFIG_FB_PXA_SMARTPANEL |
| 1342 | fbi->smart_cmds = (uint16_t *) fbi->dma_buff->cmd_buff; | 1342 | fbi->smart_cmds = (uint16_t *) fbi->dma_buff->cmd_buff; |
diff --git a/drivers/video/sticore.h b/drivers/video/sticore.h index 1a9a60c74be3..7fe5be4bc70e 100644 --- a/drivers/video/sticore.h +++ b/drivers/video/sticore.h | |||
| @@ -352,8 +352,6 @@ struct sti_struct *sti_get_rom(unsigned int index); /* 0: default sti */ | |||
| 352 | 352 | ||
| 353 | /* functions to call the STI ROM directly */ | 353 | /* functions to call the STI ROM directly */ |
| 354 | 354 | ||
| 355 | int sti_init_graph(struct sti_struct *sti); | ||
| 356 | void sti_inq_conf(struct sti_struct *sti); | ||
| 357 | void sti_putc(struct sti_struct *sti, int c, int y, int x); | 355 | void sti_putc(struct sti_struct *sti, int c, int y, int x); |
| 358 | void sti_set(struct sti_struct *sti, int src_y, int src_x, | 356 | void sti_set(struct sti_struct *sti, int src_y, int src_x, |
| 359 | int height, int width, u8 color); | 357 | int height, int width, u8 color); |
diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c index 598d35eff935..166481402412 100644 --- a/drivers/video/stifb.c +++ b/drivers/video/stifb.c | |||
| @@ -1078,8 +1078,7 @@ static struct fb_ops stifb_ops = { | |||
| 1078 | * Initialization | 1078 | * Initialization |
| 1079 | */ | 1079 | */ |
| 1080 | 1080 | ||
| 1081 | int __init | 1081 | static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref) |
| 1082 | stifb_init_fb(struct sti_struct *sti, int bpp_pref) | ||
| 1083 | { | 1082 | { |
| 1084 | struct fb_fix_screeninfo *fix; | 1083 | struct fb_fix_screeninfo *fix; |
| 1085 | struct fb_var_screeninfo *var; | 1084 | struct fb_var_screeninfo *var; |
| @@ -1315,8 +1314,7 @@ static int stifb_disabled __initdata; | |||
| 1315 | int __init | 1314 | int __init |
| 1316 | stifb_setup(char *options); | 1315 | stifb_setup(char *options); |
| 1317 | 1316 | ||
| 1318 | int __init | 1317 | static int __init stifb_init(void) |
| 1319 | stifb_init(void) | ||
| 1320 | { | 1318 | { |
| 1321 | struct sti_struct *sti; | 1319 | struct sti_struct *sti; |
| 1322 | struct sti_struct *def_sti; | 1320 | struct sti_struct *def_sti; |
