kfifo: move struct kfifo in place

This is a new generic kernel FIFO implementation.

The current kernel fifo API is not very widely used, because it has to
many constrains.  Only 17 files in the current 2.6.31-rc5 used it.
FIFO's are like list's a very basic thing and a kfifo API which handles
the most use case would save a lot of development time and memory
resources.

I think this are the reasons why kfifo is not in use:

 - The API is to simple, important functions are missing
 - A fifo can be only allocated dynamically
 - There is a requirement of a spinlock whether you need it or not
 - There is no support for data records inside a fifo

So I decided to extend the kfifo in a more generic way without blowing up
the API to much.  The new API has the following benefits:

 - Generic usage: For kernel internal use and/or device driver.
 - Provide an API for the most use case.
 - Slim API: The whole API provides 25 functions.
 - Linux style habit.
 - DECLARE_KFIFO, DEFINE_KFIFO and INIT_KFIFO Macros
 - Direct copy_to_user from the fifo and copy_from_user into the fifo.
 - The kfifo itself is an in place member of the using data structure, this save an
   indirection access and does not waste the kernel allocator.
 - Lockless access: if only one reader and one writer is active on the fifo,
   which is the common use case, no additional locking is necessary.
 - Remove spinlock - give the user the freedom of choice what kind of locking to use if
   one is required.
 - Ability to handle records. Three type of records are supported:
   - Variable length records between 0-255 bytes, with a record size
     field of 1 bytes.
   - Variable length records between 0-65535 bytes, with a record size
     field of 2 bytes.
   - Fixed size records, which no record size field.
 - Preserve memory resource.
 - Performance!
 - Easy to use!

This patch:

Since most users want to have the kfifo as part of another object,
reorganize the code to allow including struct kfifo in another data
structure.  This requires changing the kfifo_alloc and kfifo_init
prototypes so that we pass an existing kfifo pointer into them.  This
patch changes the implementation and all existing users.

[[email protected]: fix warning]
Signed-off-by: Stefani Seibold <[email protected]>
Acked-by: Greg Kroah-Hartman <[email protected]>
Acked-by: Mauro Carvalho Chehab <[email protected]>
Acked-by: Andi Kleen <[email protected]>
Acked-by: Arnd Bergmann <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
This commit is contained in:
Stefani Seibold 2009-12-21 14:37:26 -08:00 • committed by Linus Torvalds
commit 4546548789
24 changed files with 238 additions and 259 deletions

View file

@ -37,7 +37,7 @@ static void recycle_frame(struct fhci_usb *usb, struct packet *pkt)
pkt->info = 0;
pkt->priv_data = NULL;
cq_put(usb->ep0->empty_frame_Q, pkt);
cq_put(&usb->ep0->empty_frame_Q, pkt);
}
/* confirm submitted packet */
@ -57,7 +57,7 @@ void fhci_transaction_confirm(struct fhci_usb *usb, struct packet *pkt)
if ((td->data + td->actual_len) && trans_len)
memcpy(td->data + td->actual_len, pkt->data,
trans_len);
cq_put(usb->ep0->dummy_packets_Q, pkt->data);
cq_put(&usb->ep0->dummy_packets_Q, pkt->data);
}
recycle_frame(usb, pkt);
@ -213,7 +213,7 @@ static int add_packet(struct fhci_usb *usb, struct ed *ed, struct td *td)
}
/* update frame object fields before transmitting */
pkt = cq_get(usb->ep0->empty_frame_Q);
pkt = cq_get(&usb->ep0->empty_frame_Q);
if (!pkt) {
fhci_dbg(usb->fhci, "there is no empty frame\n");
return -1;
@ -222,7 +222,7 @@ static int add_packet(struct fhci_usb *usb, struct ed *ed, struct td *td)
pkt->info = 0;
if (data == NULL) {
data = cq_get(usb->ep0->dummy_packets_Q);
data = cq_get(&usb->ep0->dummy_packets_Q);
BUG_ON(!data);
pkt->info = PKT_DUMMY_PACKET;
}
@ -246,7 +246,7 @@ static int add_packet(struct fhci_usb *usb, struct ed *ed, struct td *td)
list_del_init(&td->frame_lh);
td->status = USB_TD_OK;
if (pkt->info & PKT_DUMMY_PACKET)
cq_put(usb->ep0->dummy_packets_Q, pkt->data);
cq_put(&usb->ep0->dummy_packets_Q, pkt->data);
recycle_frame(usb, pkt);
usb->actual_frame->total_bytes -= (len + PROTOCOL_OVERHEAD);
fhci_err(usb->fhci, "host transaction failed\n");

View file

@ -106,33 +106,33 @@ void fhci_ep0_free(struct fhci_usb *usb)
cpm_muram_free(cpm_muram_offset(ep->td_base));
if (ep->conf_frame_Q) {
size = cq_howmany(ep->conf_frame_Q);
size = cq_howmany(&ep->conf_frame_Q);
for (; size; size--) {
struct packet *pkt = cq_get(ep->conf_frame_Q);
struct packet *pkt = cq_get(&ep->conf_frame_Q);
kfree(pkt);
}
cq_delete(ep->conf_frame_Q);
cq_delete(&ep->conf_frame_Q);
}
if (ep->empty_frame_Q) {
size = cq_howmany(ep->empty_frame_Q);
size = cq_howmany(&ep->empty_frame_Q);
for (; size; size--) {
struct packet *pkt = cq_get(ep->empty_frame_Q);
struct packet *pkt = cq_get(&ep->empty_frame_Q);
kfree(pkt);
}
cq_delete(ep->empty_frame_Q);
cq_delete(&ep->empty_frame_Q);
}
if (ep->dummy_packets_Q) {
size = cq_howmany(ep->dummy_packets_Q);
size = cq_howmany(&ep->dummy_packets_Q);
for (; size; size--) {
u8 *buff = cq_get(ep->dummy_packets_Q);
u8 *buff = cq_get(&ep->dummy_packets_Q);
kfree(buff);
}
cq_delete(ep->dummy_packets_Q);
cq_delete(&ep->dummy_packets_Q);
}
kfree(ep);
@ -175,10 +175,9 @@ u32 fhci_create_ep(struct fhci_usb *usb, enum fhci_mem_alloc data_mem,
ep->td_base = cpm_muram_addr(ep_offset);
/* zero all queue pointers */
ep->conf_frame_Q = cq_new(ring_len + 2);
ep->empty_frame_Q = cq_new(ring_len + 2);
ep->dummy_packets_Q = cq_new(ring_len + 2);
if (!ep->conf_frame_Q || !ep->empty_frame_Q || !ep->dummy_packets_Q) {
if (cq_new(&ep->conf_frame_Q, ring_len + 2) ||
cq_new(&ep->empty_frame_Q, ring_len + 2) ||
cq_new(&ep->dummy_packets_Q, ring_len + 2)) {
err_for = "frame_queues";
goto err;
}
@ -199,8 +198,8 @@ u32 fhci_create_ep(struct fhci_usb *usb, enum fhci_mem_alloc data_mem,
err_for = "buffer";
goto err;
}
cq_put(ep->empty_frame_Q, pkt);
cq_put(ep->dummy_packets_Q, buff);
cq_put(&ep->empty_frame_Q, pkt);
cq_put(&ep->dummy_packets_Q, buff);
}
/* we put the endpoint parameter RAM right behind the TD ring */
@ -319,7 +318,7 @@ static void fhci_td_transaction_confirm(struct fhci_usb *usb)
if ((buf == DUMMY2_BD_BUFFER) && !(td_status & ~TD_W))
continue;
pkt = cq_get(ep->conf_frame_Q);
pkt = cq_get(&ep->conf_frame_Q);
if (!pkt)
fhci_err(usb->fhci, "no frame to confirm\n");
@ -460,9 +459,9 @@ u32 fhci_host_transaction(struct fhci_usb *usb,
out_be16(&td->length, pkt->len);
/* put the frame to the confirmation queue */
cq_put(ep->conf_frame_Q, pkt);
cq_put(&ep->conf_frame_Q, pkt);
if (cq_howmany(ep->conf_frame_Q) == 1)
if (cq_howmany(&ep->conf_frame_Q) == 1)
out_8(&usb->fhci->regs->usb_comm, USB_CMD_STR_FIFO);
return 0;

View file

@ -423,9 +423,9 @@ struct endpoint {
struct usb_td __iomem *td_base; /* first TD in the ring */
struct usb_td __iomem *conf_td; /* next TD for confirm after transac */
struct usb_td __iomem *empty_td;/* next TD for new transaction req. */
struct kfifo *empty_frame_Q; /* Empty frames list to use */
struct kfifo *conf_frame_Q; /* frames passed to TDs,waiting for tx */
struct kfifo *dummy_packets_Q;/* dummy packets for the CRC overun */
struct kfifo empty_frame_Q; /* Empty frames list to use */
struct kfifo conf_frame_Q; /* frames passed to TDs,waiting for tx */
struct kfifo dummy_packets_Q;/* dummy packets for the CRC overun */
bool already_pushed_dummy_bd;
};
@ -493,9 +493,9 @@ static inline struct usb_hcd *fhci_to_hcd(struct fhci_hcd *fhci)
}
/* fifo of pointers */
static inline struct kfifo *cq_new(int size)
static inline int cq_new(struct kfifo *fifo, int size)
{
return kfifo_alloc(size * sizeof(void *), GFP_KERNEL, NULL);
return kfifo_alloc(fifo, size * sizeof(void *), GFP_KERNEL, NULL);
}
static inline void cq_delete(struct kfifo *kfifo)

View file

@ -939,9 +939,8 @@ int usb_serial_probe(struct usb_interface *interface,
dev_err(&interface->dev, "No free urbs available\n");
goto probe_error;
}
port->write_fifo = kfifo_alloc(PAGE_SIZE, GFP_KERNEL,
&port->lock);
if (IS_ERR(port->write_fifo))
if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL,
&port->lock))
goto probe_error;
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
port->bulk_out_size = buffer_size;