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> 2628646821SStefan Richter #include <linux/miscdevice.h> 27b5e47729SStefan Richter #include <linux/module.h> 28b5e47729SStefan Richter #include <linux/pci.h> 29b5e47729SStefan Richter #include <linux/poll.h> 30b5e47729SStefan Richter #include <linux/sched.h> /* required for linux/wait.h */ 31b5e47729SStefan Richter #include <linux/slab.h> 32b5e47729SStefan Richter #include <linux/spinlock.h> 33b5e47729SStefan Richter #include <linux/timex.h> 34b5e47729SStefan Richter #include <linux/uaccess.h> 35b5e47729SStefan Richter #include <linux/wait.h> 36b5e47729SStefan Richter 3728646821SStefan Richter #include <asm/atomic.h> 38b5e47729SStefan Richter #include <asm/byteorder.h> 3928646821SStefan Richter 4028646821SStefan Richter #include "nosy.h" 4128646821SStefan Richter #include "nosy-user.h" 4228646821SStefan Richter 4328646821SStefan Richter #define TCODE_PHY_PACKET 0x10 4428646821SStefan Richter #define PCI_DEVICE_ID_TI_PCILYNX 0x8000 4528646821SStefan Richter 4628646821SStefan Richter #define notify(s, args...) printk(KERN_NOTICE s, ## args) 4728646821SStefan Richter #define error(s, args...) printk(KERN_ERR s, ## args) 4828646821SStefan Richter #define debug(s, args...) printk(KERN_DEBUG s, ## args) 4928646821SStefan Richter 50b5e47729SStefan Richter static char driver_name[] = KBUILD_MODNAME; 5128646821SStefan Richter 5228646821SStefan Richter struct pcl_status { 5328646821SStefan Richter unsigned int transfer_count : 13; 5428646821SStefan Richter unsigned int reserved0 : 1; 5528646821SStefan Richter unsigned int ack_type : 1; 5628646821SStefan Richter unsigned int ack : 4; 5728646821SStefan Richter unsigned int rcv_speed : 2; 5828646821SStefan Richter unsigned int rcv_dma_channel : 6; 5928646821SStefan Richter unsigned int packet_complete : 1; 6028646821SStefan Richter unsigned int packet_error : 1; 6128646821SStefan Richter unsigned int master_error : 1; 6228646821SStefan Richter unsigned int iso_mode : 1; 6328646821SStefan Richter unsigned int self_id : 1; 6428646821SStefan Richter }; 6528646821SStefan Richter 6628646821SStefan Richter /* this is the physical layout of a PCL, its size is 128 bytes */ 6728646821SStefan Richter struct pcl { 6828646821SStefan Richter u32 next; 6928646821SStefan Richter u32 async_error_next; 7028646821SStefan Richter u32 user_data; 7128646821SStefan Richter struct pcl_status pcl_status; 7228646821SStefan Richter u32 remaining_transfer_count; 7328646821SStefan Richter u32 next_data_buffer; 7428646821SStefan Richter struct { 7528646821SStefan Richter u32 control; 7628646821SStefan Richter u32 pointer; 7728646821SStefan Richter } buffer[13] __attribute__ ((packed)); 7828646821SStefan Richter } __attribute__ ((packed)); 7928646821SStefan Richter 8028646821SStefan Richter struct packet { 81b5e47729SStefan Richter unsigned int length; 8228646821SStefan Richter char data[0]; 8328646821SStefan Richter }; 8428646821SStefan Richter 8528646821SStefan Richter struct packet_buffer { 8628646821SStefan Richter char *data; 8728646821SStefan Richter size_t capacity; 8828646821SStefan Richter long total_packet_count, lost_packet_count; 8928646821SStefan Richter atomic_t size; 9028646821SStefan Richter struct packet *head, *tail; 9128646821SStefan Richter wait_queue_head_t wait; 9228646821SStefan Richter }; 9328646821SStefan Richter 9428646821SStefan Richter struct pcilynx { 9528646821SStefan Richter struct pci_dev *pci_device; 9628646821SStefan Richter unsigned char *registers; 9728646821SStefan Richter 9828646821SStefan Richter struct pcl *rcv_start_pcl, *rcv_pcl; 9928646821SStefan Richter u32 *rcv_buffer; 10028646821SStefan Richter 10128646821SStefan Richter dma_addr_t rcv_start_pcl_bus, rcv_pcl_bus, rcv_buffer_bus; 10228646821SStefan Richter 10328646821SStefan Richter spinlock_t client_list_lock; 10428646821SStefan Richter struct list_head client_list; 10528646821SStefan Richter 10628646821SStefan Richter struct miscdevice misc; 10728646821SStefan Richter }; 10828646821SStefan Richter 10928646821SStefan Richter struct client { 11028646821SStefan Richter struct pcilynx *lynx; 111c7b2a99cSStefan Richter u32 tcode_mask; 11228646821SStefan Richter struct packet_buffer buffer; 11328646821SStefan Richter struct list_head link; 11428646821SStefan Richter }; 11528646821SStefan Richter 11628646821SStefan Richter #define MAX_MINORS 64 117b5e47729SStefan Richter static struct pcilynx *minors[MAX_MINORS]; 11828646821SStefan Richter 11928646821SStefan Richter static int 12028646821SStefan Richter packet_buffer_init(struct packet_buffer *buffer, size_t capacity) 12128646821SStefan Richter { 12228646821SStefan Richter buffer->data = kmalloc(capacity, GFP_KERNEL); 12328646821SStefan Richter if (buffer->data == NULL) 12428646821SStefan Richter return -ENOMEM; 12528646821SStefan Richter buffer->head = (struct packet *) buffer->data; 12628646821SStefan Richter buffer->tail = (struct packet *) buffer->data; 12728646821SStefan Richter buffer->capacity = capacity; 12828646821SStefan Richter buffer->lost_packet_count = 0; 12928646821SStefan Richter atomic_set(&buffer->size, 0); 13028646821SStefan Richter init_waitqueue_head(&buffer->wait); 13128646821SStefan Richter 13228646821SStefan Richter return 0; 13328646821SStefan Richter } 13428646821SStefan Richter 13528646821SStefan Richter static void 13628646821SStefan Richter packet_buffer_destroy(struct packet_buffer *buffer) 13728646821SStefan Richter { 13828646821SStefan Richter kfree(buffer->data); 13928646821SStefan Richter } 14028646821SStefan Richter 14128646821SStefan Richter static int 14228646821SStefan Richter packet_buffer_get(struct packet_buffer *buffer, void *data, size_t user_length) 14328646821SStefan Richter { 14428646821SStefan Richter size_t length; 14528646821SStefan Richter char *end; 14628646821SStefan Richter 14728646821SStefan Richter if (wait_event_interruptible(buffer->wait, 14828646821SStefan Richter atomic_read(&buffer->size) > 0)) 14928646821SStefan Richter return -ERESTARTSYS; 15028646821SStefan Richter 15128646821SStefan Richter /* FIXME: Check length <= user_length. */ 15228646821SStefan Richter 15328646821SStefan Richter end = buffer->data + buffer->capacity; 15428646821SStefan Richter length = buffer->head->length; 15528646821SStefan Richter 15628646821SStefan Richter if (&buffer->head->data[length] < end) { 15728646821SStefan Richter if (copy_to_user(data, buffer->head->data, length)) 15828646821SStefan Richter return -EFAULT; 15928646821SStefan Richter buffer->head = (struct packet *) &buffer->head->data[length]; 160b5e47729SStefan Richter } else { 16128646821SStefan Richter size_t split = end - buffer->head->data; 16228646821SStefan Richter 16328646821SStefan Richter if (copy_to_user(data, buffer->head->data, split)) 16428646821SStefan Richter return -EFAULT; 16528646821SStefan Richter if (copy_to_user(data + split, buffer->data, length - split)) 16628646821SStefan Richter return -EFAULT; 16728646821SStefan Richter buffer->head = (struct packet *) &buffer->data[length - split]; 16828646821SStefan Richter } 16928646821SStefan Richter 170b5e47729SStefan Richter /* 171b5e47729SStefan Richter * Decrease buffer->size as the last thing, since this is what 17228646821SStefan Richter * keeps the interrupt from overwriting the packet we are 173b5e47729SStefan Richter * retrieving from the buffer. 174b5e47729SStefan Richter */ 17528646821SStefan Richter atomic_sub(sizeof(struct packet) + length, &buffer->size); 17628646821SStefan Richter 17728646821SStefan Richter return length; 17828646821SStefan Richter } 17928646821SStefan Richter 18028646821SStefan Richter static void 18128646821SStefan Richter packet_buffer_put(struct packet_buffer *buffer, void *data, size_t length) 18228646821SStefan Richter { 18328646821SStefan Richter char *end; 18428646821SStefan Richter 18528646821SStefan Richter buffer->total_packet_count++; 18628646821SStefan Richter 18728646821SStefan Richter if (buffer->capacity < 18828646821SStefan Richter atomic_read(&buffer->size) + sizeof(struct packet) + length) { 18928646821SStefan Richter buffer->lost_packet_count++; 19028646821SStefan Richter return; 19128646821SStefan Richter } 19228646821SStefan Richter 19328646821SStefan Richter end = buffer->data + buffer->capacity; 19428646821SStefan Richter buffer->tail->length = length; 19528646821SStefan Richter 19628646821SStefan Richter if (&buffer->tail->data[length] < end) { 19728646821SStefan Richter memcpy(buffer->tail->data, data, length); 19828646821SStefan Richter buffer->tail = (struct packet *) &buffer->tail->data[length]; 199b5e47729SStefan Richter } else { 20028646821SStefan Richter size_t split = end - buffer->tail->data; 20128646821SStefan Richter 20228646821SStefan Richter memcpy(buffer->tail->data, data, split); 20328646821SStefan Richter memcpy(buffer->data, data + split, length - split); 20428646821SStefan Richter buffer->tail = (struct packet *) &buffer->data[length - split]; 20528646821SStefan Richter } 20628646821SStefan Richter 20728646821SStefan Richter /* Finally, adjust buffer size and wake up userspace reader. */ 20828646821SStefan Richter 20928646821SStefan Richter atomic_add(sizeof(struct packet) + length, &buffer->size); 21028646821SStefan Richter wake_up_interruptible(&buffer->wait); 21128646821SStefan Richter } 21228646821SStefan Richter 21328646821SStefan Richter static inline void 21428646821SStefan Richter reg_write(struct pcilynx *lynx, int offset, u32 data) 21528646821SStefan Richter { 21628646821SStefan Richter writel(data, lynx->registers + offset); 21728646821SStefan Richter } 21828646821SStefan Richter 21928646821SStefan Richter static inline u32 22028646821SStefan Richter reg_read(struct pcilynx *lynx, int offset) 22128646821SStefan Richter { 22228646821SStefan Richter return readl(lynx->registers + offset); 22328646821SStefan Richter } 22428646821SStefan Richter 22528646821SStefan Richter static inline void 22628646821SStefan Richter reg_set_bits(struct pcilynx *lynx, int offset, u32 mask) 22728646821SStefan Richter { 22828646821SStefan Richter reg_write(lynx, offset, (reg_read(lynx, offset) | mask)); 22928646821SStefan Richter } 23028646821SStefan Richter 231b5e47729SStefan Richter /* 232b5e47729SStefan Richter * Maybe the pcl programs could be set up to just append data instead 233b5e47729SStefan Richter * of using a whole packet. 234b5e47729SStefan Richter */ 23528646821SStefan Richter static inline void 236b5e47729SStefan Richter run_pcl(struct pcilynx *lynx, dma_addr_t pcl_bus, 237b5e47729SStefan Richter int dmachan) 23828646821SStefan Richter { 23928646821SStefan Richter reg_write(lynx, DMA0_CURRENT_PCL + dmachan * 0x20, pcl_bus); 24028646821SStefan Richter reg_write(lynx, DMA0_CHAN_CTRL + dmachan * 0x20, 24128646821SStefan Richter DMA_CHAN_CTRL_ENABLE | DMA_CHAN_CTRL_LINK); 24228646821SStefan Richter } 24328646821SStefan Richter 24428646821SStefan Richter static int 24528646821SStefan Richter set_phy_reg(struct pcilynx *lynx, int addr, int val) 24628646821SStefan Richter { 24728646821SStefan Richter if (addr > 15) { 248b5e47729SStefan Richter debug("PHY register address %d out of range\n", addr); 24928646821SStefan Richter return -1; 25028646821SStefan Richter } 25128646821SStefan Richter 25228646821SStefan Richter if (val > 0xff) { 253b5e47729SStefan Richter debug("PHY register value %d out of range\n", val); 25428646821SStefan Richter return -1; 25528646821SStefan Richter } 25628646821SStefan Richter 25728646821SStefan Richter reg_write(lynx, LINK_PHY, LINK_PHY_WRITE | 25828646821SStefan Richter LINK_PHY_ADDR(addr) | LINK_PHY_WDATA(val)); 25928646821SStefan Richter 26028646821SStefan Richter return 0; 26128646821SStefan Richter } 26228646821SStefan Richter 26328646821SStefan Richter static int 26428646821SStefan Richter nosy_open(struct inode *inode, struct file *file) 26528646821SStefan Richter { 26628646821SStefan Richter int minor = iminor(inode); 26755e77c06SStefan Richter struct client *client; 26828646821SStefan Richter 26928646821SStefan Richter if (minor > MAX_MINORS || minors[minor] == NULL) 27028646821SStefan Richter return -ENODEV; 27128646821SStefan Richter 27255e77c06SStefan Richter client = kmalloc(sizeof *client, GFP_KERNEL); 27355e77c06SStefan Richter if (client == NULL) 27428646821SStefan Richter return -ENOMEM; 27555e77c06SStefan Richter 27655e77c06SStefan Richter client->tcode_mask = ~0; 27755e77c06SStefan Richter client->lynx = minors[minor]; 27855e77c06SStefan Richter INIT_LIST_HEAD(&client->link); 27955e77c06SStefan Richter 28055e77c06SStefan Richter if (packet_buffer_init(&client->buffer, 128 * 1024) < 0) { 28155e77c06SStefan Richter kfree(client); 28255e77c06SStefan Richter return -ENOMEM; 28355e77c06SStefan Richter } 28455e77c06SStefan Richter 28555e77c06SStefan Richter file->private_data = client; 28655e77c06SStefan Richter 28728646821SStefan Richter return 0; 28828646821SStefan Richter } 28928646821SStefan Richter 29028646821SStefan Richter static int 29128646821SStefan Richter nosy_release(struct inode *inode, struct file *file) 29228646821SStefan Richter { 29355e77c06SStefan Richter struct client *client = file->private_data; 29455e77c06SStefan Richter 29555e77c06SStefan Richter spin_lock_irq(&client->lynx->client_list_lock); 29655e77c06SStefan Richter list_del_init(&client->link); 29755e77c06SStefan Richter spin_unlock_irq(&client->lynx->client_list_lock); 29855e77c06SStefan Richter 29955e77c06SStefan Richter packet_buffer_destroy(&client->buffer); 30055e77c06SStefan Richter kfree(client); 30128646821SStefan Richter 30228646821SStefan Richter return 0; 30328646821SStefan Richter } 30428646821SStefan Richter 30528646821SStefan Richter static unsigned int 30628646821SStefan Richter nosy_poll(struct file *file, poll_table *pt) 30728646821SStefan Richter { 30828646821SStefan Richter struct client *client = file->private_data; 30928646821SStefan Richter 31028646821SStefan Richter poll_wait(file, &client->buffer.wait, pt); 31128646821SStefan Richter 31228646821SStefan Richter if (atomic_read(&client->buffer.size) > 0) 31328646821SStefan Richter return POLLIN | POLLRDNORM; 31428646821SStefan Richter else 31528646821SStefan Richter return 0; 31628646821SStefan Richter } 31728646821SStefan Richter 31828646821SStefan Richter static ssize_t 31928646821SStefan Richter nosy_read(struct file *file, char *buffer, size_t count, loff_t *offset) 32028646821SStefan Richter { 32128646821SStefan Richter struct client *client = file->private_data; 32228646821SStefan Richter 32328646821SStefan Richter return packet_buffer_get(&client->buffer, buffer, count); 32428646821SStefan Richter } 32528646821SStefan Richter 326c7b2a99cSStefan Richter static long 327c7b2a99cSStefan Richter nosy_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 32828646821SStefan Richter { 32928646821SStefan Richter struct client *client = file->private_data; 330c7b2a99cSStefan Richter spinlock_t *client_list_lock = &client->lynx->client_list_lock; 33128646821SStefan Richter struct nosy_stats stats; 33228646821SStefan Richter 333b5e47729SStefan Richter switch (cmd) { 334b5e47729SStefan Richter case NOSY_IOC_GET_STATS: 335c7b2a99cSStefan Richter spin_lock_irq(client_list_lock); 33628646821SStefan Richter stats.total_packet_count = client->buffer.total_packet_count; 33728646821SStefan Richter stats.lost_packet_count = client->buffer.lost_packet_count; 338c7b2a99cSStefan Richter spin_unlock_irq(client_list_lock); 339c7b2a99cSStefan Richter 34028646821SStefan Richter if (copy_to_user((void *) arg, &stats, sizeof stats)) 34128646821SStefan Richter return -EFAULT; 34228646821SStefan Richter else 34328646821SStefan Richter return 0; 34428646821SStefan Richter 34528646821SStefan Richter case NOSY_IOC_START: 34655e77c06SStefan Richter spin_lock_irq(client_list_lock); 34755e77c06SStefan Richter list_add_tail(&client->link, &client->lynx->client_list); 34855e77c06SStefan Richter spin_unlock_irq(client_list_lock); 34955e77c06SStefan Richter 35028646821SStefan Richter return 0; 35128646821SStefan Richter 35228646821SStefan Richter case NOSY_IOC_STOP: 35355e77c06SStefan Richter spin_lock_irq(client_list_lock); 35455e77c06SStefan Richter list_del_init(&client->link); 35555e77c06SStefan Richter spin_unlock_irq(client_list_lock); 35655e77c06SStefan Richter 35728646821SStefan Richter return 0; 35828646821SStefan Richter 35928646821SStefan Richter case NOSY_IOC_FILTER: 360c7b2a99cSStefan Richter spin_lock_irq(client_list_lock); 36128646821SStefan Richter client->tcode_mask = arg; 362c7b2a99cSStefan Richter spin_unlock_irq(client_list_lock); 36355e77c06SStefan Richter 36428646821SStefan Richter return 0; 36528646821SStefan Richter 36628646821SStefan Richter default: 36728646821SStefan Richter return -EINVAL; 36828646821SStefan Richter /* Flush buffer, configure filter. */ 36928646821SStefan Richter } 37028646821SStefan Richter } 37128646821SStefan Richter 372b5e47729SStefan Richter static const struct file_operations nosy_ops = { 37328646821SStefan Richter .owner = THIS_MODULE, 37428646821SStefan Richter .read = nosy_read, 375c7b2a99cSStefan Richter .unlocked_ioctl = nosy_ioctl, 37628646821SStefan Richter .poll = nosy_poll, 37728646821SStefan Richter .open = nosy_open, 37828646821SStefan Richter .release = nosy_release, 37928646821SStefan Richter }; 38028646821SStefan Richter 38128646821SStefan Richter #define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */ 38228646821SStefan Richter 38328646821SStefan Richter struct link_packet { 38428646821SStefan Richter unsigned int priority : 4; 38528646821SStefan Richter unsigned int tcode : 4; 38628646821SStefan Richter unsigned int rt : 2; 38728646821SStefan Richter unsigned int tlabel : 6; 38828646821SStefan Richter unsigned int destination : 16; 38928646821SStefan Richter }; 39028646821SStefan Richter 39128646821SStefan Richter static void 392685c3f80SStefan Richter packet_irq_handler(struct pcilynx *lynx) 39328646821SStefan Richter { 39428646821SStefan Richter struct client *client; 395c7b2a99cSStefan Richter u32 tcode_mask; 39628646821SStefan Richter size_t length; 39728646821SStefan Richter struct link_packet *packet; 39828646821SStefan Richter struct timeval tv; 39928646821SStefan Richter 40028646821SStefan Richter /* FIXME: Also report rcv_speed. */ 40128646821SStefan Richter 40228646821SStefan Richter length = lynx->rcv_pcl->pcl_status.transfer_count; 40328646821SStefan Richter packet = (struct link_packet *) &lynx->rcv_buffer[1]; 40428646821SStefan Richter 40528646821SStefan Richter do_gettimeofday(&tv); 40628646821SStefan Richter lynx->rcv_buffer[0] = tv.tv_usec; 40728646821SStefan Richter 40828646821SStefan Richter if (length == PHY_PACKET_SIZE) 40928646821SStefan Richter tcode_mask = 1 << TCODE_PHY_PACKET; 41028646821SStefan Richter else 41128646821SStefan Richter tcode_mask = 1 << packet->tcode; 41228646821SStefan Richter 413685c3f80SStefan Richter spin_lock(&lynx->client_list_lock); 41428646821SStefan Richter 415b5e47729SStefan Richter list_for_each_entry(client, &lynx->client_list, link) 41628646821SStefan Richter if (client->tcode_mask & tcode_mask) 41728646821SStefan Richter packet_buffer_put(&client->buffer, 41828646821SStefan Richter lynx->rcv_buffer, length + 4); 41928646821SStefan Richter 420685c3f80SStefan Richter spin_unlock(&lynx->client_list_lock); 42128646821SStefan Richter } 42228646821SStefan Richter 42328646821SStefan Richter static void 424685c3f80SStefan Richter bus_reset_irq_handler(struct pcilynx *lynx) 42528646821SStefan Richter { 42628646821SStefan Richter struct client *client; 42728646821SStefan Richter struct timeval tv; 42828646821SStefan Richter 42928646821SStefan Richter do_gettimeofday(&tv); 43028646821SStefan Richter 431685c3f80SStefan Richter spin_lock(&lynx->client_list_lock); 43228646821SStefan Richter 433b5e47729SStefan Richter list_for_each_entry(client, &lynx->client_list, link) 43428646821SStefan Richter packet_buffer_put(&client->buffer, &tv.tv_usec, 4); 43528646821SStefan Richter 436685c3f80SStefan Richter spin_unlock(&lynx->client_list_lock); 43728646821SStefan Richter } 43828646821SStefan Richter 43928646821SStefan Richter static irqreturn_t 44028646821SStefan Richter irq_handler(int irq, void *device) 44128646821SStefan Richter { 442b5e47729SStefan Richter struct pcilynx *lynx = device; 44328646821SStefan Richter u32 pci_int_status; 44428646821SStefan Richter 44528646821SStefan Richter pci_int_status = reg_read(lynx, PCI_INT_STATUS); 44628646821SStefan Richter 44716547667SStefan Richter if (pci_int_status == ~0) 44816547667SStefan Richter /* Card was ejected. */ 44916547667SStefan Richter return IRQ_NONE; 45016547667SStefan Richter 45128646821SStefan Richter if ((pci_int_status & PCI_INT_INT_PEND) == 0) 45228646821SStefan Richter /* Not our interrupt, bail out quickly. */ 45328646821SStefan Richter return IRQ_NONE; 45428646821SStefan Richter 45528646821SStefan Richter if ((pci_int_status & PCI_INT_P1394_INT) != 0) { 45628646821SStefan Richter u32 link_int_status; 45728646821SStefan Richter 45828646821SStefan Richter link_int_status = reg_read(lynx, LINK_INT_STATUS); 45928646821SStefan Richter reg_write(lynx, LINK_INT_STATUS, link_int_status); 46028646821SStefan Richter 46128646821SStefan Richter if ((link_int_status & LINK_INT_PHY_BUSRESET) > 0) 462685c3f80SStefan Richter bus_reset_irq_handler(lynx); 46328646821SStefan Richter } 46428646821SStefan Richter 46528646821SStefan Richter /* Clear the PCI_INT_STATUS register only after clearing the 46628646821SStefan Richter * LINK_INT_STATUS register; otherwise the PCI_INT_P1394 will 46728646821SStefan Richter * be set again immediately. */ 46828646821SStefan Richter 46928646821SStefan Richter reg_write(lynx, PCI_INT_STATUS, pci_int_status); 47028646821SStefan Richter 47128646821SStefan Richter if ((pci_int_status & PCI_INT_DMA0_HLT) > 0) { 472685c3f80SStefan Richter packet_irq_handler(lynx); 47328646821SStefan Richter run_pcl(lynx, lynx->rcv_start_pcl_bus, 0); 47428646821SStefan Richter } 47528646821SStefan Richter 47628646821SStefan Richter return IRQ_HANDLED; 47728646821SStefan Richter } 47828646821SStefan Richter 47928646821SStefan Richter static void 48028646821SStefan Richter remove_card(struct pci_dev *dev) 48128646821SStefan Richter { 48228646821SStefan Richter struct pcilynx *lynx; 48328646821SStefan Richter 48428646821SStefan Richter lynx = pci_get_drvdata(dev); 48528646821SStefan Richter if (!lynx) 48628646821SStefan Richter return; 48728646821SStefan Richter pci_set_drvdata(dev, NULL); 48828646821SStefan Richter 48928646821SStefan Richter reg_write(lynx, PCI_INT_ENABLE, 0); 49028646821SStefan Richter free_irq(lynx->pci_device->irq, lynx); 49128646821SStefan Richter 49228646821SStefan Richter pci_free_consistent(lynx->pci_device, sizeof(struct pcl), 49328646821SStefan Richter lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); 49428646821SStefan Richter pci_free_consistent(lynx->pci_device, sizeof(struct pcl), 49528646821SStefan Richter lynx->rcv_pcl, lynx->rcv_pcl_bus); 49628646821SStefan Richter pci_free_consistent(lynx->pci_device, PAGE_SIZE, 49728646821SStefan Richter lynx->rcv_buffer, lynx->rcv_buffer_bus); 49828646821SStefan Richter 49928646821SStefan Richter iounmap(lynx->registers); 50028646821SStefan Richter 50128646821SStefan Richter minors[lynx->misc.minor] = NULL; 50228646821SStefan Richter misc_deregister(&lynx->misc); 50328646821SStefan Richter 50428646821SStefan Richter kfree(lynx); 50528646821SStefan Richter } 50628646821SStefan Richter 50728646821SStefan Richter #define RCV_BUFFER_SIZE (16 * 1024) 50828646821SStefan Richter 50928646821SStefan Richter static int __devinit 51028646821SStefan Richter add_card(struct pci_dev *dev, const struct pci_device_id *unused) 51128646821SStefan Richter { 51228646821SStefan Richter struct pcilynx *lynx; 51328646821SStefan Richter u32 p, end; 514b5e47729SStefan Richter int i; 51528646821SStefan Richter 516b5e47729SStefan Richter if (pci_set_dma_mask(dev, 0xffffffff)) { 517b5e47729SStefan Richter error("DMA address limits not supported " 518b5e47729SStefan Richter "for PCILynx hardware\n"); 519b5e47729SStefan Richter return -ENXIO; 520b5e47729SStefan Richter } 521b5e47729SStefan Richter if (pci_enable_device(dev)) { 522b5e47729SStefan Richter error("Failed to enable PCILynx hardware\n"); 523b5e47729SStefan Richter return -ENXIO; 524b5e47729SStefan Richter } 52528646821SStefan Richter pci_set_master(dev); 52628646821SStefan Richter 52728646821SStefan Richter lynx = kzalloc(sizeof *lynx, GFP_KERNEL); 528b5e47729SStefan Richter if (lynx == NULL) { 529b5e47729SStefan Richter error("Failed to allocate control structure memory\n"); 530b5e47729SStefan Richter return -ENOMEM; 531b5e47729SStefan Richter } 53228646821SStefan Richter lynx->pci_device = dev; 53328646821SStefan Richter pci_set_drvdata(dev, lynx); 53428646821SStefan Richter 53528646821SStefan Richter spin_lock_init(&lynx->client_list_lock); 53628646821SStefan Richter INIT_LIST_HEAD(&lynx->client_list); 53728646821SStefan Richter 53828646821SStefan Richter lynx->registers = ioremap_nocache(pci_resource_start(dev, 0), 53928646821SStefan Richter PCILYNX_MAX_REGISTER); 54028646821SStefan Richter 54128646821SStefan Richter lynx->rcv_start_pcl = pci_alloc_consistent(lynx->pci_device, 542b5e47729SStefan Richter sizeof(struct pcl), &lynx->rcv_start_pcl_bus); 54328646821SStefan Richter lynx->rcv_pcl = pci_alloc_consistent(lynx->pci_device, 544b5e47729SStefan Richter sizeof(struct pcl), &lynx->rcv_pcl_bus); 545b5e47729SStefan Richter lynx->rcv_buffer = pci_alloc_consistent(lynx->pci_device, 546b5e47729SStefan Richter RCV_BUFFER_SIZE, &lynx->rcv_buffer_bus); 54728646821SStefan Richter if (lynx->rcv_start_pcl == NULL || 54828646821SStefan Richter lynx->rcv_pcl == NULL || 549b5e47729SStefan Richter lynx->rcv_buffer == NULL) { 55028646821SStefan Richter /* FIXME: do proper error handling. */ 551b5e47729SStefan Richter error("Failed to allocate receive buffer\n"); 552b5e47729SStefan Richter return -ENOMEM; 553b5e47729SStefan Richter } 55428646821SStefan Richter lynx->rcv_start_pcl->next = lynx->rcv_pcl_bus; 55528646821SStefan Richter lynx->rcv_pcl->next = PCL_NEXT_INVALID; 55628646821SStefan Richter lynx->rcv_pcl->async_error_next = PCL_NEXT_INVALID; 55728646821SStefan Richter 55828646821SStefan Richter lynx->rcv_pcl->buffer[0].control = 55928646821SStefan Richter PCL_CMD_RCV | PCL_BIGENDIAN | 2044; 56028646821SStefan Richter lynx->rcv_pcl->buffer[0].pointer = lynx->rcv_buffer_bus + 4; 56128646821SStefan Richter p = lynx->rcv_buffer_bus + 2048; 56228646821SStefan Richter end = lynx->rcv_buffer_bus + RCV_BUFFER_SIZE; 56328646821SStefan Richter for (i = 1; p < end; i++, p += 2048) { 56428646821SStefan Richter lynx->rcv_pcl->buffer[i].control = 56528646821SStefan Richter PCL_CMD_RCV | PCL_BIGENDIAN | 2048; 56628646821SStefan Richter lynx->rcv_pcl->buffer[i].pointer = p; 56728646821SStefan Richter } 56828646821SStefan Richter lynx->rcv_pcl->buffer[i - 1].control |= PCL_LAST_BUFF; 56928646821SStefan Richter 57028646821SStefan Richter reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); 57128646821SStefan Richter /* Fix buggy cards with autoboot pin not tied low: */ 57228646821SStefan Richter reg_write(lynx, DMA0_CHAN_CTRL, 0); 57328646821SStefan Richter reg_write(lynx, DMA_GLOBAL_REGISTER, 0x00 << 24); 57428646821SStefan Richter 57528646821SStefan Richter #if 0 57628646821SStefan Richter /* now, looking for PHY register set */ 57728646821SStefan Richter if ((get_phy_reg(lynx, 2) & 0xe0) == 0xe0) { 57828646821SStefan Richter lynx->phyic.reg_1394a = 1; 57928646821SStefan Richter PRINT(KERN_INFO, lynx->id, 58028646821SStefan Richter "found 1394a conform PHY (using extended register set)"); 58128646821SStefan Richter lynx->phyic.vendor = get_phy_vendorid(lynx); 58228646821SStefan Richter lynx->phyic.product = get_phy_productid(lynx); 58328646821SStefan Richter } else { 58428646821SStefan Richter lynx->phyic.reg_1394a = 0; 58528646821SStefan Richter PRINT(KERN_INFO, lynx->id, "found old 1394 PHY"); 58628646821SStefan Richter } 58728646821SStefan Richter #endif 58828646821SStefan Richter 58928646821SStefan Richter /* Setup the general receive FIFO max size. */ 59028646821SStefan Richter reg_write(lynx, FIFO_SIZES, 255); 59128646821SStefan Richter 59228646821SStefan Richter reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL); 59328646821SStefan Richter 59428646821SStefan Richter reg_write(lynx, LINK_INT_ENABLE, 59528646821SStefan Richter LINK_INT_PHY_TIME_OUT | LINK_INT_PHY_REG_RCVD | 59628646821SStefan Richter LINK_INT_PHY_BUSRESET | LINK_INT_IT_STUCK | 59728646821SStefan Richter LINK_INT_AT_STUCK | LINK_INT_SNTRJ | 59828646821SStefan Richter LINK_INT_TC_ERR | LINK_INT_GRF_OVER_FLOW | 59928646821SStefan Richter LINK_INT_ITF_UNDER_FLOW | LINK_INT_ATF_UNDER_FLOW); 60028646821SStefan Richter 60128646821SStefan Richter /* Disable the L flag in self ID packets. */ 60228646821SStefan Richter set_phy_reg(lynx, 4, 0); 60328646821SStefan Richter 60428646821SStefan Richter /* Put this baby into snoop mode */ 60528646821SStefan Richter reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_SNOOP_ENABLE); 60628646821SStefan Richter 60728646821SStefan Richter run_pcl(lynx, lynx->rcv_start_pcl_bus, 0); 60828646821SStefan Richter 609b5e47729SStefan Richter if (request_irq(dev->irq, irq_handler, IRQF_SHARED, 610b5e47729SStefan Richter driver_name, lynx)) { 611b5e47729SStefan Richter error("Failed to allocate shared interrupt %d\n", dev->irq); 612b5e47729SStefan Richter return -EIO; 613b5e47729SStefan Richter } 61428646821SStefan Richter 61528646821SStefan Richter lynx->misc.parent = &dev->dev; 61628646821SStefan Richter lynx->misc.minor = MISC_DYNAMIC_MINOR; 61728646821SStefan Richter lynx->misc.name = "nosy"; 61828646821SStefan Richter lynx->misc.fops = &nosy_ops; 619b5e47729SStefan Richter if (misc_register(&lynx->misc)) { 620b5e47729SStefan Richter error("Failed to register misc char device\n"); 621b5e47729SStefan Richter return -ENOMEM; 622b5e47729SStefan Richter } 62328646821SStefan Richter minors[lynx->misc.minor] = lynx; 62428646821SStefan Richter 62528646821SStefan Richter notify("Initialized PCILynx IEEE1394 card, irq=%d\n", dev->irq); 62628646821SStefan Richter 62728646821SStefan Richter return 0; 62828646821SStefan Richter } 62928646821SStefan Richter 63028646821SStefan Richter static struct pci_device_id pci_table[] __devinitdata = { 63128646821SStefan Richter { 63228646821SStefan Richter .vendor = PCI_VENDOR_ID_TI, 63328646821SStefan Richter .device = PCI_DEVICE_ID_TI_PCILYNX, 63428646821SStefan Richter .subvendor = PCI_ANY_ID, 63528646821SStefan Richter .subdevice = PCI_ANY_ID, 63628646821SStefan Richter }, 63728646821SStefan Richter { } /* Terminating entry */ 63828646821SStefan Richter }; 63928646821SStefan Richter 64028646821SStefan Richter static struct pci_driver lynx_pci_driver = { 641b5e47729SStefan Richter .name = driver_name, 64228646821SStefan Richter .id_table = pci_table, 64328646821SStefan Richter .probe = add_card, 644b5e47729SStefan Richter .remove = remove_card, 64528646821SStefan Richter }; 64628646821SStefan Richter 647b5e47729SStefan Richter MODULE_AUTHOR("Kristian Hoegsberg"); 64828646821SStefan Richter MODULE_DESCRIPTION("Snoop mode driver for TI pcilynx 1394 controllers"); 64928646821SStefan Richter MODULE_LICENSE("GPL"); 65028646821SStefan Richter MODULE_DEVICE_TABLE(pci, pci_table); 65128646821SStefan Richter 65228646821SStefan Richter static int __init nosy_init(void) 65328646821SStefan Richter { 65428646821SStefan Richter return pci_register_driver(&lynx_pci_driver); 65528646821SStefan Richter } 65628646821SStefan Richter 65728646821SStefan Richter static void __exit nosy_cleanup(void) 65828646821SStefan Richter { 65928646821SStefan Richter pci_unregister_driver(&lynx_pci_driver); 66028646821SStefan Richter 66128646821SStefan Richter notify("Unloaded %s.\n", driver_name); 66228646821SStefan Richter } 66328646821SStefan Richter 66428646821SStefan Richter module_init(nosy_init); 66528646821SStefan Richter module_exit(nosy_cleanup); 666