1b5e47729SStefan Richter /* 2b5e47729SStefan Richter * nosy - Snoop mode driver for TI PCILynx 1394 controllers 3b5e47729SStefan Richter * Copyright (C) 2002-2007 Kristian Høgsberg 428646821SStefan Richter * 528646821SStefan Richter * This program is free software; you can redistribute it and/or modify 628646821SStefan Richter * it under the terms of the GNU General Public License as published by 728646821SStefan Richter * the Free Software Foundation; either version 2 of the License, or 828646821SStefan Richter * (at your option) any later version. 928646821SStefan Richter * 1028646821SStefan Richter * This program is distributed in the hope that it will be useful, 1128646821SStefan Richter * but WITHOUT ANY WARRANTY; without even the implied warranty of 1228646821SStefan Richter * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1328646821SStefan Richter * GNU General Public License for more details. 1428646821SStefan Richter * 1528646821SStefan Richter * You should have received a copy of the GNU General Public License 1628646821SStefan Richter * along with this program; if not, write to the Free Software Foundation, 1728646821SStefan Richter * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 1828646821SStefan Richter */ 1928646821SStefan Richter 207429b17dSStefan Richter #include <linux/device.h> 2128646821SStefan Richter #include <linux/errno.h> 2228646821SStefan Richter #include <linux/fs.h> 23b5e47729SStefan Richter #include <linux/init.h> 24b5e47729SStefan Richter #include <linux/interrupt.h> 25b5e47729SStefan Richter #include <linux/io.h> 26b5e47729SStefan Richter #include <linux/kernel.h> 27424d66ceSStefan Richter #include <linux/kref.h> 2828646821SStefan Richter #include <linux/miscdevice.h> 29b5e47729SStefan Richter #include <linux/module.h> 30424d66ceSStefan Richter #include <linux/mutex.h> 31b5e47729SStefan Richter #include <linux/pci.h> 32b5e47729SStefan Richter #include <linux/poll.h> 33b5e47729SStefan Richter #include <linux/sched.h> /* required for linux/wait.h */ 34b5e47729SStefan Richter #include <linux/slab.h> 35b5e47729SStefan Richter #include <linux/spinlock.h> 36b5e47729SStefan Richter #include <linux/timex.h> 37b5e47729SStefan Richter #include <linux/uaccess.h> 38b5e47729SStefan Richter #include <linux/wait.h> 39e894d1d7Ssantosh nayak #include <linux/dma-mapping.h> 4060063497SArun Sharma #include <linux/atomic.h> 41b5e47729SStefan Richter #include <asm/byteorder.h> 4228646821SStefan Richter 4328646821SStefan Richter #include "nosy.h" 4428646821SStefan Richter #include "nosy-user.h" 4528646821SStefan Richter 4628646821SStefan Richter #define TCODE_PHY_PACKET 0x10 4728646821SStefan Richter #define PCI_DEVICE_ID_TI_PCILYNX 0x8000 4828646821SStefan Richter 49b5e47729SStefan Richter static char driver_name[] = KBUILD_MODNAME; 5028646821SStefan Richter 5128646821SStefan Richter /* this is the physical layout of a PCL, its size is 128 bytes */ 5228646821SStefan Richter struct pcl { 53fd8c8d46SStefan Richter __le32 next; 54fd8c8d46SStefan Richter __le32 async_error_next; 5528646821SStefan Richter u32 user_data; 56fd8c8d46SStefan Richter __le32 pcl_status; 57fd8c8d46SStefan Richter __le32 remaining_transfer_count; 58fd8c8d46SStefan Richter __le32 next_data_buffer; 5928646821SStefan Richter struct { 60fd8c8d46SStefan Richter __le32 control; 61fd8c8d46SStefan Richter __le32 pointer; 62fd8c8d46SStefan Richter } buffer[13]; 63fd8c8d46SStefan Richter }; 6428646821SStefan Richter 6528646821SStefan Richter struct packet { 66b5e47729SStefan Richter unsigned int length; 6728646821SStefan Richter char data[0]; 6828646821SStefan Richter }; 6928646821SStefan Richter 7028646821SStefan Richter struct packet_buffer { 7128646821SStefan Richter char *data; 7228646821SStefan Richter size_t capacity; 7328646821SStefan Richter long total_packet_count, lost_packet_count; 7428646821SStefan Richter atomic_t size; 7528646821SStefan Richter struct packet *head, *tail; 7628646821SStefan Richter wait_queue_head_t wait; 7728646821SStefan Richter }; 7828646821SStefan Richter 7928646821SStefan Richter struct pcilynx { 8028646821SStefan Richter struct pci_dev *pci_device; 81c89db7b8SStefan Richter __iomem char *registers; 8228646821SStefan Richter 8328646821SStefan Richter struct pcl *rcv_start_pcl, *rcv_pcl; 84fd8c8d46SStefan Richter __le32 *rcv_buffer; 8528646821SStefan Richter 8628646821SStefan Richter dma_addr_t rcv_start_pcl_bus, rcv_pcl_bus, rcv_buffer_bus; 8728646821SStefan Richter 8828646821SStefan Richter spinlock_t client_list_lock; 8928646821SStefan Richter struct list_head client_list; 9028646821SStefan Richter 9128646821SStefan Richter struct miscdevice misc; 92424d66ceSStefan Richter struct list_head link; 93424d66ceSStefan Richter struct kref kref; 9428646821SStefan Richter }; 9528646821SStefan Richter 96424d66ceSStefan Richter static inline struct pcilynx * 97424d66ceSStefan Richter lynx_get(struct pcilynx *lynx) 98424d66ceSStefan Richter { 99424d66ceSStefan Richter kref_get(&lynx->kref); 100424d66ceSStefan Richter 101424d66ceSStefan Richter return lynx; 102424d66ceSStefan Richter } 103424d66ceSStefan Richter 104424d66ceSStefan Richter static void 105424d66ceSStefan Richter lynx_release(struct kref *kref) 106424d66ceSStefan Richter { 107424d66ceSStefan Richter kfree(container_of(kref, struct pcilynx, kref)); 108424d66ceSStefan Richter } 109424d66ceSStefan Richter 110424d66ceSStefan Richter static inline void 111424d66ceSStefan Richter lynx_put(struct pcilynx *lynx) 112424d66ceSStefan Richter { 113424d66ceSStefan Richter kref_put(&lynx->kref, lynx_release); 114424d66ceSStefan Richter } 115424d66ceSStefan Richter 11628646821SStefan Richter struct client { 11728646821SStefan Richter struct pcilynx *lynx; 118c7b2a99cSStefan Richter u32 tcode_mask; 11928646821SStefan Richter struct packet_buffer buffer; 12028646821SStefan Richter struct list_head link; 12128646821SStefan Richter }; 12228646821SStefan Richter 123424d66ceSStefan Richter static DEFINE_MUTEX(card_mutex); 124424d66ceSStefan Richter static LIST_HEAD(card_list); 12528646821SStefan Richter 12628646821SStefan Richter static int 12728646821SStefan Richter packet_buffer_init(struct packet_buffer *buffer, size_t capacity) 12828646821SStefan Richter { 12928646821SStefan Richter buffer->data = kmalloc(capacity, GFP_KERNEL); 13028646821SStefan Richter if (buffer->data == NULL) 13128646821SStefan Richter return -ENOMEM; 13228646821SStefan Richter buffer->head = (struct packet *) buffer->data; 13328646821SStefan Richter buffer->tail = (struct packet *) buffer->data; 13428646821SStefan Richter buffer->capacity = capacity; 13528646821SStefan Richter buffer->lost_packet_count = 0; 13628646821SStefan Richter atomic_set(&buffer->size, 0); 13728646821SStefan Richter init_waitqueue_head(&buffer->wait); 13828646821SStefan Richter 13928646821SStefan Richter return 0; 14028646821SStefan Richter } 14128646821SStefan Richter 14228646821SStefan Richter static void 14328646821SStefan Richter packet_buffer_destroy(struct packet_buffer *buffer) 14428646821SStefan Richter { 14528646821SStefan Richter kfree(buffer->data); 14628646821SStefan Richter } 14728646821SStefan Richter 14828646821SStefan Richter static int 149c89db7b8SStefan Richter packet_buffer_get(struct client *client, char __user *data, size_t user_length) 15028646821SStefan Richter { 151424d66ceSStefan Richter struct packet_buffer *buffer = &client->buffer; 15228646821SStefan Richter size_t length; 15328646821SStefan Richter char *end; 15428646821SStefan Richter 15528646821SStefan Richter if (wait_event_interruptible(buffer->wait, 156424d66ceSStefan Richter atomic_read(&buffer->size) > 0) || 157424d66ceSStefan Richter list_empty(&client->lynx->link)) 15828646821SStefan Richter return -ERESTARTSYS; 15928646821SStefan Richter 160424d66ceSStefan Richter if (atomic_read(&buffer->size) == 0) 161424d66ceSStefan Richter return -ENODEV; 162424d66ceSStefan Richter 16328646821SStefan Richter /* FIXME: Check length <= user_length. */ 16428646821SStefan Richter 16528646821SStefan Richter end = buffer->data + buffer->capacity; 16628646821SStefan Richter length = buffer->head->length; 16728646821SStefan Richter 16828646821SStefan Richter if (&buffer->head->data[length] < end) { 16928646821SStefan Richter if (copy_to_user(data, buffer->head->data, length)) 17028646821SStefan Richter return -EFAULT; 17128646821SStefan Richter buffer->head = (struct packet *) &buffer->head->data[length]; 172b5e47729SStefan Richter } else { 17328646821SStefan Richter size_t split = end - buffer->head->data; 17428646821SStefan Richter 17528646821SStefan Richter if (copy_to_user(data, buffer->head->data, split)) 17628646821SStefan Richter return -EFAULT; 17728646821SStefan Richter if (copy_to_user(data + split, buffer->data, length - split)) 17828646821SStefan Richter return -EFAULT; 17928646821SStefan Richter buffer->head = (struct packet *) &buffer->data[length - split]; 18028646821SStefan Richter } 18128646821SStefan Richter 182b5e47729SStefan Richter /* 183b5e47729SStefan Richter * Decrease buffer->size as the last thing, since this is what 18428646821SStefan Richter * keeps the interrupt from overwriting the packet we are 185b5e47729SStefan Richter * retrieving from the buffer. 186b5e47729SStefan Richter */ 18728646821SStefan Richter atomic_sub(sizeof(struct packet) + length, &buffer->size); 18828646821SStefan Richter 18928646821SStefan Richter return length; 19028646821SStefan Richter } 19128646821SStefan Richter 19228646821SStefan Richter static void 19328646821SStefan Richter packet_buffer_put(struct packet_buffer *buffer, void *data, size_t length) 19428646821SStefan Richter { 19528646821SStefan Richter char *end; 19628646821SStefan Richter 19728646821SStefan Richter buffer->total_packet_count++; 19828646821SStefan Richter 19928646821SStefan Richter if (buffer->capacity < 20028646821SStefan Richter atomic_read(&buffer->size) + sizeof(struct packet) + length) { 20128646821SStefan Richter buffer->lost_packet_count++; 20228646821SStefan Richter return; 20328646821SStefan Richter } 20428646821SStefan Richter 20528646821SStefan Richter end = buffer->data + buffer->capacity; 20628646821SStefan Richter buffer->tail->length = length; 20728646821SStefan Richter 20828646821SStefan Richter if (&buffer->tail->data[length] < end) { 20928646821SStefan Richter memcpy(buffer->tail->data, data, length); 21028646821SStefan Richter buffer->tail = (struct packet *) &buffer->tail->data[length]; 211b5e47729SStefan Richter } else { 21228646821SStefan Richter size_t split = end - buffer->tail->data; 21328646821SStefan Richter 21428646821SStefan Richter memcpy(buffer->tail->data, data, split); 21528646821SStefan Richter memcpy(buffer->data, data + split, length - split); 21628646821SStefan Richter buffer->tail = (struct packet *) &buffer->data[length - split]; 21728646821SStefan Richter } 21828646821SStefan Richter 21928646821SStefan Richter /* Finally, adjust buffer size and wake up userspace reader. */ 22028646821SStefan Richter 22128646821SStefan Richter atomic_add(sizeof(struct packet) + length, &buffer->size); 22228646821SStefan Richter wake_up_interruptible(&buffer->wait); 22328646821SStefan Richter } 22428646821SStefan Richter 22528646821SStefan Richter static inline void 22628646821SStefan Richter reg_write(struct pcilynx *lynx, int offset, u32 data) 22728646821SStefan Richter { 22828646821SStefan Richter writel(data, lynx->registers + offset); 22928646821SStefan Richter } 23028646821SStefan Richter 23128646821SStefan Richter static inline u32 23228646821SStefan Richter reg_read(struct pcilynx *lynx, int offset) 23328646821SStefan Richter { 23428646821SStefan Richter return readl(lynx->registers + offset); 23528646821SStefan Richter } 23628646821SStefan Richter 23728646821SStefan Richter static inline void 23828646821SStefan Richter reg_set_bits(struct pcilynx *lynx, int offset, u32 mask) 23928646821SStefan Richter { 24028646821SStefan Richter reg_write(lynx, offset, (reg_read(lynx, offset) | mask)); 24128646821SStefan Richter } 24228646821SStefan Richter 243b5e47729SStefan Richter /* 244b5e47729SStefan Richter * Maybe the pcl programs could be set up to just append data instead 245b5e47729SStefan Richter * of using a whole packet. 246b5e47729SStefan Richter */ 24728646821SStefan Richter static inline void 248b5e47729SStefan Richter run_pcl(struct pcilynx *lynx, dma_addr_t pcl_bus, 249b5e47729SStefan Richter int dmachan) 25028646821SStefan Richter { 25128646821SStefan Richter reg_write(lynx, DMA0_CURRENT_PCL + dmachan * 0x20, pcl_bus); 25228646821SStefan Richter reg_write(lynx, DMA0_CHAN_CTRL + dmachan * 0x20, 25328646821SStefan Richter DMA_CHAN_CTRL_ENABLE | DMA_CHAN_CTRL_LINK); 25428646821SStefan Richter } 25528646821SStefan Richter 25628646821SStefan Richter static int 25728646821SStefan Richter set_phy_reg(struct pcilynx *lynx, int addr, int val) 25828646821SStefan Richter { 25928646821SStefan Richter if (addr > 15) { 2607429b17dSStefan Richter dev_err(&lynx->pci_device->dev, 2617429b17dSStefan Richter "PHY register address %d out of range\n", addr); 26228646821SStefan Richter return -1; 26328646821SStefan Richter } 26428646821SStefan Richter if (val > 0xff) { 2657429b17dSStefan Richter dev_err(&lynx->pci_device->dev, 2667429b17dSStefan Richter "PHY register value %d out of range\n", val); 26728646821SStefan Richter return -1; 26828646821SStefan Richter } 26928646821SStefan Richter reg_write(lynx, LINK_PHY, LINK_PHY_WRITE | 27028646821SStefan Richter LINK_PHY_ADDR(addr) | LINK_PHY_WDATA(val)); 27128646821SStefan Richter 27228646821SStefan Richter return 0; 27328646821SStefan Richter } 27428646821SStefan Richter 27528646821SStefan Richter static int 27628646821SStefan Richter nosy_open(struct inode *inode, struct file *file) 27728646821SStefan Richter { 27828646821SStefan Richter int minor = iminor(inode); 27955e77c06SStefan Richter struct client *client; 280424d66ceSStefan Richter struct pcilynx *tmp, *lynx = NULL; 28128646821SStefan Richter 282424d66ceSStefan Richter mutex_lock(&card_mutex); 283424d66ceSStefan Richter list_for_each_entry(tmp, &card_list, link) 284424d66ceSStefan Richter if (tmp->misc.minor == minor) { 285424d66ceSStefan Richter lynx = lynx_get(tmp); 286424d66ceSStefan Richter break; 287424d66ceSStefan Richter } 288424d66ceSStefan Richter mutex_unlock(&card_mutex); 289424d66ceSStefan Richter if (lynx == NULL) 29028646821SStefan Richter return -ENODEV; 29128646821SStefan Richter 29255e77c06SStefan Richter client = kmalloc(sizeof *client, GFP_KERNEL); 29355e77c06SStefan Richter if (client == NULL) 294424d66ceSStefan Richter goto fail; 29555e77c06SStefan Richter 29655e77c06SStefan Richter client->tcode_mask = ~0; 297424d66ceSStefan Richter client->lynx = lynx; 29855e77c06SStefan Richter INIT_LIST_HEAD(&client->link); 29955e77c06SStefan Richter 300424d66ceSStefan Richter if (packet_buffer_init(&client->buffer, 128 * 1024) < 0) 301424d66ceSStefan Richter goto fail; 30255e77c06SStefan Richter 30355e77c06SStefan Richter file->private_data = client; 30455e77c06SStefan Richter 30560a74a6fSStefan Richter return nonseekable_open(inode, file); 306424d66ceSStefan Richter fail: 307424d66ceSStefan Richter kfree(client); 308424d66ceSStefan Richter lynx_put(lynx); 309424d66ceSStefan Richter 310424d66ceSStefan Richter return -ENOMEM; 31128646821SStefan Richter } 31228646821SStefan Richter 31328646821SStefan Richter static int 31428646821SStefan Richter nosy_release(struct inode *inode, struct file *file) 31528646821SStefan Richter { 31655e77c06SStefan Richter struct client *client = file->private_data; 317424d66ceSStefan Richter struct pcilynx *lynx = client->lynx; 31855e77c06SStefan Richter 319424d66ceSStefan Richter spin_lock_irq(&lynx->client_list_lock); 32055e77c06SStefan Richter list_del_init(&client->link); 321424d66ceSStefan Richter spin_unlock_irq(&lynx->client_list_lock); 32255e77c06SStefan Richter 32355e77c06SStefan Richter packet_buffer_destroy(&client->buffer); 32455e77c06SStefan Richter kfree(client); 325424d66ceSStefan Richter lynx_put(lynx); 32628646821SStefan Richter 32728646821SStefan Richter return 0; 32828646821SStefan Richter } 32928646821SStefan Richter 33028646821SStefan Richter static unsigned int 33128646821SStefan Richter nosy_poll(struct file *file, poll_table *pt) 33228646821SStefan Richter { 33328646821SStefan Richter struct client *client = file->private_data; 334424d66ceSStefan Richter unsigned int ret = 0; 33528646821SStefan Richter 33628646821SStefan Richter poll_wait(file, &client->buffer.wait, pt); 33728646821SStefan Richter 33828646821SStefan Richter if (atomic_read(&client->buffer.size) > 0) 339424d66ceSStefan Richter ret = POLLIN | POLLRDNORM; 340424d66ceSStefan Richter 341424d66ceSStefan Richter if (list_empty(&client->lynx->link)) 342424d66ceSStefan Richter ret |= POLLHUP; 343424d66ceSStefan Richter 344424d66ceSStefan Richter return ret; 34528646821SStefan Richter } 34628646821SStefan Richter 34728646821SStefan Richter static ssize_t 348c89db7b8SStefan Richter nosy_read(struct file *file, char __user *buffer, size_t count, loff_t *offset) 34928646821SStefan Richter { 35028646821SStefan Richter struct client *client = file->private_data; 35128646821SStefan Richter 352424d66ceSStefan Richter return packet_buffer_get(client, buffer, count); 35328646821SStefan Richter } 35428646821SStefan Richter 355c7b2a99cSStefan Richter static long 356c7b2a99cSStefan Richter nosy_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 35728646821SStefan Richter { 35828646821SStefan Richter struct client *client = file->private_data; 359c7b2a99cSStefan Richter spinlock_t *client_list_lock = &client->lynx->client_list_lock; 36028646821SStefan Richter struct nosy_stats stats; 36128646821SStefan Richter 362b5e47729SStefan Richter switch (cmd) { 363b5e47729SStefan Richter case NOSY_IOC_GET_STATS: 364c7b2a99cSStefan Richter spin_lock_irq(client_list_lock); 36528646821SStefan Richter stats.total_packet_count = client->buffer.total_packet_count; 36628646821SStefan Richter stats.lost_packet_count = client->buffer.lost_packet_count; 367c7b2a99cSStefan Richter spin_unlock_irq(client_list_lock); 368c7b2a99cSStefan Richter 369c89db7b8SStefan Richter if (copy_to_user((void __user *) arg, &stats, sizeof stats)) 37028646821SStefan Richter return -EFAULT; 37128646821SStefan Richter else 37228646821SStefan Richter return 0; 37328646821SStefan Richter 37428646821SStefan Richter case NOSY_IOC_START: 37555e77c06SStefan Richter spin_lock_irq(client_list_lock); 37655e77c06SStefan Richter list_add_tail(&client->link, &client->lynx->client_list); 37755e77c06SStefan Richter spin_unlock_irq(client_list_lock); 37855e77c06SStefan Richter 37928646821SStefan Richter return 0; 38028646821SStefan Richter 38128646821SStefan Richter case NOSY_IOC_STOP: 38255e77c06SStefan Richter spin_lock_irq(client_list_lock); 38355e77c06SStefan Richter list_del_init(&client->link); 38455e77c06SStefan Richter spin_unlock_irq(client_list_lock); 38555e77c06SStefan Richter 38628646821SStefan Richter return 0; 38728646821SStefan Richter 38828646821SStefan Richter case NOSY_IOC_FILTER: 389c7b2a99cSStefan Richter spin_lock_irq(client_list_lock); 39028646821SStefan Richter client->tcode_mask = arg; 391c7b2a99cSStefan Richter spin_unlock_irq(client_list_lock); 39255e77c06SStefan Richter 39328646821SStefan Richter return 0; 39428646821SStefan Richter 39528646821SStefan Richter default: 39628646821SStefan Richter return -EINVAL; 39728646821SStefan Richter /* Flush buffer, configure filter. */ 39828646821SStefan Richter } 39928646821SStefan Richter } 40028646821SStefan Richter 401b5e47729SStefan Richter static const struct file_operations nosy_ops = { 40228646821SStefan Richter .owner = THIS_MODULE, 40328646821SStefan Richter .read = nosy_read, 404c7b2a99cSStefan Richter .unlocked_ioctl = nosy_ioctl, 40528646821SStefan Richter .poll = nosy_poll, 40628646821SStefan Richter .open = nosy_open, 40728646821SStefan Richter .release = nosy_release, 40828646821SStefan Richter }; 40928646821SStefan Richter 41028646821SStefan Richter #define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */ 41128646821SStefan Richter 41228646821SStefan Richter static void 413685c3f80SStefan Richter packet_irq_handler(struct pcilynx *lynx) 41428646821SStefan Richter { 41528646821SStefan Richter struct client *client; 416fd8c8d46SStefan Richter u32 tcode_mask, tcode; 41728646821SStefan Richter size_t length; 41828646821SStefan Richter struct timeval tv; 41928646821SStefan Richter 42028646821SStefan Richter /* FIXME: Also report rcv_speed. */ 42128646821SStefan Richter 422fd8c8d46SStefan Richter length = __le32_to_cpu(lynx->rcv_pcl->pcl_status) & 0x00001fff; 423fd8c8d46SStefan Richter tcode = __le32_to_cpu(lynx->rcv_buffer[1]) >> 4 & 0xf; 42428646821SStefan Richter 42528646821SStefan Richter do_gettimeofday(&tv); 426fd8c8d46SStefan Richter lynx->rcv_buffer[0] = (__force __le32)tv.tv_usec; 42728646821SStefan Richter 42828646821SStefan Richter if (length == PHY_PACKET_SIZE) 42928646821SStefan Richter tcode_mask = 1 << TCODE_PHY_PACKET; 43028646821SStefan Richter else 431fd8c8d46SStefan Richter tcode_mask = 1 << tcode; 43228646821SStefan Richter 433685c3f80SStefan Richter spin_lock(&lynx->client_list_lock); 43428646821SStefan Richter 435b5e47729SStefan Richter list_for_each_entry(client, &lynx->client_list, link) 43628646821SStefan Richter if (client->tcode_mask & tcode_mask) 43728646821SStefan Richter packet_buffer_put(&client->buffer, 43828646821SStefan Richter lynx->rcv_buffer, length + 4); 43928646821SStefan Richter 440685c3f80SStefan Richter spin_unlock(&lynx->client_list_lock); 44128646821SStefan Richter } 44228646821SStefan Richter 44328646821SStefan Richter static void 444685c3f80SStefan Richter bus_reset_irq_handler(struct pcilynx *lynx) 44528646821SStefan Richter { 44628646821SStefan Richter struct client *client; 44728646821SStefan Richter struct timeval tv; 44828646821SStefan Richter 44928646821SStefan Richter do_gettimeofday(&tv); 45028646821SStefan Richter 451685c3f80SStefan Richter spin_lock(&lynx->client_list_lock); 45228646821SStefan Richter 453b5e47729SStefan Richter list_for_each_entry(client, &lynx->client_list, link) 45428646821SStefan Richter packet_buffer_put(&client->buffer, &tv.tv_usec, 4); 45528646821SStefan Richter 456685c3f80SStefan Richter spin_unlock(&lynx->client_list_lock); 45728646821SStefan Richter } 45828646821SStefan Richter 45928646821SStefan Richter static irqreturn_t 46028646821SStefan Richter irq_handler(int irq, void *device) 46128646821SStefan Richter { 462b5e47729SStefan Richter struct pcilynx *lynx = device; 46328646821SStefan Richter u32 pci_int_status; 46428646821SStefan Richter 46528646821SStefan Richter pci_int_status = reg_read(lynx, PCI_INT_STATUS); 46628646821SStefan Richter 46716547667SStefan Richter if (pci_int_status == ~0) 46816547667SStefan Richter /* Card was ejected. */ 46916547667SStefan Richter return IRQ_NONE; 47016547667SStefan Richter 47128646821SStefan Richter if ((pci_int_status & PCI_INT_INT_PEND) == 0) 47228646821SStefan Richter /* Not our interrupt, bail out quickly. */ 47328646821SStefan Richter return IRQ_NONE; 47428646821SStefan Richter 47528646821SStefan Richter if ((pci_int_status & PCI_INT_P1394_INT) != 0) { 47628646821SStefan Richter u32 link_int_status; 47728646821SStefan Richter 47828646821SStefan Richter link_int_status = reg_read(lynx, LINK_INT_STATUS); 47928646821SStefan Richter reg_write(lynx, LINK_INT_STATUS, link_int_status); 48028646821SStefan Richter 48128646821SStefan Richter if ((link_int_status & LINK_INT_PHY_BUSRESET) > 0) 482685c3f80SStefan Richter bus_reset_irq_handler(lynx); 48328646821SStefan Richter } 48428646821SStefan Richter 48528646821SStefan Richter /* Clear the PCI_INT_STATUS register only after clearing the 48628646821SStefan Richter * LINK_INT_STATUS register; otherwise the PCI_INT_P1394 will 48728646821SStefan Richter * be set again immediately. */ 48828646821SStefan Richter 48928646821SStefan Richter reg_write(lynx, PCI_INT_STATUS, pci_int_status); 49028646821SStefan Richter 49128646821SStefan Richter if ((pci_int_status & PCI_INT_DMA0_HLT) > 0) { 492685c3f80SStefan Richter packet_irq_handler(lynx); 49328646821SStefan Richter run_pcl(lynx, lynx->rcv_start_pcl_bus, 0); 49428646821SStefan Richter } 49528646821SStefan Richter 49628646821SStefan Richter return IRQ_HANDLED; 49728646821SStefan Richter } 49828646821SStefan Richter 49928646821SStefan Richter static void 50028646821SStefan Richter remove_card(struct pci_dev *dev) 50128646821SStefan Richter { 502424d66ceSStefan Richter struct pcilynx *lynx = pci_get_drvdata(dev); 503424d66ceSStefan Richter struct client *client; 50428646821SStefan Richter 505424d66ceSStefan Richter mutex_lock(&card_mutex); 506424d66ceSStefan Richter list_del_init(&lynx->link); 507424d66ceSStefan Richter misc_deregister(&lynx->misc); 508424d66ceSStefan Richter mutex_unlock(&card_mutex); 50928646821SStefan Richter 51028646821SStefan Richter reg_write(lynx, PCI_INT_ENABLE, 0); 51128646821SStefan Richter free_irq(lynx->pci_device->irq, lynx); 51228646821SStefan Richter 513424d66ceSStefan Richter spin_lock_irq(&lynx->client_list_lock); 514424d66ceSStefan Richter list_for_each_entry(client, &lynx->client_list, link) 515424d66ceSStefan Richter wake_up_interruptible(&client->buffer.wait); 516424d66ceSStefan Richter spin_unlock_irq(&lynx->client_list_lock); 517424d66ceSStefan Richter 51828646821SStefan Richter pci_free_consistent(lynx->pci_device, sizeof(struct pcl), 51928646821SStefan Richter lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); 52028646821SStefan Richter pci_free_consistent(lynx->pci_device, sizeof(struct pcl), 52128646821SStefan Richter lynx->rcv_pcl, lynx->rcv_pcl_bus); 52228646821SStefan Richter pci_free_consistent(lynx->pci_device, PAGE_SIZE, 52328646821SStefan Richter lynx->rcv_buffer, lynx->rcv_buffer_bus); 52428646821SStefan Richter 52528646821SStefan Richter iounmap(lynx->registers); 526b6d9c125SStefan Richter pci_disable_device(dev); 527424d66ceSStefan Richter lynx_put(lynx); 52828646821SStefan Richter } 52928646821SStefan Richter 53028646821SStefan Richter #define RCV_BUFFER_SIZE (16 * 1024) 53128646821SStefan Richter 53228646821SStefan Richter static int __devinit 53328646821SStefan Richter add_card(struct pci_dev *dev, const struct pci_device_id *unused) 53428646821SStefan Richter { 53528646821SStefan Richter struct pcilynx *lynx; 53628646821SStefan Richter u32 p, end; 537b6d9c125SStefan Richter int ret, i; 53828646821SStefan Richter 539e894d1d7Ssantosh nayak if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) { 5407429b17dSStefan Richter dev_err(&dev->dev, 5417429b17dSStefan Richter "DMA address limits not supported for PCILynx hardware\n"); 542b5e47729SStefan Richter return -ENXIO; 543b5e47729SStefan Richter } 544b5e47729SStefan Richter if (pci_enable_device(dev)) { 5457429b17dSStefan Richter dev_err(&dev->dev, "Failed to enable PCILynx hardware\n"); 546b5e47729SStefan Richter return -ENXIO; 547b5e47729SStefan Richter } 54828646821SStefan Richter pci_set_master(dev); 54928646821SStefan Richter 55028646821SStefan Richter lynx = kzalloc(sizeof *lynx, GFP_KERNEL); 551b5e47729SStefan Richter if (lynx == NULL) { 5527429b17dSStefan Richter dev_err(&dev->dev, "Failed to allocate control structure\n"); 553b6d9c125SStefan Richter ret = -ENOMEM; 554b6d9c125SStefan Richter goto fail_disable; 555b5e47729SStefan Richter } 55628646821SStefan Richter lynx->pci_device = dev; 55728646821SStefan Richter pci_set_drvdata(dev, lynx); 55828646821SStefan Richter 55928646821SStefan Richter spin_lock_init(&lynx->client_list_lock); 56028646821SStefan Richter INIT_LIST_HEAD(&lynx->client_list); 561424d66ceSStefan Richter kref_init(&lynx->kref); 56228646821SStefan Richter 56328646821SStefan Richter lynx->registers = ioremap_nocache(pci_resource_start(dev, 0), 56428646821SStefan Richter PCILYNX_MAX_REGISTER); 56528646821SStefan Richter 56628646821SStefan Richter lynx->rcv_start_pcl = pci_alloc_consistent(lynx->pci_device, 567b5e47729SStefan Richter sizeof(struct pcl), &lynx->rcv_start_pcl_bus); 56828646821SStefan Richter lynx->rcv_pcl = pci_alloc_consistent(lynx->pci_device, 569b5e47729SStefan Richter sizeof(struct pcl), &lynx->rcv_pcl_bus); 570b5e47729SStefan Richter lynx->rcv_buffer = pci_alloc_consistent(lynx->pci_device, 571b5e47729SStefan Richter RCV_BUFFER_SIZE, &lynx->rcv_buffer_bus); 57228646821SStefan Richter if (lynx->rcv_start_pcl == NULL || 57328646821SStefan Richter lynx->rcv_pcl == NULL || 574b5e47729SStefan Richter lynx->rcv_buffer == NULL) { 5757429b17dSStefan Richter dev_err(&dev->dev, "Failed to allocate receive buffer\n"); 576b6d9c125SStefan Richter ret = -ENOMEM; 577b6d9c125SStefan Richter goto fail_deallocate; 578b5e47729SStefan Richter } 579fd8c8d46SStefan Richter lynx->rcv_start_pcl->next = cpu_to_le32(lynx->rcv_pcl_bus); 580fd8c8d46SStefan Richter lynx->rcv_pcl->next = cpu_to_le32(PCL_NEXT_INVALID); 581fd8c8d46SStefan Richter lynx->rcv_pcl->async_error_next = cpu_to_le32(PCL_NEXT_INVALID); 58228646821SStefan Richter 58328646821SStefan Richter lynx->rcv_pcl->buffer[0].control = 584fd8c8d46SStefan Richter cpu_to_le32(PCL_CMD_RCV | PCL_BIGENDIAN | 2044); 585fd8c8d46SStefan Richter lynx->rcv_pcl->buffer[0].pointer = 586fd8c8d46SStefan Richter cpu_to_le32(lynx->rcv_buffer_bus + 4); 58728646821SStefan Richter p = lynx->rcv_buffer_bus + 2048; 58828646821SStefan Richter end = lynx->rcv_buffer_bus + RCV_BUFFER_SIZE; 58928646821SStefan Richter for (i = 1; p < end; i++, p += 2048) { 59028646821SStefan Richter lynx->rcv_pcl->buffer[i].control = 591fd8c8d46SStefan Richter cpu_to_le32(PCL_CMD_RCV | PCL_BIGENDIAN | 2048); 592fd8c8d46SStefan Richter lynx->rcv_pcl->buffer[i].pointer = cpu_to_le32(p); 59328646821SStefan Richter } 594fd8c8d46SStefan Richter lynx->rcv_pcl->buffer[i - 1].control |= cpu_to_le32(PCL_LAST_BUFF); 59528646821SStefan Richter 59628646821SStefan Richter reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); 59728646821SStefan Richter /* Fix buggy cards with autoboot pin not tied low: */ 59828646821SStefan Richter reg_write(lynx, DMA0_CHAN_CTRL, 0); 59928646821SStefan Richter reg_write(lynx, DMA_GLOBAL_REGISTER, 0x00 << 24); 60028646821SStefan Richter 60128646821SStefan Richter #if 0 60228646821SStefan Richter /* now, looking for PHY register set */ 60328646821SStefan Richter if ((get_phy_reg(lynx, 2) & 0xe0) == 0xe0) { 60428646821SStefan Richter lynx->phyic.reg_1394a = 1; 60528646821SStefan Richter PRINT(KERN_INFO, lynx->id, 60628646821SStefan Richter "found 1394a conform PHY (using extended register set)"); 60728646821SStefan Richter lynx->phyic.vendor = get_phy_vendorid(lynx); 60828646821SStefan Richter lynx->phyic.product = get_phy_productid(lynx); 60928646821SStefan Richter } else { 61028646821SStefan Richter lynx->phyic.reg_1394a = 0; 61128646821SStefan Richter PRINT(KERN_INFO, lynx->id, "found old 1394 PHY"); 61228646821SStefan Richter } 61328646821SStefan Richter #endif 61428646821SStefan Richter 61528646821SStefan Richter /* Setup the general receive FIFO max size. */ 61628646821SStefan Richter reg_write(lynx, FIFO_SIZES, 255); 61728646821SStefan Richter 61828646821SStefan Richter reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL); 61928646821SStefan Richter 62028646821SStefan Richter reg_write(lynx, LINK_INT_ENABLE, 62128646821SStefan Richter LINK_INT_PHY_TIME_OUT | LINK_INT_PHY_REG_RCVD | 62228646821SStefan Richter LINK_INT_PHY_BUSRESET | LINK_INT_IT_STUCK | 62328646821SStefan Richter LINK_INT_AT_STUCK | LINK_INT_SNTRJ | 62428646821SStefan Richter LINK_INT_TC_ERR | LINK_INT_GRF_OVER_FLOW | 62528646821SStefan Richter LINK_INT_ITF_UNDER_FLOW | LINK_INT_ATF_UNDER_FLOW); 62628646821SStefan Richter 62728646821SStefan Richter /* Disable the L flag in self ID packets. */ 62828646821SStefan Richter set_phy_reg(lynx, 4, 0); 62928646821SStefan Richter 63028646821SStefan Richter /* Put this baby into snoop mode */ 63128646821SStefan Richter reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_SNOOP_ENABLE); 63228646821SStefan Richter 63328646821SStefan Richter run_pcl(lynx, lynx->rcv_start_pcl_bus, 0); 63428646821SStefan Richter 635b5e47729SStefan Richter if (request_irq(dev->irq, irq_handler, IRQF_SHARED, 636b5e47729SStefan Richter driver_name, lynx)) { 6377429b17dSStefan Richter dev_err(&dev->dev, 6387429b17dSStefan Richter "Failed to allocate shared interrupt %d\n", dev->irq); 639b6d9c125SStefan Richter ret = -EIO; 640b6d9c125SStefan Richter goto fail_deallocate; 641b5e47729SStefan Richter } 64228646821SStefan Richter 64328646821SStefan Richter lynx->misc.parent = &dev->dev; 64428646821SStefan Richter lynx->misc.minor = MISC_DYNAMIC_MINOR; 64528646821SStefan Richter lynx->misc.name = "nosy"; 64628646821SStefan Richter lynx->misc.fops = &nosy_ops; 647424d66ceSStefan Richter 648424d66ceSStefan Richter mutex_lock(&card_mutex); 649b6d9c125SStefan Richter ret = misc_register(&lynx->misc); 650b6d9c125SStefan Richter if (ret) { 6517429b17dSStefan Richter dev_err(&dev->dev, "Failed to register misc char device\n"); 652424d66ceSStefan Richter mutex_unlock(&card_mutex); 653b6d9c125SStefan Richter goto fail_free_irq; 654b5e47729SStefan Richter } 655424d66ceSStefan Richter list_add_tail(&lynx->link, &card_list); 656424d66ceSStefan Richter mutex_unlock(&card_mutex); 65728646821SStefan Richter 6587429b17dSStefan Richter dev_info(&dev->dev, 6597429b17dSStefan Richter "Initialized PCILynx IEEE1394 card, irq=%d\n", dev->irq); 66028646821SStefan Richter 66128646821SStefan Richter return 0; 662b6d9c125SStefan Richter 663b6d9c125SStefan Richter fail_free_irq: 664b6d9c125SStefan Richter reg_write(lynx, PCI_INT_ENABLE, 0); 665b6d9c125SStefan Richter free_irq(lynx->pci_device->irq, lynx); 666b6d9c125SStefan Richter 667b6d9c125SStefan Richter fail_deallocate: 668b6d9c125SStefan Richter if (lynx->rcv_start_pcl) 669b6d9c125SStefan Richter pci_free_consistent(lynx->pci_device, sizeof(struct pcl), 670b6d9c125SStefan Richter lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); 671b6d9c125SStefan Richter if (lynx->rcv_pcl) 672b6d9c125SStefan Richter pci_free_consistent(lynx->pci_device, sizeof(struct pcl), 673b6d9c125SStefan Richter lynx->rcv_pcl, lynx->rcv_pcl_bus); 674b6d9c125SStefan Richter if (lynx->rcv_buffer) 675b6d9c125SStefan Richter pci_free_consistent(lynx->pci_device, PAGE_SIZE, 676b6d9c125SStefan Richter lynx->rcv_buffer, lynx->rcv_buffer_bus); 677b6d9c125SStefan Richter iounmap(lynx->registers); 678b6d9c125SStefan Richter kfree(lynx); 679b6d9c125SStefan Richter 680b6d9c125SStefan Richter fail_disable: 681b6d9c125SStefan Richter pci_disable_device(dev); 682b6d9c125SStefan Richter 683b6d9c125SStefan Richter return ret; 68428646821SStefan Richter } 68528646821SStefan Richter 68628646821SStefan Richter static struct pci_device_id pci_table[] __devinitdata = { 68728646821SStefan Richter { 68828646821SStefan Richter .vendor = PCI_VENDOR_ID_TI, 68928646821SStefan Richter .device = PCI_DEVICE_ID_TI_PCILYNX, 69028646821SStefan Richter .subvendor = PCI_ANY_ID, 69128646821SStefan Richter .subdevice = PCI_ANY_ID, 69228646821SStefan Richter }, 69328646821SStefan Richter { } /* Terminating entry */ 69428646821SStefan Richter }; 69528646821SStefan Richter 696fe2af11cSAxel Lin MODULE_DEVICE_TABLE(pci, pci_table); 697fe2af11cSAxel Lin 69828646821SStefan Richter static struct pci_driver lynx_pci_driver = { 699b5e47729SStefan Richter .name = driver_name, 70028646821SStefan Richter .id_table = pci_table, 70128646821SStefan Richter .probe = add_card, 702b5e47729SStefan Richter .remove = remove_card, 70328646821SStefan Richter }; 70428646821SStefan Richter 705fe2af11cSAxel Lin module_pci_driver(lynx_pci_driver); 706fe2af11cSAxel Lin 707b5e47729SStefan Richter MODULE_AUTHOR("Kristian Hoegsberg"); 70828646821SStefan Richter MODULE_DESCRIPTION("Snoop mode driver for TI pcilynx 1394 controllers"); 70928646821SStefan Richter MODULE_LICENSE("GPL"); 710