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 2028646821SStefan Richter #include <linux/errno.h> 2128646821SStefan Richter #include <linux/fs.h> 22b5e47729SStefan Richter #include <linux/init.h> 23b5e47729SStefan Richter #include <linux/interrupt.h> 24b5e47729SStefan Richter #include <linux/io.h> 25b5e47729SStefan Richter #include <linux/kernel.h> 26424d66ceSStefan Richter #include <linux/kref.h> 2728646821SStefan Richter #include <linux/miscdevice.h> 28b5e47729SStefan Richter #include <linux/module.h> 29424d66ceSStefan Richter #include <linux/mutex.h> 30b5e47729SStefan Richter #include <linux/pci.h> 31b5e47729SStefan Richter #include <linux/poll.h> 32b5e47729SStefan Richter #include <linux/sched.h> /* required for linux/wait.h */ 33b5e47729SStefan Richter #include <linux/slab.h> 34b5e47729SStefan Richter #include <linux/spinlock.h> 35b5e47729SStefan Richter #include <linux/timex.h> 36b5e47729SStefan Richter #include <linux/uaccess.h> 37b5e47729SStefan Richter #include <linux/wait.h> 38b5e47729SStefan Richter 3928646821SStefan Richter #include <asm/atomic.h> 40b5e47729SStefan Richter #include <asm/byteorder.h> 4128646821SStefan Richter 4228646821SStefan Richter #include "nosy.h" 4328646821SStefan Richter #include "nosy-user.h" 4428646821SStefan Richter 4528646821SStefan Richter #define TCODE_PHY_PACKET 0x10 4628646821SStefan Richter #define PCI_DEVICE_ID_TI_PCILYNX 0x8000 4728646821SStefan Richter 4828646821SStefan Richter #define notify(s, args...) printk(KERN_NOTICE s, ## args) 4928646821SStefan Richter #define error(s, args...) printk(KERN_ERR s, ## args) 5028646821SStefan Richter #define debug(s, args...) printk(KERN_DEBUG s, ## args) 5128646821SStefan Richter 52b5e47729SStefan Richter static char driver_name[] = KBUILD_MODNAME; 5328646821SStefan Richter 5428646821SStefan Richter struct pcl_status { 5528646821SStefan Richter unsigned int transfer_count : 13; 5628646821SStefan Richter unsigned int reserved0 : 1; 5728646821SStefan Richter unsigned int ack_type : 1; 5828646821SStefan Richter unsigned int ack : 4; 5928646821SStefan Richter unsigned int rcv_speed : 2; 6028646821SStefan Richter unsigned int rcv_dma_channel : 6; 6128646821SStefan Richter unsigned int packet_complete : 1; 6228646821SStefan Richter unsigned int packet_error : 1; 6328646821SStefan Richter unsigned int master_error : 1; 6428646821SStefan Richter unsigned int iso_mode : 1; 6528646821SStefan Richter unsigned int self_id : 1; 6628646821SStefan Richter }; 6728646821SStefan Richter 6828646821SStefan Richter /* this is the physical layout of a PCL, its size is 128 bytes */ 6928646821SStefan Richter struct pcl { 7028646821SStefan Richter u32 next; 7128646821SStefan Richter u32 async_error_next; 7228646821SStefan Richter u32 user_data; 7328646821SStefan Richter struct pcl_status pcl_status; 7428646821SStefan Richter u32 remaining_transfer_count; 7528646821SStefan Richter u32 next_data_buffer; 7628646821SStefan Richter struct { 7728646821SStefan Richter u32 control; 7828646821SStefan Richter u32 pointer; 7928646821SStefan Richter } buffer[13] __attribute__ ((packed)); 8028646821SStefan Richter } __attribute__ ((packed)); 8128646821SStefan Richter 8228646821SStefan Richter struct packet { 83b5e47729SStefan Richter unsigned int length; 8428646821SStefan Richter char data[0]; 8528646821SStefan Richter }; 8628646821SStefan Richter 8728646821SStefan Richter struct packet_buffer { 8828646821SStefan Richter char *data; 8928646821SStefan Richter size_t capacity; 9028646821SStefan Richter long total_packet_count, lost_packet_count; 9128646821SStefan Richter atomic_t size; 9228646821SStefan Richter struct packet *head, *tail; 9328646821SStefan Richter wait_queue_head_t wait; 9428646821SStefan Richter }; 9528646821SStefan Richter 9628646821SStefan Richter struct pcilynx { 9728646821SStefan Richter struct pci_dev *pci_device; 9828646821SStefan Richter unsigned char *registers; 9928646821SStefan Richter 10028646821SStefan Richter struct pcl *rcv_start_pcl, *rcv_pcl; 10128646821SStefan Richter u32 *rcv_buffer; 10228646821SStefan Richter 10328646821SStefan Richter dma_addr_t rcv_start_pcl_bus, rcv_pcl_bus, rcv_buffer_bus; 10428646821SStefan Richter 10528646821SStefan Richter spinlock_t client_list_lock; 10628646821SStefan Richter struct list_head client_list; 10728646821SStefan Richter 10828646821SStefan Richter struct miscdevice misc; 109424d66ceSStefan Richter struct list_head link; 110424d66ceSStefan Richter struct kref kref; 11128646821SStefan Richter }; 11228646821SStefan Richter 113424d66ceSStefan Richter static inline struct pcilynx * 114424d66ceSStefan Richter lynx_get(struct pcilynx *lynx) 115424d66ceSStefan Richter { 116424d66ceSStefan Richter kref_get(&lynx->kref); 117424d66ceSStefan Richter 118424d66ceSStefan Richter return lynx; 119424d66ceSStefan Richter } 120424d66ceSStefan Richter 121424d66ceSStefan Richter static void 122424d66ceSStefan Richter lynx_release(struct kref *kref) 123424d66ceSStefan Richter { 124424d66ceSStefan Richter kfree(container_of(kref, struct pcilynx, kref)); 125424d66ceSStefan Richter } 126424d66ceSStefan Richter 127424d66ceSStefan Richter static inline void 128424d66ceSStefan Richter lynx_put(struct pcilynx *lynx) 129424d66ceSStefan Richter { 130424d66ceSStefan Richter kref_put(&lynx->kref, lynx_release); 131424d66ceSStefan Richter } 132424d66ceSStefan Richter 13328646821SStefan Richter struct client { 13428646821SStefan Richter struct pcilynx *lynx; 135c7b2a99cSStefan Richter u32 tcode_mask; 13628646821SStefan Richter struct packet_buffer buffer; 13728646821SStefan Richter struct list_head link; 13828646821SStefan Richter }; 13928646821SStefan Richter 140424d66ceSStefan Richter static DEFINE_MUTEX(card_mutex); 141424d66ceSStefan Richter static LIST_HEAD(card_list); 14228646821SStefan Richter 14328646821SStefan Richter static int 14428646821SStefan Richter packet_buffer_init(struct packet_buffer *buffer, size_t capacity) 14528646821SStefan Richter { 14628646821SStefan Richter buffer->data = kmalloc(capacity, GFP_KERNEL); 14728646821SStefan Richter if (buffer->data == NULL) 14828646821SStefan Richter return -ENOMEM; 14928646821SStefan Richter buffer->head = (struct packet *) buffer->data; 15028646821SStefan Richter buffer->tail = (struct packet *) buffer->data; 15128646821SStefan Richter buffer->capacity = capacity; 15228646821SStefan Richter buffer->lost_packet_count = 0; 15328646821SStefan Richter atomic_set(&buffer->size, 0); 15428646821SStefan Richter init_waitqueue_head(&buffer->wait); 15528646821SStefan Richter 15628646821SStefan Richter return 0; 15728646821SStefan Richter } 15828646821SStefan Richter 15928646821SStefan Richter static void 16028646821SStefan Richter packet_buffer_destroy(struct packet_buffer *buffer) 16128646821SStefan Richter { 16228646821SStefan Richter kfree(buffer->data); 16328646821SStefan Richter } 16428646821SStefan Richter 16528646821SStefan Richter static int 166424d66ceSStefan Richter packet_buffer_get(struct client *client, void *data, size_t user_length) 16728646821SStefan Richter { 168424d66ceSStefan Richter struct packet_buffer *buffer = &client->buffer; 16928646821SStefan Richter size_t length; 17028646821SStefan Richter char *end; 17128646821SStefan Richter 17228646821SStefan Richter if (wait_event_interruptible(buffer->wait, 173424d66ceSStefan Richter atomic_read(&buffer->size) > 0) || 174424d66ceSStefan Richter list_empty(&client->lynx->link)) 17528646821SStefan Richter return -ERESTARTSYS; 17628646821SStefan Richter 177424d66ceSStefan Richter if (atomic_read(&buffer->size) == 0) 178424d66ceSStefan Richter return -ENODEV; 179424d66ceSStefan Richter 18028646821SStefan Richter /* FIXME: Check length <= user_length. */ 18128646821SStefan Richter 18228646821SStefan Richter end = buffer->data + buffer->capacity; 18328646821SStefan Richter length = buffer->head->length; 18428646821SStefan Richter 18528646821SStefan Richter if (&buffer->head->data[length] < end) { 18628646821SStefan Richter if (copy_to_user(data, buffer->head->data, length)) 18728646821SStefan Richter return -EFAULT; 18828646821SStefan Richter buffer->head = (struct packet *) &buffer->head->data[length]; 189b5e47729SStefan Richter } else { 19028646821SStefan Richter size_t split = end - buffer->head->data; 19128646821SStefan Richter 19228646821SStefan Richter if (copy_to_user(data, buffer->head->data, split)) 19328646821SStefan Richter return -EFAULT; 19428646821SStefan Richter if (copy_to_user(data + split, buffer->data, length - split)) 19528646821SStefan Richter return -EFAULT; 19628646821SStefan Richter buffer->head = (struct packet *) &buffer->data[length - split]; 19728646821SStefan Richter } 19828646821SStefan Richter 199b5e47729SStefan Richter /* 200b5e47729SStefan Richter * Decrease buffer->size as the last thing, since this is what 20128646821SStefan Richter * keeps the interrupt from overwriting the packet we are 202b5e47729SStefan Richter * retrieving from the buffer. 203b5e47729SStefan Richter */ 20428646821SStefan Richter atomic_sub(sizeof(struct packet) + length, &buffer->size); 20528646821SStefan Richter 20628646821SStefan Richter return length; 20728646821SStefan Richter } 20828646821SStefan Richter 20928646821SStefan Richter static void 21028646821SStefan Richter packet_buffer_put(struct packet_buffer *buffer, void *data, size_t length) 21128646821SStefan Richter { 21228646821SStefan Richter char *end; 21328646821SStefan Richter 21428646821SStefan Richter buffer->total_packet_count++; 21528646821SStefan Richter 21628646821SStefan Richter if (buffer->capacity < 21728646821SStefan Richter atomic_read(&buffer->size) + sizeof(struct packet) + length) { 21828646821SStefan Richter buffer->lost_packet_count++; 21928646821SStefan Richter return; 22028646821SStefan Richter } 22128646821SStefan Richter 22228646821SStefan Richter end = buffer->data + buffer->capacity; 22328646821SStefan Richter buffer->tail->length = length; 22428646821SStefan Richter 22528646821SStefan Richter if (&buffer->tail->data[length] < end) { 22628646821SStefan Richter memcpy(buffer->tail->data, data, length); 22728646821SStefan Richter buffer->tail = (struct packet *) &buffer->tail->data[length]; 228b5e47729SStefan Richter } else { 22928646821SStefan Richter size_t split = end - buffer->tail->data; 23028646821SStefan Richter 23128646821SStefan Richter memcpy(buffer->tail->data, data, split); 23228646821SStefan Richter memcpy(buffer->data, data + split, length - split); 23328646821SStefan Richter buffer->tail = (struct packet *) &buffer->data[length - split]; 23428646821SStefan Richter } 23528646821SStefan Richter 23628646821SStefan Richter /* Finally, adjust buffer size and wake up userspace reader. */ 23728646821SStefan Richter 23828646821SStefan Richter atomic_add(sizeof(struct packet) + length, &buffer->size); 23928646821SStefan Richter wake_up_interruptible(&buffer->wait); 24028646821SStefan Richter } 24128646821SStefan Richter 24228646821SStefan Richter static inline void 24328646821SStefan Richter reg_write(struct pcilynx *lynx, int offset, u32 data) 24428646821SStefan Richter { 24528646821SStefan Richter writel(data, lynx->registers + offset); 24628646821SStefan Richter } 24728646821SStefan Richter 24828646821SStefan Richter static inline u32 24928646821SStefan Richter reg_read(struct pcilynx *lynx, int offset) 25028646821SStefan Richter { 25128646821SStefan Richter return readl(lynx->registers + offset); 25228646821SStefan Richter } 25328646821SStefan Richter 25428646821SStefan Richter static inline void 25528646821SStefan Richter reg_set_bits(struct pcilynx *lynx, int offset, u32 mask) 25628646821SStefan Richter { 25728646821SStefan Richter reg_write(lynx, offset, (reg_read(lynx, offset) | mask)); 25828646821SStefan Richter } 25928646821SStefan Richter 260b5e47729SStefan Richter /* 261b5e47729SStefan Richter * Maybe the pcl programs could be set up to just append data instead 262b5e47729SStefan Richter * of using a whole packet. 263b5e47729SStefan Richter */ 26428646821SStefan Richter static inline void 265b5e47729SStefan Richter run_pcl(struct pcilynx *lynx, dma_addr_t pcl_bus, 266b5e47729SStefan Richter int dmachan) 26728646821SStefan Richter { 26828646821SStefan Richter reg_write(lynx, DMA0_CURRENT_PCL + dmachan * 0x20, pcl_bus); 26928646821SStefan Richter reg_write(lynx, DMA0_CHAN_CTRL + dmachan * 0x20, 27028646821SStefan Richter DMA_CHAN_CTRL_ENABLE | DMA_CHAN_CTRL_LINK); 27128646821SStefan Richter } 27228646821SStefan Richter 27328646821SStefan Richter static int 27428646821SStefan Richter set_phy_reg(struct pcilynx *lynx, int addr, int val) 27528646821SStefan Richter { 27628646821SStefan Richter if (addr > 15) { 277b5e47729SStefan Richter debug("PHY register address %d out of range\n", addr); 27828646821SStefan Richter return -1; 27928646821SStefan Richter } 28028646821SStefan Richter 28128646821SStefan Richter if (val > 0xff) { 282b5e47729SStefan Richter debug("PHY register value %d out of range\n", val); 28328646821SStefan Richter return -1; 28428646821SStefan Richter } 28528646821SStefan Richter 28628646821SStefan Richter reg_write(lynx, LINK_PHY, LINK_PHY_WRITE | 28728646821SStefan Richter LINK_PHY_ADDR(addr) | LINK_PHY_WDATA(val)); 28828646821SStefan Richter 28928646821SStefan Richter return 0; 29028646821SStefan Richter } 29128646821SStefan Richter 29228646821SStefan Richter static int 29328646821SStefan Richter nosy_open(struct inode *inode, struct file *file) 29428646821SStefan Richter { 29528646821SStefan Richter int minor = iminor(inode); 29655e77c06SStefan Richter struct client *client; 297424d66ceSStefan Richter struct pcilynx *tmp, *lynx = NULL; 29828646821SStefan Richter 299424d66ceSStefan Richter mutex_lock(&card_mutex); 300424d66ceSStefan Richter list_for_each_entry(tmp, &card_list, link) 301424d66ceSStefan Richter if (tmp->misc.minor == minor) { 302424d66ceSStefan Richter lynx = lynx_get(tmp); 303424d66ceSStefan Richter break; 304424d66ceSStefan Richter } 305424d66ceSStefan Richter mutex_unlock(&card_mutex); 306424d66ceSStefan Richter if (lynx == NULL) 30728646821SStefan Richter return -ENODEV; 30828646821SStefan Richter 30955e77c06SStefan Richter client = kmalloc(sizeof *client, GFP_KERNEL); 31055e77c06SStefan Richter if (client == NULL) 311424d66ceSStefan Richter goto fail; 31255e77c06SStefan Richter 31355e77c06SStefan Richter client->tcode_mask = ~0; 314424d66ceSStefan Richter client->lynx = lynx; 31555e77c06SStefan Richter INIT_LIST_HEAD(&client->link); 31655e77c06SStefan Richter 317424d66ceSStefan Richter if (packet_buffer_init(&client->buffer, 128 * 1024) < 0) 318424d66ceSStefan Richter goto fail; 31955e77c06SStefan Richter 32055e77c06SStefan Richter file->private_data = client; 32155e77c06SStefan Richter 32228646821SStefan Richter return 0; 323424d66ceSStefan Richter fail: 324424d66ceSStefan Richter kfree(client); 325424d66ceSStefan Richter lynx_put(lynx); 326424d66ceSStefan Richter 327424d66ceSStefan Richter return -ENOMEM; 32828646821SStefan Richter } 32928646821SStefan Richter 33028646821SStefan Richter static int 33128646821SStefan Richter nosy_release(struct inode *inode, struct file *file) 33228646821SStefan Richter { 33355e77c06SStefan Richter struct client *client = file->private_data; 334424d66ceSStefan Richter struct pcilynx *lynx = client->lynx; 33555e77c06SStefan Richter 336424d66ceSStefan Richter spin_lock_irq(&lynx->client_list_lock); 33755e77c06SStefan Richter list_del_init(&client->link); 338424d66ceSStefan Richter spin_unlock_irq(&lynx->client_list_lock); 33955e77c06SStefan Richter 34055e77c06SStefan Richter packet_buffer_destroy(&client->buffer); 34155e77c06SStefan Richter kfree(client); 342424d66ceSStefan Richter lynx_put(lynx); 34328646821SStefan Richter 34428646821SStefan Richter return 0; 34528646821SStefan Richter } 34628646821SStefan Richter 34728646821SStefan Richter static unsigned int 34828646821SStefan Richter nosy_poll(struct file *file, poll_table *pt) 34928646821SStefan Richter { 35028646821SStefan Richter struct client *client = file->private_data; 351424d66ceSStefan Richter unsigned int ret = 0; 35228646821SStefan Richter 35328646821SStefan Richter poll_wait(file, &client->buffer.wait, pt); 35428646821SStefan Richter 35528646821SStefan Richter if (atomic_read(&client->buffer.size) > 0) 356424d66ceSStefan Richter ret = POLLIN | POLLRDNORM; 357424d66ceSStefan Richter 358424d66ceSStefan Richter if (list_empty(&client->lynx->link)) 359424d66ceSStefan Richter ret |= POLLHUP; 360424d66ceSStefan Richter 361424d66ceSStefan Richter return ret; 36228646821SStefan Richter } 36328646821SStefan Richter 36428646821SStefan Richter static ssize_t 36528646821SStefan Richter nosy_read(struct file *file, char *buffer, size_t count, loff_t *offset) 36628646821SStefan Richter { 36728646821SStefan Richter struct client *client = file->private_data; 36828646821SStefan Richter 369424d66ceSStefan Richter return packet_buffer_get(client, buffer, count); 37028646821SStefan Richter } 37128646821SStefan Richter 372c7b2a99cSStefan Richter static long 373c7b2a99cSStefan Richter nosy_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 37428646821SStefan Richter { 37528646821SStefan Richter struct client *client = file->private_data; 376c7b2a99cSStefan Richter spinlock_t *client_list_lock = &client->lynx->client_list_lock; 37728646821SStefan Richter struct nosy_stats stats; 37828646821SStefan Richter 379b5e47729SStefan Richter switch (cmd) { 380b5e47729SStefan Richter case NOSY_IOC_GET_STATS: 381c7b2a99cSStefan Richter spin_lock_irq(client_list_lock); 38228646821SStefan Richter stats.total_packet_count = client->buffer.total_packet_count; 38328646821SStefan Richter stats.lost_packet_count = client->buffer.lost_packet_count; 384c7b2a99cSStefan Richter spin_unlock_irq(client_list_lock); 385c7b2a99cSStefan Richter 38628646821SStefan Richter if (copy_to_user((void *) arg, &stats, sizeof stats)) 38728646821SStefan Richter return -EFAULT; 38828646821SStefan Richter else 38928646821SStefan Richter return 0; 39028646821SStefan Richter 39128646821SStefan Richter case NOSY_IOC_START: 39255e77c06SStefan Richter spin_lock_irq(client_list_lock); 39355e77c06SStefan Richter list_add_tail(&client->link, &client->lynx->client_list); 39455e77c06SStefan Richter spin_unlock_irq(client_list_lock); 39555e77c06SStefan Richter 39628646821SStefan Richter return 0; 39728646821SStefan Richter 39828646821SStefan Richter case NOSY_IOC_STOP: 39955e77c06SStefan Richter spin_lock_irq(client_list_lock); 40055e77c06SStefan Richter list_del_init(&client->link); 40155e77c06SStefan Richter spin_unlock_irq(client_list_lock); 40255e77c06SStefan Richter 40328646821SStefan Richter return 0; 40428646821SStefan Richter 40528646821SStefan Richter case NOSY_IOC_FILTER: 406c7b2a99cSStefan Richter spin_lock_irq(client_list_lock); 40728646821SStefan Richter client->tcode_mask = arg; 408c7b2a99cSStefan Richter spin_unlock_irq(client_list_lock); 40955e77c06SStefan Richter 41028646821SStefan Richter return 0; 41128646821SStefan Richter 41228646821SStefan Richter default: 41328646821SStefan Richter return -EINVAL; 41428646821SStefan Richter /* Flush buffer, configure filter. */ 41528646821SStefan Richter } 41628646821SStefan Richter } 41728646821SStefan Richter 418b5e47729SStefan Richter static const struct file_operations nosy_ops = { 41928646821SStefan Richter .owner = THIS_MODULE, 42028646821SStefan Richter .read = nosy_read, 421c7b2a99cSStefan Richter .unlocked_ioctl = nosy_ioctl, 42228646821SStefan Richter .poll = nosy_poll, 42328646821SStefan Richter .open = nosy_open, 42428646821SStefan Richter .release = nosy_release, 42528646821SStefan Richter }; 42628646821SStefan Richter 42728646821SStefan Richter #define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */ 42828646821SStefan Richter 42928646821SStefan Richter struct link_packet { 43028646821SStefan Richter unsigned int priority : 4; 43128646821SStefan Richter unsigned int tcode : 4; 43228646821SStefan Richter unsigned int rt : 2; 43328646821SStefan Richter unsigned int tlabel : 6; 43428646821SStefan Richter unsigned int destination : 16; 43528646821SStefan Richter }; 43628646821SStefan Richter 43728646821SStefan Richter static void 438685c3f80SStefan Richter packet_irq_handler(struct pcilynx *lynx) 43928646821SStefan Richter { 44028646821SStefan Richter struct client *client; 441c7b2a99cSStefan Richter u32 tcode_mask; 44228646821SStefan Richter size_t length; 44328646821SStefan Richter struct link_packet *packet; 44428646821SStefan Richter struct timeval tv; 44528646821SStefan Richter 44628646821SStefan Richter /* FIXME: Also report rcv_speed. */ 44728646821SStefan Richter 44828646821SStefan Richter length = lynx->rcv_pcl->pcl_status.transfer_count; 44928646821SStefan Richter packet = (struct link_packet *) &lynx->rcv_buffer[1]; 45028646821SStefan Richter 45128646821SStefan Richter do_gettimeofday(&tv); 45228646821SStefan Richter lynx->rcv_buffer[0] = tv.tv_usec; 45328646821SStefan Richter 45428646821SStefan Richter if (length == PHY_PACKET_SIZE) 45528646821SStefan Richter tcode_mask = 1 << TCODE_PHY_PACKET; 45628646821SStefan Richter else 45728646821SStefan Richter tcode_mask = 1 << packet->tcode; 45828646821SStefan Richter 459685c3f80SStefan Richter spin_lock(&lynx->client_list_lock); 46028646821SStefan Richter 461b5e47729SStefan Richter list_for_each_entry(client, &lynx->client_list, link) 46228646821SStefan Richter if (client->tcode_mask & tcode_mask) 46328646821SStefan Richter packet_buffer_put(&client->buffer, 46428646821SStefan Richter lynx->rcv_buffer, length + 4); 46528646821SStefan Richter 466685c3f80SStefan Richter spin_unlock(&lynx->client_list_lock); 46728646821SStefan Richter } 46828646821SStefan Richter 46928646821SStefan Richter static void 470685c3f80SStefan Richter bus_reset_irq_handler(struct pcilynx *lynx) 47128646821SStefan Richter { 47228646821SStefan Richter struct client *client; 47328646821SStefan Richter struct timeval tv; 47428646821SStefan Richter 47528646821SStefan Richter do_gettimeofday(&tv); 47628646821SStefan Richter 477685c3f80SStefan Richter spin_lock(&lynx->client_list_lock); 47828646821SStefan Richter 479b5e47729SStefan Richter list_for_each_entry(client, &lynx->client_list, link) 48028646821SStefan Richter packet_buffer_put(&client->buffer, &tv.tv_usec, 4); 48128646821SStefan Richter 482685c3f80SStefan Richter spin_unlock(&lynx->client_list_lock); 48328646821SStefan Richter } 48428646821SStefan Richter 48528646821SStefan Richter static irqreturn_t 48628646821SStefan Richter irq_handler(int irq, void *device) 48728646821SStefan Richter { 488b5e47729SStefan Richter struct pcilynx *lynx = device; 48928646821SStefan Richter u32 pci_int_status; 49028646821SStefan Richter 49128646821SStefan Richter pci_int_status = reg_read(lynx, PCI_INT_STATUS); 49228646821SStefan Richter 49316547667SStefan Richter if (pci_int_status == ~0) 49416547667SStefan Richter /* Card was ejected. */ 49516547667SStefan Richter return IRQ_NONE; 49616547667SStefan Richter 49728646821SStefan Richter if ((pci_int_status & PCI_INT_INT_PEND) == 0) 49828646821SStefan Richter /* Not our interrupt, bail out quickly. */ 49928646821SStefan Richter return IRQ_NONE; 50028646821SStefan Richter 50128646821SStefan Richter if ((pci_int_status & PCI_INT_P1394_INT) != 0) { 50228646821SStefan Richter u32 link_int_status; 50328646821SStefan Richter 50428646821SStefan Richter link_int_status = reg_read(lynx, LINK_INT_STATUS); 50528646821SStefan Richter reg_write(lynx, LINK_INT_STATUS, link_int_status); 50628646821SStefan Richter 50728646821SStefan Richter if ((link_int_status & LINK_INT_PHY_BUSRESET) > 0) 508685c3f80SStefan Richter bus_reset_irq_handler(lynx); 50928646821SStefan Richter } 51028646821SStefan Richter 51128646821SStefan Richter /* Clear the PCI_INT_STATUS register only after clearing the 51228646821SStefan Richter * LINK_INT_STATUS register; otherwise the PCI_INT_P1394 will 51328646821SStefan Richter * be set again immediately. */ 51428646821SStefan Richter 51528646821SStefan Richter reg_write(lynx, PCI_INT_STATUS, pci_int_status); 51628646821SStefan Richter 51728646821SStefan Richter if ((pci_int_status & PCI_INT_DMA0_HLT) > 0) { 518685c3f80SStefan Richter packet_irq_handler(lynx); 51928646821SStefan Richter run_pcl(lynx, lynx->rcv_start_pcl_bus, 0); 52028646821SStefan Richter } 52128646821SStefan Richter 52228646821SStefan Richter return IRQ_HANDLED; 52328646821SStefan Richter } 52428646821SStefan Richter 52528646821SStefan Richter static void 52628646821SStefan Richter remove_card(struct pci_dev *dev) 52728646821SStefan Richter { 528424d66ceSStefan Richter struct pcilynx *lynx = pci_get_drvdata(dev); 529424d66ceSStefan Richter struct client *client; 53028646821SStefan Richter 531424d66ceSStefan Richter mutex_lock(&card_mutex); 532424d66ceSStefan Richter list_del_init(&lynx->link); 533424d66ceSStefan Richter misc_deregister(&lynx->misc); 534424d66ceSStefan Richter mutex_unlock(&card_mutex); 53528646821SStefan Richter 53628646821SStefan Richter reg_write(lynx, PCI_INT_ENABLE, 0); 53728646821SStefan Richter free_irq(lynx->pci_device->irq, lynx); 53828646821SStefan Richter 539424d66ceSStefan Richter spin_lock_irq(&lynx->client_list_lock); 540424d66ceSStefan Richter list_for_each_entry(client, &lynx->client_list, link) 541424d66ceSStefan Richter wake_up_interruptible(&client->buffer.wait); 542424d66ceSStefan Richter spin_unlock_irq(&lynx->client_list_lock); 543424d66ceSStefan Richter 54428646821SStefan Richter pci_free_consistent(lynx->pci_device, sizeof(struct pcl), 54528646821SStefan Richter lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); 54628646821SStefan Richter pci_free_consistent(lynx->pci_device, sizeof(struct pcl), 54728646821SStefan Richter lynx->rcv_pcl, lynx->rcv_pcl_bus); 54828646821SStefan Richter pci_free_consistent(lynx->pci_device, PAGE_SIZE, 54928646821SStefan Richter lynx->rcv_buffer, lynx->rcv_buffer_bus); 55028646821SStefan Richter 55128646821SStefan Richter iounmap(lynx->registers); 552b6d9c125SStefan Richter pci_disable_device(dev); 553424d66ceSStefan Richter lynx_put(lynx); 55428646821SStefan Richter } 55528646821SStefan Richter 55628646821SStefan Richter #define RCV_BUFFER_SIZE (16 * 1024) 55728646821SStefan Richter 55828646821SStefan Richter static int __devinit 55928646821SStefan Richter add_card(struct pci_dev *dev, const struct pci_device_id *unused) 56028646821SStefan Richter { 56128646821SStefan Richter struct pcilynx *lynx; 56228646821SStefan Richter u32 p, end; 563b6d9c125SStefan Richter int ret, i; 56428646821SStefan Richter 565b5e47729SStefan Richter if (pci_set_dma_mask(dev, 0xffffffff)) { 566b5e47729SStefan Richter error("DMA address limits not supported " 567b5e47729SStefan Richter "for PCILynx hardware\n"); 568b5e47729SStefan Richter return -ENXIO; 569b5e47729SStefan Richter } 570b5e47729SStefan Richter if (pci_enable_device(dev)) { 571b5e47729SStefan Richter error("Failed to enable PCILynx hardware\n"); 572b5e47729SStefan Richter return -ENXIO; 573b5e47729SStefan Richter } 57428646821SStefan Richter pci_set_master(dev); 57528646821SStefan Richter 57628646821SStefan Richter lynx = kzalloc(sizeof *lynx, GFP_KERNEL); 577b5e47729SStefan Richter if (lynx == NULL) { 578b5e47729SStefan Richter error("Failed to allocate control structure memory\n"); 579b6d9c125SStefan Richter ret = -ENOMEM; 580b6d9c125SStefan Richter goto fail_disable; 581b5e47729SStefan Richter } 58228646821SStefan Richter lynx->pci_device = dev; 58328646821SStefan Richter pci_set_drvdata(dev, lynx); 58428646821SStefan Richter 58528646821SStefan Richter spin_lock_init(&lynx->client_list_lock); 58628646821SStefan Richter INIT_LIST_HEAD(&lynx->client_list); 587424d66ceSStefan Richter kref_init(&lynx->kref); 58828646821SStefan Richter 58928646821SStefan Richter lynx->registers = ioremap_nocache(pci_resource_start(dev, 0), 59028646821SStefan Richter PCILYNX_MAX_REGISTER); 59128646821SStefan Richter 59228646821SStefan Richter lynx->rcv_start_pcl = pci_alloc_consistent(lynx->pci_device, 593b5e47729SStefan Richter sizeof(struct pcl), &lynx->rcv_start_pcl_bus); 59428646821SStefan Richter lynx->rcv_pcl = pci_alloc_consistent(lynx->pci_device, 595b5e47729SStefan Richter sizeof(struct pcl), &lynx->rcv_pcl_bus); 596b5e47729SStefan Richter lynx->rcv_buffer = pci_alloc_consistent(lynx->pci_device, 597b5e47729SStefan Richter RCV_BUFFER_SIZE, &lynx->rcv_buffer_bus); 59828646821SStefan Richter if (lynx->rcv_start_pcl == NULL || 59928646821SStefan Richter lynx->rcv_pcl == NULL || 600b5e47729SStefan Richter lynx->rcv_buffer == NULL) { 601b5e47729SStefan Richter error("Failed to allocate receive buffer\n"); 602b6d9c125SStefan Richter ret = -ENOMEM; 603b6d9c125SStefan Richter goto fail_deallocate; 604b5e47729SStefan Richter } 60528646821SStefan Richter lynx->rcv_start_pcl->next = lynx->rcv_pcl_bus; 60628646821SStefan Richter lynx->rcv_pcl->next = PCL_NEXT_INVALID; 60728646821SStefan Richter lynx->rcv_pcl->async_error_next = PCL_NEXT_INVALID; 60828646821SStefan Richter 60928646821SStefan Richter lynx->rcv_pcl->buffer[0].control = 61028646821SStefan Richter PCL_CMD_RCV | PCL_BIGENDIAN | 2044; 61128646821SStefan Richter lynx->rcv_pcl->buffer[0].pointer = lynx->rcv_buffer_bus + 4; 61228646821SStefan Richter p = lynx->rcv_buffer_bus + 2048; 61328646821SStefan Richter end = lynx->rcv_buffer_bus + RCV_BUFFER_SIZE; 61428646821SStefan Richter for (i = 1; p < end; i++, p += 2048) { 61528646821SStefan Richter lynx->rcv_pcl->buffer[i].control = 61628646821SStefan Richter PCL_CMD_RCV | PCL_BIGENDIAN | 2048; 61728646821SStefan Richter lynx->rcv_pcl->buffer[i].pointer = p; 61828646821SStefan Richter } 61928646821SStefan Richter lynx->rcv_pcl->buffer[i - 1].control |= PCL_LAST_BUFF; 62028646821SStefan Richter 62128646821SStefan Richter reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); 62228646821SStefan Richter /* Fix buggy cards with autoboot pin not tied low: */ 62328646821SStefan Richter reg_write(lynx, DMA0_CHAN_CTRL, 0); 62428646821SStefan Richter reg_write(lynx, DMA_GLOBAL_REGISTER, 0x00 << 24); 62528646821SStefan Richter 62628646821SStefan Richter #if 0 62728646821SStefan Richter /* now, looking for PHY register set */ 62828646821SStefan Richter if ((get_phy_reg(lynx, 2) & 0xe0) == 0xe0) { 62928646821SStefan Richter lynx->phyic.reg_1394a = 1; 63028646821SStefan Richter PRINT(KERN_INFO, lynx->id, 63128646821SStefan Richter "found 1394a conform PHY (using extended register set)"); 63228646821SStefan Richter lynx->phyic.vendor = get_phy_vendorid(lynx); 63328646821SStefan Richter lynx->phyic.product = get_phy_productid(lynx); 63428646821SStefan Richter } else { 63528646821SStefan Richter lynx->phyic.reg_1394a = 0; 63628646821SStefan Richter PRINT(KERN_INFO, lynx->id, "found old 1394 PHY"); 63728646821SStefan Richter } 63828646821SStefan Richter #endif 63928646821SStefan Richter 64028646821SStefan Richter /* Setup the general receive FIFO max size. */ 64128646821SStefan Richter reg_write(lynx, FIFO_SIZES, 255); 64228646821SStefan Richter 64328646821SStefan Richter reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL); 64428646821SStefan Richter 64528646821SStefan Richter reg_write(lynx, LINK_INT_ENABLE, 64628646821SStefan Richter LINK_INT_PHY_TIME_OUT | LINK_INT_PHY_REG_RCVD | 64728646821SStefan Richter LINK_INT_PHY_BUSRESET | LINK_INT_IT_STUCK | 64828646821SStefan Richter LINK_INT_AT_STUCK | LINK_INT_SNTRJ | 64928646821SStefan Richter LINK_INT_TC_ERR | LINK_INT_GRF_OVER_FLOW | 65028646821SStefan Richter LINK_INT_ITF_UNDER_FLOW | LINK_INT_ATF_UNDER_FLOW); 65128646821SStefan Richter 65228646821SStefan Richter /* Disable the L flag in self ID packets. */ 65328646821SStefan Richter set_phy_reg(lynx, 4, 0); 65428646821SStefan Richter 65528646821SStefan Richter /* Put this baby into snoop mode */ 65628646821SStefan Richter reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_SNOOP_ENABLE); 65728646821SStefan Richter 65828646821SStefan Richter run_pcl(lynx, lynx->rcv_start_pcl_bus, 0); 65928646821SStefan Richter 660b5e47729SStefan Richter if (request_irq(dev->irq, irq_handler, IRQF_SHARED, 661b5e47729SStefan Richter driver_name, lynx)) { 662b5e47729SStefan Richter error("Failed to allocate shared interrupt %d\n", dev->irq); 663b6d9c125SStefan Richter ret = -EIO; 664b6d9c125SStefan Richter goto fail_deallocate; 665b5e47729SStefan Richter } 66628646821SStefan Richter 66728646821SStefan Richter lynx->misc.parent = &dev->dev; 66828646821SStefan Richter lynx->misc.minor = MISC_DYNAMIC_MINOR; 66928646821SStefan Richter lynx->misc.name = "nosy"; 67028646821SStefan Richter lynx->misc.fops = &nosy_ops; 671424d66ceSStefan Richter 672424d66ceSStefan Richter mutex_lock(&card_mutex); 673b6d9c125SStefan Richter ret = misc_register(&lynx->misc); 674b6d9c125SStefan Richter if (ret) { 675b5e47729SStefan Richter error("Failed to register misc char device\n"); 676424d66ceSStefan Richter mutex_unlock(&card_mutex); 677b6d9c125SStefan Richter goto fail_free_irq; 678b5e47729SStefan Richter } 679424d66ceSStefan Richter list_add_tail(&lynx->link, &card_list); 680424d66ceSStefan Richter mutex_unlock(&card_mutex); 68128646821SStefan Richter 68228646821SStefan Richter notify("Initialized PCILynx IEEE1394 card, irq=%d\n", dev->irq); 68328646821SStefan Richter 68428646821SStefan Richter return 0; 685b6d9c125SStefan Richter 686b6d9c125SStefan Richter fail_free_irq: 687b6d9c125SStefan Richter reg_write(lynx, PCI_INT_ENABLE, 0); 688b6d9c125SStefan Richter free_irq(lynx->pci_device->irq, lynx); 689b6d9c125SStefan Richter 690b6d9c125SStefan Richter fail_deallocate: 691b6d9c125SStefan Richter if (lynx->rcv_start_pcl) 692b6d9c125SStefan Richter pci_free_consistent(lynx->pci_device, sizeof(struct pcl), 693b6d9c125SStefan Richter lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); 694b6d9c125SStefan Richter if (lynx->rcv_pcl) 695b6d9c125SStefan Richter pci_free_consistent(lynx->pci_device, sizeof(struct pcl), 696b6d9c125SStefan Richter lynx->rcv_pcl, lynx->rcv_pcl_bus); 697b6d9c125SStefan Richter if (lynx->rcv_buffer) 698b6d9c125SStefan Richter pci_free_consistent(lynx->pci_device, PAGE_SIZE, 699b6d9c125SStefan Richter lynx->rcv_buffer, lynx->rcv_buffer_bus); 700b6d9c125SStefan Richter iounmap(lynx->registers); 701b6d9c125SStefan Richter kfree(lynx); 702b6d9c125SStefan Richter 703b6d9c125SStefan Richter fail_disable: 704b6d9c125SStefan Richter pci_disable_device(dev); 705b6d9c125SStefan Richter 706b6d9c125SStefan Richter return ret; 70728646821SStefan Richter } 70828646821SStefan Richter 70928646821SStefan Richter static struct pci_device_id pci_table[] __devinitdata = { 71028646821SStefan Richter { 71128646821SStefan Richter .vendor = PCI_VENDOR_ID_TI, 71228646821SStefan Richter .device = PCI_DEVICE_ID_TI_PCILYNX, 71328646821SStefan Richter .subvendor = PCI_ANY_ID, 71428646821SStefan Richter .subdevice = PCI_ANY_ID, 71528646821SStefan Richter }, 71628646821SStefan Richter { } /* Terminating entry */ 71728646821SStefan Richter }; 71828646821SStefan Richter 71928646821SStefan Richter static struct pci_driver lynx_pci_driver = { 720b5e47729SStefan Richter .name = driver_name, 72128646821SStefan Richter .id_table = pci_table, 72228646821SStefan Richter .probe = add_card, 723b5e47729SStefan Richter .remove = remove_card, 72428646821SStefan Richter }; 72528646821SStefan Richter 726b5e47729SStefan Richter MODULE_AUTHOR("Kristian Hoegsberg"); 72728646821SStefan Richter MODULE_DESCRIPTION("Snoop mode driver for TI pcilynx 1394 controllers"); 72828646821SStefan Richter MODULE_LICENSE("GPL"); 72928646821SStefan Richter MODULE_DEVICE_TABLE(pci, pci_table); 73028646821SStefan Richter 73128646821SStefan Richter static int __init nosy_init(void) 73228646821SStefan Richter { 73328646821SStefan Richter return pci_register_driver(&lynx_pci_driver); 73428646821SStefan Richter } 73528646821SStefan Richter 73628646821SStefan Richter static void __exit nosy_cleanup(void) 73728646821SStefan Richter { 73828646821SStefan Richter pci_unregister_driver(&lynx_pci_driver); 73928646821SStefan Richter 74028646821SStefan Richter notify("Unloaded %s.\n", driver_name); 74128646821SStefan Richter } 74228646821SStefan Richter 74328646821SStefan Richter module_init(nosy_init); 74428646821SStefan Richter module_exit(nosy_cleanup); 745